diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e63fc6afe4..a495502a22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ This document will guide you through the process of contributing to the project. All contributions are appreciated, whether it's identifying problems, highlighting missing features, or contributing to the codebase in simple or complex ways. -You are encouraged to join the [Source Network Discord](discord.gg/w7jYQVJ) to discuss ideas, ask questions, and find inspiration for future developments. +You are encouraged to join the [Source Network Discord](https://discord.gg/w7jYQVJ) to discuss ideas, ask questions, and find inspiration for future developments. ## Getting started To get started, clone the repository, build, and run it: diff --git a/README.md b/README.md index 3f8276b5cb..368dbe4e0c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

-DefraDB is a user-centric database that prioritizes data ownership, personal privacy, and information security. Its data model, powered by the convergence of [MerkleCRDTs](https://arxiv.org/pdf/2004.00107.pdf) and the content-addressability of [IPLD](https://docs.ipld.io/), enables a multi-write-master architecture. It features [DQL](https://docs.source.network/references/query-specification/query-language-overview), a query language compatible with GraphQL but providing extra convenience. By leveraging peer-to-peer networking it can be deployed nimbly in novel topologies. Access control is determined by a relationship-based DSL, supporting document or field-level policies, secured by the SourceHub network. DefraDB is a core part of the [Source technologies](https://source.network/) that enable new paradigms of decentralized data and access-control management, user-centric apps, data trustworthiness, and much more. +DefraDB is a user-centric database that prioritizes data ownership, personal privacy, and information security. Its data model, powered by the convergence of [MerkleCRDTs](https://arxiv.org/pdf/2004.00107.pdf) and the content-addressability of [IPLD](https://docs.ipld.io/), enables a multi-write-master architecture. It features [DQL](https://docs.source.network/defradb/references/query-specification/query-language-overview), a query language compatible with GraphQL but providing extra convenience. By leveraging peer-to-peer networking it can be deployed nimbly in novel topologies. Access control is determined by a relationship-based DSL, supporting document or field-level policies, secured by the SourceHub network. DefraDB is a core part of the [Source technologies](https://source.network/) that enable new paradigms of decentralized data and access-control management, user-centric apps, data trustworthiness, and much more. Read the documentation on [docs.source.network](https://docs.source.network/). diff --git a/acp/README.md b/acp/README.md index 4e8d5b7f5b..3fedb5a274 100644 --- a/acp/README.md +++ b/acp/README.md @@ -631,6 +631,26 @@ Result: Error: document not found or not authorized to access ``` +Sometimes we might want to give a specific access (form a relationship) not just to one identity, but any identity. +In that case we can specify "*" instead of specifying an explicit `actor`: +```sh +defradb client acp relationship add \ +--collection Users \ +--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \ +--relation reader \ +--actor "*" \ +--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac +``` + +Result: +```json +{ + "ExistedAlready": false +} +``` + +**Note: specifying `*` does not overwrite any previous formed relationships, they will remain as is ** + ### Revoking Access To Private Documents To revoke access to a document for an actor, we must delete the relationship between the @@ -695,6 +715,26 @@ defradb client collection docIDs --identity 4d092126012ebaf56161716018a71630d994 **Result is empty from the above command** +We can also revoke the previously granted implicit relationship which gave all actors access using the "*" actor. +Similarly we can just specify "*" to revoke all access given to actors implicitly through this relationship: +```sh +defradb client acp relationship delete \ +--collection Users \ +--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \ +--relation reader \ +--actor "*" \ +--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac +``` + +Result: +```json +{ + "RecordFound": true +} +``` + +**Note: Deleting with`*` does not remove any explicitly formed relationships, they will remain as they were ** + ## DAC Usage HTTP: ### Authentication diff --git a/acp/acp_local.go b/acp/acp_local.go index a8a0d32290..99b2cb15f4 100644 --- a/acp/acp_local.go +++ b/acp/acp_local.go @@ -254,9 +254,25 @@ func (l *ACPLocal) AddActorRelationship( ctx = auth.InjectPrincipal(ctx, principal) + var newActorRelationship *types.Relationship + if targetActor == "*" { + newActorRelationship = types.NewAllActorsRelationship( + resourceName, + objectID, + relation, + ) + } else { + newActorRelationship = types.NewActorRelationship( + resourceName, + objectID, + relation, + targetActor, + ) + } + setRelationshipRequest := types.SetRelationshipRequest{ PolicyId: policyID, - Relationship: types.NewActorRelationship(resourceName, objectID, relation, targetActor), + Relationship: newActorRelationship, CreationTime: creationTime, } @@ -285,9 +301,25 @@ func (l *ACPLocal) DeleteActorRelationship( ctx = auth.InjectPrincipal(ctx, principal) + var newActorRelationship *types.Relationship + if targetActor == "*" { + newActorRelationship = types.NewAllActorsRelationship( + resourceName, + objectID, + relation, + ) + } else { + newActorRelationship = types.NewActorRelationship( + resourceName, + objectID, + relation, + targetActor, + ) + } + deleteRelationshipRequest := types.DeleteRelationshipRequest{ PolicyId: policyID, - Relationship: types.NewActorRelationship(resourceName, objectID, relation, targetActor), + Relationship: newActorRelationship, } deleteRelationshipResponse, err := l.engine.DeleteRelationship(ctx, &deleteRelationshipRequest) diff --git a/acp/acp_source_hub.go b/acp/acp_source_hub.go index edd6008b63..dd248c5db9 100644 --- a/acp/acp_source_hub.go +++ b/acp/acp_source_hub.go @@ -273,18 +273,28 @@ func (a *acpSourceHub) AddActorRelationship( creationTime *protoTypes.Timestamp, ) (bool, error) { msgSet := sourcehub.MsgSet{} + + var newActorRelationship *acptypes.Relationship + if targetActor == "*" { + newActorRelationship = acptypes.NewAllActorsRelationship( + resourceName, + objectID, + relation, + ) + } else { + newActorRelationship = acptypes.NewActorRelationship( + resourceName, + objectID, + relation, + targetActor, + ) + } + cmdMapper := msgSet.WithBearerPolicyCmd(&acptypes.MsgBearerPolicyCmd{ - Creator: a.signer.GetAccAddress(), - BearerToken: requester.BearerToken, - PolicyId: policyID, - Cmd: acptypes.NewSetRelationshipCmd( - acptypes.NewActorRelationship( - resourceName, - objectID, - relation, - targetActor, - ), - ), + Creator: a.signer.GetAccAddress(), + BearerToken: requester.BearerToken, + PolicyId: policyID, + Cmd: acptypes.NewSetRelationshipCmd(newActorRelationship), CreationTime: creationTime, }) tx, err := a.txBuilder.Build(ctx, a.signer, &msgSet) @@ -323,18 +333,28 @@ func (a *acpSourceHub) DeleteActorRelationship( creationTime *protoTypes.Timestamp, ) (bool, error) { msgSet := sourcehub.MsgSet{} + + var newActorRelationship *acptypes.Relationship + if targetActor == "*" { + newActorRelationship = acptypes.NewAllActorsRelationship( + resourceName, + objectID, + relation, + ) + } else { + newActorRelationship = acptypes.NewActorRelationship( + resourceName, + objectID, + relation, + targetActor, + ) + } + cmdMapper := msgSet.WithBearerPolicyCmd(&acptypes.MsgBearerPolicyCmd{ - Creator: a.signer.GetAccAddress(), - BearerToken: requester.BearerToken, - PolicyId: policyID, - Cmd: acptypes.NewDeleteRelationshipCmd( - acptypes.NewActorRelationship( - resourceName, - objectID, - relation, - targetActor, - ), - ), + Creator: a.signer.GetAccAddress(), + BearerToken: requester.BearerToken, + PolicyId: policyID, + Cmd: acptypes.NewDeleteRelationshipCmd(newActorRelationship), CreationTime: creationTime, }) diff --git a/cli/acp_relationship_add.go b/cli/acp_relationship_add.go index c0838a2ce2..0026e992f5 100644 --- a/cli/acp_relationship_add.go +++ b/cli/acp_relationship_add.go @@ -64,6 +64,14 @@ Example: Let another actor (4d092126012ebaf56161716018a71630d99443d9d5217e9d8502 --actor did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \ --identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac +Example: Let all actors read a private document: + defradb client acp relationship add \ + --collection Users \ + --docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \ + --relation reader \ + --actor "*" \ + --identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac + Example: Creating a dummy relationship does nothing (from database perspective): defradb client acp relationship add \ -c Users \ diff --git a/cli/errors.go b/cli/errors.go index f084ed21b0..ff283de5f9 100644 --- a/cli/errors.go +++ b/cli/errors.go @@ -17,9 +17,11 @@ import ( ) const ( - errInvalidLensConfig string = "invalid lens configuration" - errSchemaVersionNotOfSchema string = "the given schema version is from a different schema" - errRequiredFlag string = "the required flag [--%s|-%s] is %s" + errInvalidLensConfig string = "invalid lens configuration" + errSchemaVersionNotOfSchema string = "the given schema version is from a different schema" + errRequiredFlag string = "the required flag [--%s|-%s] is %s" + errInvalidAscensionOrder string = "invalid order: expected ASC or DESC" + errInvalidInxedFieldDescription string = "invalid or malformed field description" ) var ( @@ -55,3 +57,11 @@ func NewErrSchemaVersionNotOfSchema(schemaRoot string, schemaVersionID string) e errors.NewKV("SchemaVersionID", schemaVersionID), ) } + +func NewErrInvalidAscensionOrder(fieldName string) error { + return errors.New(errInvalidAscensionOrder, errors.NewKV("Field", fieldName)) +} + +func NewErrInvalidInxedFieldDescription(fieldName string) error { + return errors.New(errInvalidInxedFieldDescription, errors.NewKV("Field", fieldName)) +} diff --git a/cli/index_create.go b/cli/index_create.go index 0d724da15b..e9f4350fa0 100644 --- a/cli/index_create.go +++ b/cli/index_create.go @@ -11,6 +11,8 @@ package cli import ( + "strings" + "github.com/spf13/cobra" "github.com/sourcenetwork/defradb/client" @@ -22,26 +24,51 @@ func MakeIndexCreateCommand() *cobra.Command { var fieldsArg []string var uniqueArg bool var cmd = &cobra.Command{ - Use: "create -c --collection --fields [-n --name ] [--unique]", + Use: "create -c --collection --fields [-n --name ] [--unique]", Short: "Creates a secondary index on a collection's field(s)", Long: `Creates a secondary index on a collection's field(s). The --name flag is optional. If not provided, a name will be generated automatically. The --unique flag is optional. If provided, the index will be unique. +If no order is specified for the field, the default value will be "ASC" Example: create an index for 'Users' collection on 'name' field: defradb client index create --collection Users --fields name Example: create a named index for 'Users' collection on 'name' field: - defradb client index create --collection Users --fields name --name UsersByName`, + defradb client index create --collection Users --fields name --name UsersByName + +Example: create a unique index for 'Users' collection on 'name' in ascending order, and 'age' in descending order: + defradb client index create --collection Users --fields name:ASC,age:DESC --unique +`, ValidArgs: []string{"collection", "fields", "name"}, RunE: func(cmd *cobra.Command, args []string) error { store := mustGetContextStore(cmd) var fields []client.IndexedFieldDescription - for _, name := range fieldsArg { - fields = append(fields, client.IndexedFieldDescription{Name: name}) + + for _, field := range fieldsArg { + // For each field, parse it into a field name and ascension order, separated by a colon + // If there is no colon, assume the ascension order is ASC by default + const asc = "ASC" + const desc = "DESC" + parts := strings.Split(field, ":") + fieldName := parts[0] + order := asc + if len(parts) == 2 { + order = strings.ToUpper(parts[1]) + if order != asc && order != desc { + return NewErrInvalidAscensionOrder(field) + } + } else if len(parts) > 2 { + return NewErrInvalidInxedFieldDescription(field) + } + fields = append(fields, client.IndexedFieldDescription{ + Name: fieldName, + Descending: order == desc, + }) } + desc := client.IndexDescription{ Name: nameArg, Fields: fields, @@ -51,6 +78,7 @@ Example: create a named index for 'Users' collection on 'name' field: if err != nil { return err } + desc, err = col.CreateIndex(cmd.Context(), desc) if err != nil { return err diff --git a/client/db.go b/client/db.go index e8942e8501..bfafb76942 100644 --- a/client/db.go +++ b/client/db.go @@ -113,7 +113,9 @@ type DB interface { // If failure occurs, the result will return an error. Upon success the boolean value will // be true if the relationship already existed (no-op), and false if a new relationship was made. // - // Note: The request actor must either be the owner or manager of the document. + // Note: + // - The request actor must either be the owner or manager of the document. + // - If the target actor arg is "*", then the relationship applies to all actors implicitly. AddDocActorRelationship( ctx context.Context, collectionName string, @@ -128,7 +130,10 @@ type DB interface { // be true if the relationship record was found and deleted. Upon success the boolean value // will be false if the relationship record was not found (no-op). // - // Note: The request actor must either be the owner or manager of the document. + // Note: + // - The request actor must either be the owner or manager of the document. + // - If the target actor arg is "*", then the implicitly added relationship with all actors is + // removed, however this does not revoke access from actors that had explicit relationships. DeleteDocActorRelationship( ctx context.Context, collectionName string, diff --git a/client/document.go b/client/document.go index 4abadcac52..b4ae927522 100644 --- a/client/document.go +++ b/client/document.go @@ -358,11 +358,11 @@ func validateFieldSchema(val any, field FieldDefinition) (NormalValue, error) { return NewNormalNillableIntArray(v), nil case FieldKind_NILLABLE_JSON: - v, err := getJSON(val) + v, err := NewJSON(val) if err != nil { return nil, err } - return NewNormalJSON(&JSON{v}), nil + return NewNormalJSON(v), nil } return nil, NewErrUnhandledType("FieldKind", field.Kind) @@ -438,72 +438,6 @@ func getDateTime(v any) (time.Time, error) { return time.Parse(time.RFC3339, s) } -// getJSON converts the given value to a valid JSON value. -// -// If the value is of type *fastjson.Value it needs to be -// manually parsed. All other values are valid JSON. -func getJSON(v any) (any, error) { - val, ok := v.(*fastjson.Value) - if !ok { - return v, nil - } - switch val.Type() { - case fastjson.TypeArray: - arr, err := val.Array() - if err != nil { - return nil, err - } - out := make([]any, len(arr)) - for i, v := range arr { - c, err := getJSON(v) - if err != nil { - return nil, err - } - out[i] = c - } - return out, nil - - case fastjson.TypeObject: - obj, err := val.Object() - if err != nil { - return nil, err - } - out := make(map[string]any) - obj.Visit(func(key []byte, v *fastjson.Value) { - c, e := getJSON(v) - out[string(key)] = c - err = errors.Join(err, e) - }) - return out, err - - case fastjson.TypeFalse: - return false, nil - - case fastjson.TypeTrue: - return true, nil - - case fastjson.TypeNumber: - out, err := val.Int64() - if err == nil { - return out, nil - } - return val.Float64() - - case fastjson.TypeString: - out, err := val.StringBytes() - if err != nil { - return nil, err - } - return string(out), nil - - case fastjson.TypeNull: - return nil, nil - - default: - return nil, NewErrInvalidJSONPayload(v) - } -} - func getArray[T any]( v any, typeGetter func(any) (T, error), diff --git a/client/document_test.go b/client/document_test.go index b74af54b27..4f4dc9aa48 100644 --- a/client/document_test.go +++ b/client/document_test.go @@ -194,13 +194,13 @@ func TestNewFromJSON_WithValidJSONFieldValue_NoError(t *testing.T) { assert.Equal(t, doc.values[doc.fields["Age"]].IsDocument(), false) assert.Equal(t, doc.values[doc.fields["Custom"]].Value(), map[string]any{ "string": "maple", - "int": int64(260), + "int": float64(260), "float": float64(3.14), "false": false, "true": true, "null": nil, - "array": []any{"one", int64(1)}, - "object": map[string]any{"one": int64(1)}, + "array": []any{"one", float64(1)}, + "object": map[string]any{"one": float64(1)}, }) assert.Equal(t, doc.values[doc.fields["Custom"]].IsDocument(), false) } diff --git a/client/json.go b/client/json.go new file mode 100644 index 0000000000..23a23de2b1 --- /dev/null +++ b/client/json.go @@ -0,0 +1,433 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package client + +import ( + "encoding/json" + "io" + + "github.com/valyala/fastjson" + "golang.org/x/exp/constraints" +) + +// JSON represents a JSON value that can be any valid JSON type: object, array, number, string, boolean, or null. +// It provides type-safe access to the underlying value through various accessor methods. +type JSON interface { + json.Marshaler + // Array returns the value as a JSON array along with a boolean indicating if the value is an array. + // Returns nil and false if the value is not an array. + Array() ([]JSON, bool) + + // Object returns the value as a JSON object along with a boolean indicating if the value is an object. + // Returns nil and false if the value is not an object. + Object() (map[string]JSON, bool) + + // Number returns the value as a number along with a boolean indicating if the value is a number. + // Returns 0 and false if the value is not a number. + Number() (float64, bool) + + // String returns the value as a string along with a boolean indicating if the value is a string. + // Returns empty string and false if the value is not a string. + String() (string, bool) + + // Bool returns the value as a boolean along with a boolean indicating if the value is a boolean. + // Returns false and false if the value is not a boolean. + Bool() (bool, bool) + + // IsNull returns true if the value is null, false otherwise. + IsNull() bool + + // Value returns the value that JSON represents. + // The type will be one of: map[string]JSON, []JSON, float64, string, bool, or nil. + Value() any + + // Unwrap returns the underlying value with all nested JSON values unwrapped. + // For objects and arrays, this recursively unwraps all nested JSON values. + Unwrap() any + + // Marshal writes the JSON value to the writer. + // Returns an error if marshaling fails. + Marshal(w io.Writer) error +} + +type jsonVoid struct{} + +func (v jsonVoid) Object() (map[string]JSON, bool) { + return nil, false +} + +func (v jsonVoid) Array() ([]JSON, bool) { + return nil, false +} + +func (v jsonVoid) Number() (float64, bool) { + return 0, false +} + +func (v jsonVoid) String() (string, bool) { + return "", false +} + +func (v jsonVoid) Bool() (bool, bool) { + return false, false +} + +func (v jsonVoid) IsNull() bool { + return false +} + +type jsonBase[T any] struct { + jsonVoid + val T +} + +func (v jsonBase[T]) Value() any { + return v.val +} + +func (v jsonBase[T]) Unwrap() any { + return v.val +} + +func (v jsonBase[T]) Marshal(w io.Writer) error { + return json.NewEncoder(w).Encode(v.val) +} + +func (v jsonBase[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(v.val) +} + +type jsonObject struct { + jsonBase[map[string]JSON] +} + +var _ JSON = jsonObject{} + +func (obj jsonObject) Object() (map[string]JSON, bool) { + return obj.val, true +} + +func (obj jsonObject) MarshalJSON() ([]byte, error) { + return json.Marshal(obj.val) +} + +func (obj jsonObject) Unwrap() any { + result := make(map[string]any, len(obj.jsonBase.val)) + for k, v := range obj.val { + result[k] = v.Unwrap() + } + return result +} + +type jsonArray struct { + jsonBase[[]JSON] +} + +var _ JSON = jsonArray{} + +func (arr jsonArray) Array() ([]JSON, bool) { + return arr.val, true +} + +func (arr jsonArray) MarshalJSON() ([]byte, error) { + return json.Marshal(arr.val) +} + +func (arr jsonArray) Unwrap() any { + result := make([]any, len(arr.jsonBase.val)) + for i := range arr.val { + result[i] = arr.val[i].Unwrap() + } + return result +} + +type jsonNumber struct { + jsonBase[float64] +} + +var _ JSON = jsonNumber{} + +func (n jsonNumber) Number() (float64, bool) { + return n.val, true +} + +func (n jsonNumber) MarshalJSON() ([]byte, error) { + return json.Marshal(n.val) +} + +type jsonString struct { + jsonBase[string] +} + +var _ JSON = jsonString{} + +func (s jsonString) String() (string, bool) { + return s.val, true +} + +func (s jsonString) MarshalJSON() ([]byte, error) { + return json.Marshal(s.val) +} + +type jsonBool struct { + jsonBase[bool] +} + +var _ JSON = jsonBool{} + +func (b jsonBool) Bool() (bool, bool) { + return b.val, true +} + +func (b jsonBool) MarshalJSON() ([]byte, error) { + return json.Marshal(b.val) +} + +type jsonNull struct { + jsonVoid +} + +var _ JSON = jsonNull{} + +func (n jsonNull) IsNull() bool { + return true +} + +func (n jsonNull) Value() any { + return nil +} + +func (n jsonNull) Unwrap() any { + return nil +} + +func (n jsonNull) Marshal(w io.Writer) error { + return json.NewEncoder(w).Encode(nil) +} + +func (n jsonNull) MarshalJSON() ([]byte, error) { + return json.Marshal(nil) +} + +func newJSONObject(val map[string]JSON) JSON { + return jsonObject{jsonBase[map[string]JSON]{val: val}} +} + +func newJSONArray(val []JSON) JSON { + return jsonArray{jsonBase[[]JSON]{val: val}} +} + +func newJSONNumber(val float64) JSON { + return jsonNumber{jsonBase[float64]{val: val}} +} + +func newJSONString(val string) JSON { + return jsonString{jsonBase[string]{val: val}} +} + +func newJSONBool(val bool) JSON { + return jsonBool{jsonBase[bool]{val: val}} +} + +func newJSONNull() JSON { + return jsonNull{} +} + +// ParseJSONBytes parses the given JSON bytes into a JSON value. +// Returns error if the input is not valid JSON. +func ParseJSONBytes(data []byte) (JSON, error) { + var p fastjson.Parser + v, err := p.ParseBytes(data) + if err != nil { + return nil, err + } + return NewJSONFromFastJSON(v), nil +} + +// ParseJSONString parses the given JSON string into a JSON value. +// Returns error if the input is not valid JSON. +func ParseJSONString(data string) (JSON, error) { + // we could have called ParseJSONBytes([]byte(data), but this would copy the string to a byte slice. + // fastjson.Parser.ParseBytes casts the bytes slice to a string internally, so we can avoid the extra copy. + var p fastjson.Parser + v, err := p.Parse(data) + if err != nil { + return nil, err + } + return NewJSONFromFastJSON(v), nil +} + +// NewJSON creates a JSON value from a Go value. +// The Go value must be one of: +// - nil (becomes JSON null) +// - *fastjson.Value +// - string +// - map[string]any +// - bool +// - numeric types (int8 through int64, uint8 through uint64, float32, float64) +// - slice of any above type +// - []any +// Returns error if the input cannot be converted to JSON. +func NewJSON(v any) (JSON, error) { + if v == nil { + return newJSONNull(), nil + } + switch val := v.(type) { + case *fastjson.Value: + return NewJSONFromFastJSON(val), nil + case string: + return newJSONString(val), nil + case map[string]any: + return NewJSONFromMap(val) + case bool: + return newJSONBool(val), nil + case int8: + return newJSONNumber(float64(val)), nil + case int16: + return newJSONNumber(float64(val)), nil + case int32: + return newJSONNumber(float64(val)), nil + case int64: + return newJSONNumber(float64(val)), nil + case int: + return newJSONNumber(float64(val)), nil + case uint8: + return newJSONNumber(float64(val)), nil + case uint16: + return newJSONNumber(float64(val)), nil + case uint32: + return newJSONNumber(float64(val)), nil + case uint64: + return newJSONNumber(float64(val)), nil + case uint: + return newJSONNumber(float64(val)), nil + case float32: + return newJSONNumber(float64(val)), nil + case float64: + return newJSONNumber(val), nil + + case []bool: + return newJSONBoolArray(val), nil + case []int8: + return newJSONNumberArray(val), nil + case []int16: + return newJSONNumberArray(val), nil + case []int32: + return newJSONNumberArray(val), nil + case []int64: + return newJSONNumberArray(val), nil + case []int: + return newJSONNumberArray(val), nil + case []uint8: + return newJSONNumberArray(val), nil + case []uint16: + return newJSONNumberArray(val), nil + case []uint32: + return newJSONNumberArray(val), nil + case []uint64: + return newJSONNumberArray(val), nil + case []uint: + return newJSONNumberArray(val), nil + case []float32: + return newJSONNumberArray(val), nil + case []float64: + return newJSONNumberArray(val), nil + case []string: + return newJSONStringArray(val), nil + + case []any: + return newJsonArrayFromAnyArray(val) + } + + return nil, NewErrInvalidJSONPayload(v) +} + +func newJsonArrayFromAnyArray(arr []any) (JSON, error) { + result := make([]JSON, len(arr)) + for i := range arr { + jsonVal, err := NewJSON(arr[i]) + if err != nil { + return nil, err + } + result[i] = jsonVal + } + return newJSONArray(result), nil +} + +func newJSONBoolArray(v []bool) JSON { + arr := make([]JSON, len(v)) + for i := range v { + arr[i] = newJSONBool(v[i]) + } + return newJSONArray(arr) +} + +func newJSONNumberArray[T constraints.Integer | constraints.Float](v []T) JSON { + arr := make([]JSON, len(v)) + for i := range v { + arr[i] = newJSONNumber(float64(v[i])) + } + return newJSONArray(arr) +} + +func newJSONStringArray(v []string) JSON { + arr := make([]JSON, len(v)) + for i := range v { + arr[i] = newJSONString(v[i]) + } + return newJSONArray(arr) +} + +// NewJSONFromFastJSON creates a JSON value from a fastjson.Value. +func NewJSONFromFastJSON(v *fastjson.Value) JSON { + switch v.Type() { + case fastjson.TypeObject: + fastObj := v.GetObject() + obj := make(map[string]JSON, fastObj.Len()) + fastObj.Visit(func(k []byte, v *fastjson.Value) { + obj[string(k)] = NewJSONFromFastJSON(v) + }) + return newJSONObject(obj) + case fastjson.TypeArray: + fastArr := v.GetArray() + arr := make([]JSON, len(fastArr)) + for i := range fastArr { + arr[i] = NewJSONFromFastJSON(fastArr[i]) + } + return newJSONArray(arr) + case fastjson.TypeNumber: + return newJSONNumber(v.GetFloat64()) + case fastjson.TypeString: + return newJSONString(string(v.GetStringBytes())) + case fastjson.TypeTrue: + return newJSONBool(true) + case fastjson.TypeFalse: + return newJSONBool(false) + case fastjson.TypeNull: + return newJSONNull() + } + return nil +} + +// NewJSONFromMap creates a JSON object from a map[string]any. +// The map values must be valid Go values that can be converted to JSON. +// Returns error if any map value cannot be converted to JSON. +func NewJSONFromMap(data map[string]any) (JSON, error) { + obj := make(map[string]JSON, len(data)) + for k, v := range data { + jsonVal, err := NewJSON(v) + if err != nil { + return nil, err + } + obj[k] = jsonVal + } + return newJSONObject(obj), nil +} diff --git a/client/json_test.go b/client/json_test.go new file mode 100644 index 0000000000..9ac4d3b781 --- /dev/null +++ b/client/json_test.go @@ -0,0 +1,519 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package client + +import ( + "bytes" + "encoding/json" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/valyala/fastjson" +) + +func TestParseJSONAndMarshal_WithValidInput_ShouldMarshal(t *testing.T) { + tests := []struct { + name string + fromFunc func(string) (JSON, error) + }{ + { + name: "FromBytes", + fromFunc: func(data string) (JSON, error) { return ParseJSONBytes([]byte(data)) }, + }, + { + name: "FromString", + fromFunc: ParseJSONString, + }, + { + name: "FromFastJSON", + fromFunc: func(data string) (JSON, error) { + var p fastjson.Parser + v, err := p.Parse(data) + if err != nil { + return nil, err + } + return NewJSONFromFastJSON(v), nil + }, + }, + { + name: "FromMap", + fromFunc: func(data string) (JSON, error) { + var result map[string]any + if err := json.Unmarshal([]byte(data), &result); err != nil { + return nil, err + } + return NewJSONFromMap(result) + }, + }, + } + + data := `{"key1": "value1", "key2": 2, "key3": true, "key4": null, "key5": ["item1", 2, false]}` + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + jsonObj, err := tt.fromFunc(data) + require.NoError(t, err, "fromFunc failed with error %v", err) + + var buf bytes.Buffer + err = jsonObj.Marshal(&buf) + require.NoError(t, err, "jsonObj.Marshal(&buf) failed with error %v", err) + + actualStr := strings.ReplaceAll(buf.String(), "\n", "") + expectedStr := strings.ReplaceAll(data, " ", "") + require.Equal(t, actualStr, expectedStr, "Expected %s, got %s", expectedStr, actualStr) + + rawJSON, err := jsonObj.MarshalJSON() + require.NoError(t, err, "jsonObj.MarshalJSON() failed with error %v", err) + actualStr = strings.ReplaceAll(string(rawJSON), "\n", "") + require.Equal(t, actualStr, expectedStr, "Expected %s, got %s", expectedStr, actualStr) + }) + } +} + +func TestNewJSONAndMarshal_WithInvalidInput_ShouldFail(t *testing.T) { + tests := []struct { + name string + fromFunc func(string) (JSON, error) + }{ + { + name: "FromBytes", + fromFunc: func(data string) (JSON, error) { return ParseJSONBytes([]byte(data)) }, + }, + { + name: "FromString", + fromFunc: ParseJSONString, + }, + { + name: "FromMap", + fromFunc: func(data string) (JSON, error) { + var result map[string]any + if err := json.Unmarshal([]byte(data), &result); err != nil { + return nil, err + } + return NewJSONFromMap(result) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.fromFunc(`{"key1": "value1}`) + require.Error(t, err, "Expected error, but got nil") + }) + } +} + +func TestNewJSONFomString_WithInvalidInput_Error(t *testing.T) { + _, err := ParseJSONString("str") + require.Error(t, err, "Expected error, but got nil") +} + +func TestJSONObject_Methods_ShouldWorkAsExpected(t *testing.T) { + m := map[string]JSON{ + "key": newJSONString("value"), + "nested": newJSONObject(map[string]JSON{ + "inner": newJSONNumber(42), + "array": newJSONArray([]JSON{newJSONString("test"), newJSONBool(true)}), + }), + } + obj := newJSONObject(m) + expectedUnwrapped := map[string]any{ + "key": "value", + "nested": map[string]any{ + "inner": float64(42), + "array": []any{"test", true}, + }, + } + + // Positive tests + val, ok := obj.Object() + require.True(t, ok) + require.Equal(t, m, val) + require.Equal(t, m, obj.Value()) + require.Equal(t, expectedUnwrapped, obj.Unwrap()) + + // Negative tests + _, ok = obj.Array() + require.False(t, ok) + _, ok = obj.Number() + require.False(t, ok) + _, ok = obj.String() + require.False(t, ok) + _, ok = obj.Bool() + require.False(t, ok) + require.False(t, obj.IsNull()) +} + +func TestJSONArray_Methods_ShouldWorkAsExpected(t *testing.T) { + arr := []JSON{ + newJSONString("item1"), + newJSONObject(map[string]JSON{ + "key": newJSONString("value"), + "num": newJSONNumber(42), + }), + newJSONNumber(2), + } + jsonArr := newJSONArray(arr) + expectedUnwrapped := []any{ + "item1", + map[string]any{ + "key": "value", + "num": float64(42), + }, + float64(2), + } + + // Positive tests + val, ok := jsonArr.Array() + require.True(t, ok) + require.Equal(t, arr, val) + require.Equal(t, arr, jsonArr.Value()) + require.Equal(t, expectedUnwrapped, jsonArr.Unwrap()) + + // Negative tests + _, ok = jsonArr.Object() + require.False(t, ok) + _, ok = jsonArr.Number() + require.False(t, ok) + _, ok = jsonArr.String() + require.False(t, ok) + _, ok = jsonArr.Bool() + require.False(t, ok) + require.False(t, jsonArr.IsNull()) +} + +func TestJSONNumber_Methods_ShouldWorkAsExpected(t *testing.T) { + num := newJSONNumber(2.5) + expected := 2.5 + + // Positive tests + val, ok := num.Number() + require.True(t, ok) + require.Equal(t, expected, val) + require.Equal(t, expected, num.Value()) + require.Equal(t, expected, num.Unwrap()) + + // Negative tests + _, ok = num.Object() + require.False(t, ok) + _, ok = num.Array() + require.False(t, ok) + _, ok = num.String() + require.False(t, ok) + _, ok = num.Bool() + require.False(t, ok) + require.False(t, num.IsNull()) +} + +func TestJSONString_Methods_ShouldWorkAsExpected(t *testing.T) { + str := newJSONString("value") + expected := "value" + + // Positive tests + val, ok := str.String() + require.True(t, ok) + require.Equal(t, expected, val) + require.Equal(t, expected, str.Value()) + require.Equal(t, expected, str.Unwrap()) + + // Negative tests + _, ok = str.Object() + require.False(t, ok) + _, ok = str.Array() + require.False(t, ok) + _, ok = str.Number() + require.False(t, ok) + _, ok = str.Bool() + require.False(t, ok) + require.False(t, str.IsNull()) +} + +func TestJSONBool_Methods_ShouldWorkAsExpected(t *testing.T) { + b := newJSONBool(true) + expected := true + + // Positive tests + val, ok := b.Bool() + require.True(t, ok) + require.Equal(t, expected, val) + require.Equal(t, expected, b.Value()) + require.Equal(t, expected, b.Unwrap()) + + // Negative tests + _, ok = b.Object() + require.False(t, ok) + _, ok = b.Array() + require.False(t, ok) + _, ok = b.Number() + require.False(t, ok) + _, ok = b.String() + require.False(t, ok) + require.False(t, b.IsNull()) +} + +func TestJSONNull_Methods_ShouldWorkAsExpected(t *testing.T) { + null := newJSONNull() + + // Positive tests + require.True(t, null.IsNull()) + require.Nil(t, null.Value()) + require.Nil(t, null.Unwrap()) + + // Negative tests + _, ok := null.Object() + require.False(t, ok) + _, ok = null.Array() + require.False(t, ok) + _, ok = null.Number() + require.False(t, ok) + _, ok = null.String() + require.False(t, ok) + _, ok = null.Bool() + require.False(t, ok) +} + +func TestNewJSONAndMarshalJSON(t *testing.T) { + tests := []struct { + name string + input any + expected JSON + expectedJSON string + expectError bool + }{ + { + name: "Nil", + input: nil, + expected: newJSONNull(), + expectedJSON: "null", + }, + { + name: "FastJSON", + input: fastjson.MustParse(`{"key": "value"}`), + expected: newJSONObject(map[string]JSON{"key": newJSONString("value")}), + expectedJSON: `{"key":"value"}`, + }, + { + name: "Map", + input: map[string]any{"key": "value"}, + expected: newJSONObject(map[string]JSON{"key": newJSONString("value")}), + expectedJSON: `{"key":"value"}`, + }, + { + name: "Bool", + input: true, + expected: newJSONBool(true), + expectedJSON: "true", + }, + { + name: "String", + input: "str", + expected: newJSONString("str"), + expectedJSON: `"str"`, + }, + { + name: "Int8", + input: int8(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Int16", + input: int16(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Int32", + input: int32(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Int64", + input: int64(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Int", + input: 42, + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Uint8", + input: uint8(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Uint16", + input: uint16(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Uint32", + input: uint32(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Uint64", + input: uint64(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Uint", + input: uint(42), + expected: newJSONNumber(42), + expectedJSON: "42", + }, + { + name: "Float32", + input: float32(2.5), + expected: newJSONNumber(2.5), + expectedJSON: "2.5", + }, + { + name: "Float64", + input: float64(2.5), + expected: newJSONNumber(2.5), + expectedJSON: "2.5", + }, + { + name: "BoolArray", + input: []bool{true, false}, + expected: newJSONArray([]JSON{newJSONBool(true), newJSONBool(false)}), + expectedJSON: "[true,false]", + }, + { + name: "StringArray", + input: []string{"a", "b", "c"}, + expected: newJSONArray([]JSON{newJSONString("a"), newJSONString("b"), newJSONString("c")}), + expectedJSON: `["a","b","c"]`, + }, + { + name: "AnyArray", + input: []any{"a", 1, true}, + expected: newJSONArray([]JSON{newJSONString("a"), newJSONNumber(1), newJSONBool(true)}), + expectedJSON: `["a",1,true]`, + }, + { + name: "Int8Array", + input: []int8{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Int16Array", + input: []int16{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Int32Array", + input: []int32{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Int64Array", + input: []int64{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "IntArray", + input: []int{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Uint8Array", + input: []uint8{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Uint16Array", + input: []uint16{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Uint32Array", + input: []uint32{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Uint64Array", + input: []uint64{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "UintArray", + input: []uint{1, 2, 3}, + expected: newJSONArray([]JSON{newJSONNumber(1), newJSONNumber(2), newJSONNumber(3)}), + expectedJSON: "[1,2,3]", + }, + { + name: "Float32Array", + input: []float32{1.0, 2.25, 3.5}, + expected: newJSONArray([]JSON{newJSONNumber(1.0), newJSONNumber(2.25), newJSONNumber(3.5)}), + expectedJSON: "[1,2.25,3.5]", + }, + { + name: "Float64Array", + input: []float64{1.0, 2.25, 3.5}, + expected: newJSONArray([]JSON{newJSONNumber(1.0), newJSONNumber(2.25), newJSONNumber(3.5)}), + expectedJSON: "[1,2.25,3.5]", + }, + { + name: "AnyArrayWithInvalidElement", + input: []any{"valid", make(chan int)}, // channels can't be converted to JSON + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := NewJSON(tt.input) + if tt.expectError { + require.Error(t, err, "Expected error, but got nil") + return + } + require.NoError(t, err, "NewJSON failed with error %v", err) + require.Equal(t, result, tt.expected) + + if !tt.expectError { + jsonBytes, err := result.MarshalJSON() + require.NoError(t, err, "MarshalJSON failed with error %v", err) + require.Equal(t, tt.expectedJSON, string(jsonBytes)) + } + }) + } +} + +func TestNewJSONFromMap_WithInvalidValue_ShouldFail(t *testing.T) { + // Map with an invalid value (channel cannot be converted to JSON) + input := map[string]any{ + "valid": "value", + "invalid": make(chan int), + } + + _, err := NewJSONFromMap(input) + require.Error(t, err) +} diff --git a/client/normal_new.go b/client/normal_new.go index bcd0f00929..8eb1b9f24c 100644 --- a/client/normal_new.go +++ b/client/normal_new.go @@ -64,7 +64,7 @@ func NewNormalValue(val any) (NormalValue, error) { return NewNormalTime(v), nil case *Document: return NewNormalDocument(v), nil - case *JSON: + case JSON: return NewNormalJSON(v), nil case immutable.Option[bool]: diff --git a/client/normal_scalar.go b/client/normal_scalar.go index ae92fbe3a6..cc6d9054db 100644 --- a/client/normal_scalar.go +++ b/client/normal_scalar.go @@ -17,13 +17,6 @@ import ( "golang.org/x/exp/constraints" ) -// JSON contains a valid JSON value. -// -// The inner type can be any valid normal value or normal value array. -type JSON struct { - inner any -} - // NormalValue is dummy implementation of NormalValue to be embedded in other types. type baseNormalValue[T any] struct { NormalVoid @@ -126,15 +119,15 @@ func (v normalDocument) Document() (*Document, bool) { } type normalJSON struct { - baseNormalValue[*JSON] + baseNormalValue[JSON] } -func (v normalJSON) JSON() (*JSON, bool) { +func (v normalJSON) JSON() (JSON, bool) { return v.val, true } func (v normalJSON) Unwrap() any { - return v.val.inner + return v.val.Unwrap() } func newNormalInt(val int64) NormalValue { @@ -181,8 +174,8 @@ func NewNormalDocument(val *Document) NormalValue { } // NewNormalJSON creates a new NormalValue that represents a `JSON` value. -func NewNormalJSON(val *JSON) NormalValue { - return normalJSON{baseNormalValue[*JSON]{val: val}} +func NewNormalJSON(val JSON) NormalValue { + return normalJSON{baseNormalValue[JSON]{val: val}} } func areNormalScalarsEqual[T comparable](val T, f func() (T, bool)) bool { diff --git a/client/normal_value.go b/client/normal_value.go index 081814ffe2..3dc66a83fd 100644 --- a/client/normal_value.go +++ b/client/normal_value.go @@ -64,7 +64,7 @@ type NormalValue interface { Document() (*Document, bool) // JSON returns the value as JSON. The second return flag is true if the value is JSON. // Otherwise it will return nil and false. - JSON() (*JSON, bool) + JSON() (JSON, bool) // NillableBool returns the value as a nillable bool. // The second return flag is true if the value is [immutable.Option[bool]]. diff --git a/client/normal_value_test.go b/client/normal_value_test.go index bcea59e046..773727c72a 100644 --- a/client/normal_value_test.go +++ b/client/normal_value_test.go @@ -78,8 +78,8 @@ const ( // Otherwise, it returns the input itself. func extractValue(input any) any { // unwrap JSON inner values - if v, ok := input.(*JSON); ok { - return v.inner + if v, ok := input.(JSON); ok { + return v.Unwrap() } inputVal := reflect.ValueOf(input) @@ -171,7 +171,7 @@ func TestNormalValue_NewValueAndTypeAssertion(t *testing.T) { BytesType: func(v any) NormalValue { return NewNormalBytes(v.([]byte)) }, TimeType: func(v any) NormalValue { return NewNormalTime(v.(time.Time)) }, DocumentType: func(v any) NormalValue { return NewNormalDocument(v.(*Document)) }, - JSONType: func(v any) NormalValue { return NewNormalJSON(v.(*JSON)) }, + JSONType: func(v any) NormalValue { return NewNormalJSON(v.(JSON)) }, NillableBoolType: func(v any) NormalValue { return NewNormalNillableBool(v.(immutable.Option[bool])) }, NillableIntType: func(v any) NormalValue { return NewNormalNillableInt(v.(immutable.Option[int64])) }, @@ -293,7 +293,7 @@ func TestNormalValue_NewValueAndTypeAssertion(t *testing.T) { }, { nType: JSONType, - input: &JSON{nil}, + input: newJSONNumber(2), }, { nType: NillableBoolType, @@ -842,53 +842,6 @@ func TestNormalValue_NewNormalValueFromAnyArray(t *testing.T) { } } -func TestNormalValue_NewNormalJSON(t *testing.T) { - var expect *JSON - var actual *JSON - - expect = &JSON{nil} - normal := NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{"hello"} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{true} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{int64(10)} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{float64(3.14)} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{map[string]any{"one": 1}} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) - - expect = &JSON{[]any{1, "two"}} - normal = NewNormalJSON(expect) - - actual, _ = normal.JSON() - assert.Equal(t, expect, actual) -} - func TestNormalValue_NewNormalInt(t *testing.T) { i64 := int64(2) v := NewNormalInt(i64) diff --git a/client/normal_void.go b/client/normal_void.go index 3238a25ad2..a9078e5328 100644 --- a/client/normal_void.go +++ b/client/normal_void.go @@ -65,7 +65,7 @@ func (NormalVoid) Document() (*Document, bool) { return nil, false } -func (NormalVoid) JSON() (*JSON, bool) { +func (NormalVoid) JSON() (JSON, bool) { return nil, false } diff --git a/crypto/aes_test.go b/crypto/aes_test.go index 7218ca24b2..7d3375c236 100644 --- a/crypto/aes_test.go +++ b/crypto/aes_test.go @@ -149,9 +149,10 @@ func TestDecryptAES(t *testing.T) { errorContains: "message authentication failed", }, { - name: "Tampered ciphertext", - nonce: validNonce, - cipherText: append([]byte{0}, validCiphertext[AESNonceSize+1:]...), + name: "Tampered ciphertext", + nonce: validNonce, + // Flip a byte in the ciphertext to corrupt it. + cipherText: append([]byte{^validCiphertext[AESNonceSize]}, validCiphertext[AESNonceSize+1:]...), key: validKey, additionalData: validAAD, expectError: true, diff --git a/docs/data_format_changes/i3265-unified-json-types.md b/docs/data_format_changes/i3265-unified-json-types.md new file mode 100644 index 0000000000..979f75d869 --- /dev/null +++ b/docs/data_format_changes/i3265-unified-json-types.md @@ -0,0 +1,4 @@ +# Unified JSON Types + +Applied a common interface to all JSON types which made it use float64 for all numbers. +This in turned caused encoded data to change because CBOR encoding of float64 is different from int64. diff --git a/docs/website/references/cli/defradb_client_acp_relationship_add.md b/docs/website/references/cli/defradb_client_acp_relationship_add.md index 1251ffb74e..f3313b45d4 100644 --- a/docs/website/references/cli/defradb_client_acp_relationship_add.md +++ b/docs/website/references/cli/defradb_client_acp_relationship_add.md @@ -30,6 +30,14 @@ Example: Let another actor (4d092126012ebaf56161716018a71630d99443d9d5217e9d8502 --actor did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \ --identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac +Example: Let all actors read a private document: + defradb client acp relationship add \ + --collection Users \ + --docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \ + --relation reader \ + --actor "*" \ + --identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac + Example: Creating a dummy relationship does nothing (from database perspective): defradb client acp relationship add \ -c Users \ diff --git a/docs/website/references/cli/defradb_client_index_create.md b/docs/website/references/cli/defradb_client_index_create.md index f37231771d..268cd9eb70 100644 --- a/docs/website/references/cli/defradb_client_index_create.md +++ b/docs/website/references/cli/defradb_client_index_create.md @@ -8,15 +8,20 @@ Creates a secondary index on a collection's field(s). The --name flag is optional. If not provided, a name will be generated automatically. The --unique flag is optional. If provided, the index will be unique. +If no order is specified for the field, the default value will be "ASC" Example: create an index for 'Users' collection on 'name' field: defradb client index create --collection Users --fields name Example: create a named index for 'Users' collection on 'name' field: defradb client index create --collection Users --fields name --name UsersByName + +Example: create a unique index for 'Users' collection on 'name' in ascending order, and 'age' in descending order: + defradb client index create --collection Users --fields name:ASC,age:DESC --unique + ``` -defradb client index create -c --collection --fields [-n --name ] [--unique] [flags] +defradb client index create -c --collection --fields [-n --name ] [--unique] [flags] ``` ### Options diff --git a/docs/website/references/http/openapi.json b/docs/website/references/http/openapi.json index 03c6a6513d..1f28b84a92 100644 --- a/docs/website/references/http/openapi.json +++ b/docs/website/references/http/openapi.json @@ -2363,7 +2363,7 @@ "servers": [ { "description": "Local DefraDB instance", - "url": "http://localhost:9181/api/v0" + "url": "/api/v0" } ], "tags": [ diff --git a/go.mod b/go.mod index bd49118689..e8d263bb76 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.0 toolchain go1.22.7 require ( - github.com/bits-and-blooms/bitset v1.14.3 + github.com/bits-and-blooms/bitset v1.17.0 github.com/bxcodec/faker v2.0.1+incompatible github.com/cosmos/cosmos-sdk v0.50.10 github.com/cosmos/gogoproto v1.7.0 @@ -19,7 +19,7 @@ require ( github.com/go-errors/errors v1.5.1 github.com/gofrs/uuid/v5 v5.3.0 github.com/iancoleman/strcase v0.3.0 - github.com/ipfs/boxo v0.24.2 + github.com/ipfs/boxo v0.24.3 github.com/ipfs/go-block-format v0.2.0 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-datastore v0.6.0 @@ -31,10 +31,10 @@ require ( github.com/jbenet/goprocess v0.1.4 github.com/joho/godotenv v1.5.1 github.com/lens-vm/lens/host-go v0.0.0-20231127204031-8d858ed2926c - github.com/lestrrat-go/jwx/v2 v2.1.2 + github.com/lestrrat-go/jwx/v2 v2.1.3 github.com/libp2p/go-libp2p v0.37.0 github.com/libp2p/go-libp2p-gostream v0.6.0 - github.com/libp2p/go-libp2p-kad-dht v0.27.0 + github.com/libp2p/go-libp2p-kad-dht v0.28.1 github.com/libp2p/go-libp2p-pubsub v0.12.0 github.com/libp2p/go-libp2p-record v0.2.0 github.com/mr-tron/base58 v1.2.0 @@ -54,15 +54,15 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/tidwall/btree v1.7.0 github.com/valyala/fastjson v1.6.4 github.com/vito/go-sse v1.1.2 github.com/zalando/go-keyring v0.2.6 - go.opentelemetry.io/otel/metric v1.31.0 - go.opentelemetry.io/otel/sdk/metric v1.31.0 + go.opentelemetry.io/otel/metric v1.32.0 + go.opentelemetry.io/otel/sdk/metric v1.32.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c google.golang.org/grpc v1.67.1 ) @@ -80,7 +80,7 @@ require ( cosmossdk.io/depinject v1.0.0 // indirect cosmossdk.io/errors v1.0.1 // indirect cosmossdk.io/log v1.4.1 // indirect - cosmossdk.io/math v1.3.0 // indirect + cosmossdk.io/math v1.4.0 // indirect cosmossdk.io/store v1.1.1 // indirect cosmossdk.io/x/circuit v0.1.0 // indirect cosmossdk.io/x/evidence v0.1.0 // indirect @@ -151,7 +151,7 @@ require ( github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-jose/go-jose/v3 v3.0.1-0.20221117193127-916db76e8214 // indirect github.com/go-kit/kit v0.12.0 // indirect @@ -190,7 +190,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -351,10 +351,10 @@ require ( go.etcd.io/bbolt v1.3.10 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect - go.opentelemetry.io/otel v1.31.0 // indirect - go.opentelemetry.io/otel/sdk v1.31.0 // indirect - go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect + go.opentelemetry.io/otel v1.32.0 // indirect + go.opentelemetry.io/otel/sdk v1.32.0 // indirect + go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/mock v0.5.0 // indirect @@ -362,17 +362,17 @@ require ( golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.26.0 // indirect gonum.org/v1/gonum v0.15.0 // indirect google.golang.org/api v0.171.0 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 76ed0cb1ce..db0e7bc21a 100644 --- a/go.sum +++ b/go.sum @@ -202,8 +202,8 @@ cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= -cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= -cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= +cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= +cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= cosmossdk.io/store v1.1.1 h1:NA3PioJtWDVU7cHHeyvdva5J/ggyLDkyH0hGHl2804Y= cosmossdk.io/store v1.1.1/go.mod h1:8DwVTz83/2PSI366FERGbWSH7hL6sB7HbYp8bqksNwM= cosmossdk.io/x/circuit v0.1.0 h1:IAej8aRYeuOMritczqTlljbUVHq1E85CpBqaCTwYgXs= @@ -262,8 +262,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 h1:ez/4by2iGztzR4L0zgAOR8lTQK9VlyBVVd7G4omaOQs= -github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -294,8 +294,8 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA= -github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI= +github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= @@ -419,8 +419,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 h1:ZFUue+PNxmHlu7pYv+IYMtqlaO/0VwaGEqKepZf9JpA= -github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= +github.com/crackcomm/go-gitignore v0.0.0-20241020182519-7843d2ba8fdf h1:dwGgBWn84wUS1pVikGiruW+x5XM4amhjaZO20vCjay4= +github.com/crackcomm/go-gitignore v0.0.0-20241020182519-7843d2ba8fdf/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= @@ -510,8 +510,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= @@ -758,8 +758,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -856,8 +856,8 @@ github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.24.2 h1:feLM6DY6CNI0uSG3TvP/Hv4PdM/fsekjqSCqKtifF0E= -github.com/ipfs/boxo v0.24.2/go.mod h1:Dt3TJjMZtF2QksMv2LC8pQlG9VQUiSV2DsHQzvDiroo= +github.com/ipfs/boxo v0.24.3 h1:gldDPOWdM3Rz0v5LkVLtZu7A7gFNvAlWcmxhCqlHR3c= +github.com/ipfs/boxo v0.24.3/go.mod h1:h0DRzOY1IBFDHp6KNvrJLMFdSXTYID0Zf+q7X05JsNg= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= @@ -983,8 +983,8 @@ github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCG github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx/v2 v2.1.2 h1:6poete4MPsO8+LAEVhpdrNI4Xp2xdiafgl2RD89moBc= -github.com/lestrrat-go/jwx/v2 v2.1.2/go.mod h1:pO+Gz9whn7MPdbsqSJzG8TlEpMZCwQDXnFJ+zsUVh8Y= +github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5/Jo= +github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -1001,8 +1001,8 @@ github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl9 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qkCnjyaZUPYU= github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA= -github.com/libp2p/go-libp2p-kad-dht v0.27.0 h1:1Ea32tVTPiAfaLpPMbaBWFJgbsi/JpMqC2YBuFdf32o= -github.com/libp2p/go-libp2p-kad-dht v0.27.0/go.mod h1:ixhjLuzaXSGtWsKsXTj7erySNuVC4UP7NO015cRrF14= +github.com/libp2p/go-libp2p-kad-dht v0.28.1 h1:DVTfzG8Ybn88g9RycIq47evWCRss5f0Wm8iWtpwyHso= +github.com/libp2p/go-libp2p-kad-dht v0.28.1/go.mod h1:0wHURlSFdAC42+wF7GEmpLoARw8JuS8do2guCtc/Y/w= github.com/libp2p/go-libp2p-kbucket v0.6.4 h1:OjfiYxU42TKQSB8t8WYd8MKhYhMJeO2If+NiuKfb6iQ= github.com/libp2p/go-libp2p-kbucket v0.6.4/go.mod h1:jp6w82sczYaBsAypt5ayACcRJi0lgsba7o4TzJKEfWA= github.com/libp2p/go-libp2p-pubsub v0.12.0 h1:PENNZjSfk8KYxANRlpipdS7+BfLmOl3L2E/6vSNjbdI= @@ -1339,8 +1339,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= -github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= @@ -1450,8 +1450,9 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= @@ -1536,18 +1537,18 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= -go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= +go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1601,8 +1602,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1760,8 +1761,8 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1870,8 +1871,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1880,8 +1881,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1896,8 +1897,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2157,10 +2158,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/http/openapi.go b/http/openapi.go index 850ce081f4..b217036182 100644 --- a/http/openapi.go +++ b/http/openapi.go @@ -111,7 +111,7 @@ func NewOpenAPISpec() (*openapi3.T, error) { Servers: openapi3.Servers{ &openapi3.Server{ Description: "Local DefraDB instance", - URL: "http://localhost:9181/api/v0", + URL: "/api/v0", }, }, ExternalDocs: &openapi3.ExternalDocs{ diff --git a/internal/core/data.go b/internal/core/data.go deleted file mode 100644 index d84186826c..0000000000 --- a/internal/core/data.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2022 Democratized Data Foundation -// -// Use of this software is governed by the Business Source License -// included in the file licenses/BSL.txt. -// -// As of the Change Date specified in that file, in accordance with -// the Business Source License, use of this software will be governed -// by the Apache License, Version 2.0, included in the file -// licenses/APL.txt. - -package core - -import ( - "strings" - - "github.com/sourcenetwork/defradb/internal/keys" -) - -// Span is a range of keys from [Start, End). -type Span struct { - // Start represents the starting key of the Span. - Start keys.Walkable - - // End represents the ending key of the Span. - End keys.Walkable -} - -// NewSpan creates a new Span from the provided start and end keys. -func NewSpan(start, end keys.Walkable) Span { - return Span{ - Start: start, - End: end, - } -} - -// SpanComparisonResult is the result of comparing two spans. -type SpanComparisonResult uint - -const ( - Before SpanComparisonResult = iota - StartBeforeEndEqualToStart - StartBeforeEndWithin - StartBeforeEndEqual - StartBeforeEndAfter - StartEqualEndWithin - Equal - StartEqualEndAfter - StartWithinEndWithin - StartWithinEndAfter - StartWithinEndEqual - StartEqualToEndEndAfter - After -) - -// Compares two spans returning how the compare to each other. -// If the end of one span is adjacent to the other (with no gap possible) -// then those ends are considered equal. -func (this Span) Compare(other Span) SpanComparisonResult { - if this == other { - return Equal - } - - thisStart := this.Start.ToString() - thisEnd := this.End.ToString() - otherStart := other.Start.ToString() - otherEnd := other.End.ToString() - - if thisStart < otherStart { - if thisEnd == otherStart || isAdjacent(this.End, other.Start) { - return StartBeforeEndEqualToStart - } - - if thisEnd < otherStart { - return Before - } - - if thisEnd < otherEnd || strings.HasPrefix(thisEnd, otherEnd) { - return StartBeforeEndWithin - } - - if thisEnd == otherEnd { - return StartBeforeEndEqual - } - - if thisEnd > otherEnd { - return StartBeforeEndAfter - } - } - - if thisStart == otherStart { - if thisEnd < otherEnd || strings.HasPrefix(thisEnd, otherEnd) { - return StartEqualEndWithin - } - - if thisEnd == otherEnd { - return Equal - } - - if thisEnd > otherEnd { - return StartEqualEndAfter - } - } - - if thisStart < otherEnd { - if thisEnd < otherEnd || strings.HasPrefix(thisEnd, otherEnd) { - return StartWithinEndWithin - } - - if thisEnd == otherEnd { - return StartWithinEndEqual - } - - if thisEnd > otherEnd { - return StartWithinEndAfter - } - } - - if thisStart == otherEnd || isAdjacent(this.Start, other.End) { - return StartEqualToEndEndAfter - } - - return After -} - -func isAdjacent(this keys.Walkable, other keys.Walkable) bool { - return len(this.ToString()) == len(other.ToString()) && - (this.PrefixEnd().ToString() == other.ToString() || - this.ToString() == other.PrefixEnd().ToString()) -} - -// Merges an unordered, potentially overlapping and/or duplicated collection of Spans into -// a unique set in ascending order, where overlapping spans are merged into a single span. -// Will handle spans with keys of different lengths, where one might be a prefix of another. -// Adjacent spans will also be merged. -func MergeAscending(spans []Span) []Span { - if len(spans) <= 1 { - return spans - } - - uniqueSpans := []Span{} - - for _, span := range spans { - uniqueSpanFound := false - - i := 0 - for i < len(uniqueSpans) { - uniqueSpan := uniqueSpans[i] - switch span.Compare(uniqueSpan) { - case Before: - // Shift all remaining unique spans one place to the right - newArray := make([]Span, len(uniqueSpans)+1) - for j := len(uniqueSpans); j > i; j-- { - newArray[j] = uniqueSpans[i] - } - - // Then we insert - newArray[i] = NewSpan(span.Start, span.End) - - // Move the values prior to the new one across - for j := 0; j < i; j++ { - newArray[j] = uniqueSpans[j] - } - uniqueSpans = newArray - uniqueSpanFound = true - // Exit the unique-span loop, this span has been handled - i = len(uniqueSpans) - case StartBeforeEndEqualToStart, StartBeforeEndWithin, StartBeforeEndEqual: - uniqueSpans[i] = NewSpan(span.Start, uniqueSpan.End) - uniqueSpanFound = true - i++ - case StartBeforeEndAfter: - uniqueSpans = removeBefore(uniqueSpans, i, span.End.ToString()) - uniqueSpans[i] = NewSpan(span.Start, span.End) - uniqueSpanFound = true - // Exit the unique-span loop, this span has been handled - i = len(uniqueSpans) - case StartEqualEndWithin, Equal, StartWithinEndWithin, StartWithinEndEqual: - uniqueSpanFound = true - // Do nothing, span is contained within an existing unique-span - i = len(uniqueSpans) - case StartEqualEndAfter, StartWithinEndAfter, StartEqualToEndEndAfter: - uniqueSpans = removeBefore(uniqueSpans, i, span.End.ToString()) - uniqueSpans[i] = NewSpan(uniqueSpan.Start, span.End) - uniqueSpanFound = true - // Exit the unique-span loop, this span has been handled - i = len(uniqueSpans) - case After: - i++ - } - } - - if !uniqueSpanFound { - uniqueSpans = append(uniqueSpans, span) - } - } - - return uniqueSpans -} - -// Removes any items from the collection (given index onwards) who's end key is smaller -// than the given value. The returned collection will be a different instance. -func removeBefore(spans []Span, startIndex int, end string) []Span { - indexOfLastMatchingItem := -1 - for i := startIndex; i < len(spans); i++ { - if spans[i].End.ToString() <= end { - indexOfLastMatchingItem = i - } - } - - if indexOfLastMatchingItem == -1 { - return spans - } - - numberOfItemsToRemove := indexOfLastMatchingItem - startIndex - result := make([]Span, len(spans)-numberOfItemsToRemove) - // Add the items preceding the removed items - for i := 0; i < startIndex; i++ { - result[i] = spans[i] - } - - j := startIndex + numberOfItemsToRemove - // Add the items following the removed items - for i := indexOfLastMatchingItem + 1; i < len(spans); i++ { - result[j] = spans[i] - } - - return result -} diff --git a/internal/core/data_test.go b/internal/core/data_test.go deleted file mode 100644 index 154441819e..0000000000 --- a/internal/core/data_test.go +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright 2022 Democratized Data Foundation -// -// Use of this software is governed by the Business Source License -// included in the file licenses/BSL.txt. -// -// As of the Change Date specified in that file, in accordance with -// the Business Source License, use of this software will be governed -// by the Apache License, Version 2.0, included in the file -// licenses/APL.txt. - -package core - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/sourcenetwork/defradb/internal/keys" -) - -func TestMergeAscending_ReturnsEmpty_GivenEmpty(t *testing.T) { - input := []Span{} - - result := MergeAscending(input) - - assert.Empty(t, result) -} - -func TestMergeAscending_ReturnsSingle_GivenSingle(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{NewSpan(start1, end1)} - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSecondBeforeFirst_GivenKeysInReverseOrder(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k4") - end1 := keys.MustNewDataStoreKey("/1/p/0/k5") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2") - - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 2) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end2, result[0].End) - assert.Equal(t, start1, result[1].Start) - assert.Equal(t, end1, result[1].End) -} - -func TestMergeAscending_ReturnsItemsInOrder_GivenKeysInMixedOrder(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k7") - end2 := keys.MustNewDataStoreKey("/1/p/0/k8") - start3 := keys.MustNewDataStoreKey("/1/p/0/k4") - end3 := keys.MustNewDataStoreKey("/1/p/0/k5") - - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - // Span 3 should be returned between one and two - assert.Equal(t, start3, result[1].Start) - assert.Equal(t, end3, result[1].End) - assert.Equal(t, start2, result[2].Start) - assert.Equal(t, end2, result[2].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndEqualToStart(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k3") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndAdjacentToStart(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndWithin(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k3.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartPrefixesEndWithin(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1.1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndWithinEndPrefix(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k4.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartPrefixesEndWithinEndPrefix(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1.1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k3.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndEqual(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k4") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndAdjacentAndBefore(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k5") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k4") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartBeforeEndAdjacentAndGreater(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k4") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartPrefixesEndEqual(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1.1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k3") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartPrefixesEndAdjacentAndBefore(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1.1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartPrefixesEndAdjacentAndAfter(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1.1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k4") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start2, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenSpanCoveringMiddleSpans(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k6") - end2 := keys.MustNewDataStoreKey("/1/p/0/k7") - start3 := keys.MustNewDataStoreKey("/1/p/0/k9") - end3 := keys.MustNewDataStoreKey("/1/p/0/ka") - start4 := keys.MustNewDataStoreKey("/1/p/0/kc") - end4 := keys.MustNewDataStoreKey("/1/p/0/kd") - start5 := keys.MustNewDataStoreKey("/1/p/0/k4") - end5 := keys.MustNewDataStoreKey("/1/p/0/ka") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - // Spans 2 and 3 are within span 5 - assert.Equal(t, start5, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartEqualEndWithin(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k1.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartEqualEndWithinEndPrefix(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenDuplicates(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start1, end1), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartWithinEndWithin(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1.2") - end2 := keys.MustNewDataStoreKey("/1/p/0/k1.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartWithinEndWithinEndPrefix(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1.2") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2.5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartWithinEndEqual(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1.2") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartWithinEndAdjacentAndBefore(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1.2") - end2 := keys.MustNewDataStoreKey("/1/p/0/k2") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartWithinEndAdjacentAndAfter(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k3") - start2 := keys.MustNewDataStoreKey("/1/p/0/k1.2") - end2 := keys.MustNewDataStoreKey("/1/p/0/k4") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenStartEqualEndAfterSpanCoveringMiddleSpans( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - start3 := keys.MustNewDataStoreKey("/1/p/0/k7") - end3 := keys.MustNewDataStoreKey("/1/p/0/k8") - start4 := keys.MustNewDataStoreKey("/1/p/0/kc") - end4 := keys.MustNewDataStoreKey("/1/p/0/kd") - start5 := keys.MustNewDataStoreKey("/1/p/0/k4") // equal to start2 - end5 := keys.MustNewDataStoreKey("/1/p/0/ka") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - // Spans 2 and 3 are within span 5 - assert.Equal(t, start5, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenStartWithinEndAfterSpanCoveringMiddleSpans( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - start3 := keys.MustNewDataStoreKey("/1/p/0/k7") - end3 := keys.MustNewDataStoreKey("/1/p/0/k8") - start4 := keys.MustNewDataStoreKey("/1/p/0/kc") - end4 := keys.MustNewDataStoreKey("/1/p/0/kd") - start5 := keys.MustNewDataStoreKey("/1/p/0/k4.5") // within span2 - end5 := keys.MustNewDataStoreKey("/1/p/0/ka") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - assert.Equal(t, start2, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenStartEqualToEndEndAfterSpanCoveringMiddleSpans( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - start3 := keys.MustNewDataStoreKey("/1/p/0/k7") - end3 := keys.MustNewDataStoreKey("/1/p/0/k8") - start4 := keys.MustNewDataStoreKey("/1/p/0/kc") - end4 := keys.MustNewDataStoreKey("/1/p/0/kd") - start5 := keys.MustNewDataStoreKey("/1/p/0/k5") // span2's end - end5 := keys.MustNewDataStoreKey("/1/p/0/ka") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - assert.Equal(t, start2, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenStartAdjacentAndBeforeEndEndAfterSpanCoveringMiddleSpans( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k6") - start3 := keys.MustNewDataStoreKey("/1/p/0/k8") - end3 := keys.MustNewDataStoreKey("/1/p/0/k9") - start4 := keys.MustNewDataStoreKey("/1/p/0/kd") - end4 := keys.MustNewDataStoreKey("/1/p/0/ke") - start5 := keys.MustNewDataStoreKey("/1/p/0/k5") // adjacent but before span2's end - end5 := keys.MustNewDataStoreKey("/1/p/0/kb") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - assert.Equal(t, start2, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsMiddleSpansMerged_GivenStartAdjacentAndAfterEndEndAfterSpanCoveringMiddleSpans( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - start3 := keys.MustNewDataStoreKey("/1/p/0/k8") - end3 := keys.MustNewDataStoreKey("/1/p/0/k9") - start4 := keys.MustNewDataStoreKey("/1/p/0/kd") - end4 := keys.MustNewDataStoreKey("/1/p/0/ke") - start5 := keys.MustNewDataStoreKey("/1/p/0/k6") // adjacent and after span2's end - end5 := keys.MustNewDataStoreKey("/1/p/0/kb") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - NewSpan(start3, end3), - NewSpan(start4, end4), - NewSpan(start5, end5), - } - - result := MergeAscending(input) - - assert.Len(t, result, 3) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - assert.Equal(t, start2, result[1].Start) - assert.Equal(t, end5, result[1].End) - assert.Equal(t, start4, result[2].Start) - assert.Equal(t, end4, result[2].End) -} - -func TestMergeAscending_ReturnsTwoItems_GivenSecondItemAfterFirst(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k1") - end1 := keys.MustNewDataStoreKey("/1/p/0/k2") - start2 := keys.MustNewDataStoreKey("/1/p/0/k4") - end2 := keys.MustNewDataStoreKey("/1/p/0/k5") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 2) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end1, result[0].End) - assert.Equal(t, start2, result[1].Start) - assert.Equal(t, end2, result[1].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartAdjacentAndBeforeEndEndEqual(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k6") - start2 := keys.MustNewDataStoreKey("/1/p/0/k5") - end2 := keys.MustNewDataStoreKey("/1/p/0/k6") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartAdjacentAndBeforeEndEndAdjacentAndAfter( - t *testing.T, -) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k6") - start2 := keys.MustNewDataStoreKey("/1/p/0/k5") - end2 := keys.MustNewDataStoreKey("/1/p/0/k7") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartAdjacentAndBeforeEndEndAfter(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k6") - start2 := keys.MustNewDataStoreKey("/1/p/0/k5") - end2 := keys.MustNewDataStoreKey("/1/p/0/k8") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end2, result[0].End) -} - -func TestMergeAscending_ReturnsSingle_GivenStartAdjacentAndAfterEndEndAfter(t *testing.T) { - start1 := keys.MustNewDataStoreKey("/1/p/0/k3") - end1 := keys.MustNewDataStoreKey("/1/p/0/k6") - start2 := keys.MustNewDataStoreKey("/1/p/0/k7") - end2 := keys.MustNewDataStoreKey("/1/p/0/k8") - input := []Span{ - NewSpan(start1, end1), - NewSpan(start2, end2), - } - - result := MergeAscending(input) - - assert.Len(t, result, 1) - assert.Equal(t, start1, result[0].Start) - assert.Equal(t, end2, result[0].End) -} diff --git a/internal/db/base/compare.go b/internal/db/base/compare.go index c5636f9e15..63bf27bf0b 100644 --- a/internal/db/base/compare.go +++ b/internal/db/base/compare.go @@ -34,7 +34,7 @@ func Compare(a, b any) int { case bool: return compareBool(v, b.(bool)) case int: - return compareInt(int64(v), b.(int64)) + return compareInt(int64(v), int64(b.(int))) case int64: return compareInt(v, b.(int64)) case uint64: diff --git a/internal/db/collection_get.go b/internal/db/collection_get.go index e68df05df4..8360cc0915 100644 --- a/internal/db/collection_get.go +++ b/internal/db/collection_get.go @@ -15,7 +15,6 @@ import ( "github.com/sourcenetwork/defradb/acp/identity" "github.com/sourcenetwork/defradb/client" - "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/db/fetcher" "github.com/sourcenetwork/defradb/internal/keys" @@ -73,7 +72,7 @@ func (c *collection) get( // construct target DS key from DocID. targetKey := base.MakeDataStoreKeyWithCollectionAndDocID(c.Description(), primaryKey.DocID) // run the doc fetcher - err = df.Start(ctx, core.NewSpan(targetKey, targetKey.PrefixEnd())) + err = df.Start(ctx, targetKey) if err != nil { _ = df.Close() return nil, err diff --git a/internal/db/collection_index.go b/internal/db/collection_index.go index f268e14f2e..3c5da18c58 100644 --- a/internal/db/collection_index.go +++ b/internal/db/collection_index.go @@ -24,7 +24,6 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/datastore" - "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/db/description" "github.com/sourcenetwork/defradb/internal/db/fetcher" @@ -316,10 +315,8 @@ func (c *collection) iterateAllDocs( if err != nil { return errors.Join(err, df.Close()) } - start := base.MakeDataStoreKeyWithCollectionDescription(c.Description()) - spans := core.NewSpan(start, start.PrefixEnd()) - - err = df.Start(ctx, spans) + prefix := base.MakeDataStoreKeyWithCollectionDescription(c.Description()) + err = df.Start(ctx, prefix) if err != nil { return errors.Join(err, df.Close()) } diff --git a/internal/db/fetcher/errors.go b/internal/db/fetcher/errors.go index 0a8a7d21b4..8836d3982d 100644 --- a/internal/db/fetcher/errors.go +++ b/internal/db/fetcher/errors.go @@ -45,7 +45,6 @@ var ( ErrVFetcherFailedToGetDagLink = errors.New(errVFetcherFailedToGetDagLink) ErrFailedToGetDagNode = errors.New(errFailedToGetDagNode) ErrMissingMapper = errors.New(errMissingMapper) - ErrSingleSpanOnly = errors.New("spans must contain only a single entry") ErrInvalidInOperatorValue = errors.New(errInvalidInOperatorValue) ErrInvalidFilterOperator = errors.New(errInvalidFilterOperator) ErrUnexpectedTypeValue = errors.New(errUnexpectedTypeValue) diff --git a/internal/db/fetcher/fetcher.go b/internal/db/fetcher/fetcher.go index 0ca828c4b2..422de57ad7 100644 --- a/internal/db/fetcher/fetcher.go +++ b/internal/db/fetcher/fetcher.go @@ -13,6 +13,7 @@ package fetcher import ( "bytes" "context" + "slices" "strings" "github.com/bits-and-blooms/bitset" @@ -72,7 +73,7 @@ type Fetcher interface { reverse bool, showDeleted bool, ) error - Start(ctx context.Context, spans ...core.Span) error + Start(ctx context.Context, prefixes ...keys.Walkable) error FetchNext(ctx context.Context) (EncodedDocument, ExecInfo, error) Close() error } @@ -97,10 +98,10 @@ type DocumentFetcher struct { reverse bool deletedDocs bool - txn datastore.Txn - spans []core.Span - order []dsq.Order - curSpanIndex int + txn datastore.Txn + prefixes []keys.DataStoreKey + order []dsq.Order + curPrefixIndex int filter *mapper.Filter ranFilter bool // did we run the filter @@ -243,21 +244,21 @@ func (df *DocumentFetcher) init( return nil } -func (df *DocumentFetcher) Start(ctx context.Context, spans ...core.Span) error { - err := df.start(ctx, spans, false) +func (df *DocumentFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { + err := df.start(ctx, prefixes, false) if err != nil { return err } if df.deletedDocFetcher != nil { - return df.deletedDocFetcher.start(ctx, spans, true) + return df.deletedDocFetcher.start(ctx, prefixes, true) } return nil } // Start implements DocumentFetcher. -func (df *DocumentFetcher) start(ctx context.Context, spans []core.Span, withDeleted bool) error { +func (df *DocumentFetcher) start(ctx context.Context, prefixes []keys.Walkable, withDeleted bool) error { if df.col == nil { return client.NewErrUninitializeProperty("DocumentFetcher", "CollectionDescription") } @@ -267,44 +268,46 @@ func (df *DocumentFetcher) start(ctx context.Context, spans []core.Span, withDel df.deletedDocs = withDeleted - if len(spans) == 0 { // no specified spans so create a prefix scan key for the entire collection - start := base.MakeDataStoreKeyWithCollectionDescription(df.col.Description()) + if len(prefixes) == 0 { // no specified prefixes so create a prefix scan key for the entire collection + prefix := base.MakeDataStoreKeyWithCollectionDescription(df.col.Description()) if withDeleted { - start = start.WithDeletedFlag() + prefix = prefix.WithDeletedFlag() } else { - start = start.WithValueFlag() + prefix = prefix.WithValueFlag() } - df.spans = []core.Span{core.NewSpan(start, start.PrefixEnd())} + df.prefixes = []keys.DataStoreKey{prefix} } else { - valueSpans := make([]core.Span, len(spans)) - for i, span := range spans { + valuePrefixes := make([]keys.DataStoreKey, len(prefixes)) + prefixCache := make(map[string]struct{}) + for i, prefix := range prefixes { + // if we have a duplicate prefix, skip it + if _, exists := prefixCache[prefix.ToString()]; exists { + continue + } + prefixCache[prefix.ToString()] = struct{}{} if withDeleted { // DocumentFetcher only ever recieves document keys //nolint:forcetypeassert - valueSpans[i] = core.NewSpan( - span.Start.(keys.DataStoreKey).WithDeletedFlag(), - span.End.(keys.DataStoreKey).WithDeletedFlag(), - ) + valuePrefixes[i] = prefix.(keys.DataStoreKey).WithDeletedFlag() } else { // DocumentFetcher only ever recieves document keys //nolint:forcetypeassert - valueSpans[i] = core.NewSpan( - span.Start.(keys.DataStoreKey).WithValueFlag(), - span.End.(keys.DataStoreKey).WithValueFlag(), - ) + valuePrefixes[i] = prefix.(keys.DataStoreKey).WithValueFlag() } } - spans := core.MergeAscending(valueSpans) + slices.SortFunc(valuePrefixes, func(a, b keys.DataStoreKey) int { + return strings.Compare(a.ToString(), b.ToString()) + }) + if df.reverse { - for i, j := 0, len(spans)-1; i < j; i, j = i+1, j-1 { - spans[i], spans[j] = spans[j], spans[i] + for i, j := 0, len(valuePrefixes)-1; i < j; i, j = i+1, j-1 { + valuePrefixes[i], valuePrefixes[j] = valuePrefixes[j], valuePrefixes[i] } } - df.spans = spans + df.prefixes = valuePrefixes } - - df.curSpanIndex = -1 + df.curPrefixIndex = -1 if df.reverse { df.order = []dsq.Order{dsq.OrderByKeyDescending{}} @@ -312,13 +315,13 @@ func (df *DocumentFetcher) start(ctx context.Context, spans []core.Span, withDel df.order = []dsq.Order{dsq.OrderByKey{}} } - _, err := df.startNextSpan(ctx) + _, err := df.startNextPrefix(ctx) return err } -func (df *DocumentFetcher) startNextSpan(ctx context.Context) (bool, error) { - nextSpanIndex := df.curSpanIndex + 1 - if nextSpanIndex >= len(df.spans) { +func (df *DocumentFetcher) startNextPrefix(ctx context.Context) (bool, error) { + nextPrefixIndex := df.curPrefixIndex + 1 + if nextPrefixIndex >= len(df.prefixes) { return false, nil } @@ -339,12 +342,12 @@ func (df *DocumentFetcher) startNextSpan(ctx context.Context) (bool, error) { } } - span := df.spans[nextSpanIndex] - df.kvResultsIter, err = df.kvIter.IteratePrefix(ctx, span.Start.ToDS(), span.End.ToDS()) + prefix := df.prefixes[nextPrefixIndex] + df.kvResultsIter, err = df.kvIter.IteratePrefix(ctx, prefix.ToDS(), prefix.PrefixEnd().ToDS()) if err != nil { return false, err } - df.curSpanIndex = nextSpanIndex + df.curPrefixIndex = nextPrefixIndex _, _, err = df.nextKey(ctx, false) return err == nil, err @@ -353,7 +356,7 @@ func (df *DocumentFetcher) startNextSpan(ctx context.Context) (bool, error) { // nextKey gets the next kv. It sets both kv and kvEnd internally. // It returns true if the current doc is completed. // The first call to nextKey CANNOT have seekNext be true (ErrFailedToSeek) -func (df *DocumentFetcher) nextKey(ctx context.Context, seekNext bool) (spanDone bool, docDone bool, err error) { +func (df *DocumentFetcher) nextKey(ctx context.Context, seekNext bool) (prefixDone bool, docDone bool, err error) { // safety against seekNext on first call if seekNext && df.kv == nil { return false, false, ErrFailedToSeek @@ -363,13 +366,13 @@ func (df *DocumentFetcher) nextKey(ctx context.Context, seekNext bool) (spanDone curKey := df.kv.Key curKey.FieldID = "" // clear field so prefixEnd applies to docID seekKey := curKey.PrefixEnd().ToString() - spanDone, df.kv, err = df.seekKV(seekKey) + prefixDone, df.kv, err = df.seekKV(seekKey) // handle any internal errors if err != nil { return false, false, err } } else { - spanDone, df.kv, err = df.nextKV() + prefixDone, df.kv, err = df.nextKV() // handle any internal errors if err != nil { return false, false, err @@ -379,21 +382,21 @@ func (df *DocumentFetcher) nextKey(ctx context.Context, seekNext bool) (spanDone if df.kv != nil && (df.kv.Key.InstanceType != keys.ValueKey && df.kv.Key.InstanceType != keys.DeletedKey) { // We can only ready value values, if we escape the collection's value keys // then we must be done and can stop reading - spanDone = true + prefixDone = true } - df.kvEnd = spanDone + df.kvEnd = prefixDone if df.kvEnd { err = df.kvResultsIter.Close() if err != nil { return false, false, err } - moreSpans, err := df.startNextSpan(ctx) + morePrefixes, err := df.startNextPrefix(ctx) if err != nil { return false, false, err } df.isReadingDocument = false - return !moreSpans, true, nil + return !morePrefixes, true, nil } // check if we've crossed document boundries @@ -406,7 +409,7 @@ func (df *DocumentFetcher) nextKey(ctx context.Context, seekNext bool) (spanDone // nextKV is a lower-level utility compared to nextKey. The differences are as follows: // - It directly interacts with the KVIterator. -// - Returns true if the entire iterator/span is exhausted +// - Returns true if the entire iterator/prefix is exhausted // - Returns a kv pair instead of internally updating func (df *DocumentFetcher) nextKV() (iterDone bool, kv *keyValue, err error) { done, dsKey, res, err := df.nextKVRaw() @@ -458,7 +461,7 @@ func (df *DocumentFetcher) seekKV(key string) (bool, *keyValue, error) { // nextKV is a lower-level utility compared to nextKey. The differences are as follows: // - It directly interacts with the KVIterator. -// - Returns true if the entire iterator/span is exhausted +// - Returns true if the entire iterator/prefix is exhausted // - Returns a kv pair instead of internally updating func (df *DocumentFetcher) nextKVRaw() (bool, keys.DataStoreKey, dsq.Result, error) { res, available := df.kvResultsIter.NextSync() @@ -658,7 +661,7 @@ func (df *DocumentFetcher) fetchNext(ctx context.Context) (EncodedDocument, Exec // if we don't pass the filter (ran and pass) or if we don't have access to document then // there is no point in collecting other select fields, so we seek to the next doc. - spansDone, docDone, err := df.nextKey(ctx, !df.passedPermissionCheck || !df.passedFilter && df.ranFilter) + prefixsDone, docDone, err := df.nextKey(ctx, !df.passedPermissionCheck || !df.passedFilter && df.ranFilter) if err != nil { return nil, ExecInfo{}, err @@ -693,7 +696,7 @@ func (df *DocumentFetcher) fetchNext(ctx context.Context) (EncodedDocument, Exec } } - if spansDone { + if prefixsDone { return nil, df.execInfo, nil } } diff --git a/internal/db/fetcher/indexer.go b/internal/db/fetcher/indexer.go index 3f7b82b6e0..71881a31ab 100644 --- a/internal/db/fetcher/indexer.go +++ b/internal/db/fetcher/indexer.go @@ -21,6 +21,7 @@ import ( "github.com/sourcenetwork/defradb/datastore" "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -124,9 +125,9 @@ outer: return err } -func (f *IndexFetcher) Start(ctx context.Context, spans ...core.Span) error { +func (f *IndexFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { if f.indexIter == nil { - return f.docFetcher.Start(ctx, spans...) + return f.docFetcher.Start(ctx, prefixes...) } return f.indexIter.Init(ctx, f.txn.Datastore()) } @@ -192,8 +193,7 @@ func (f *IndexFetcher) FetchNext(ctx context.Context) (EncodedDocument, ExecInfo if len(f.docFields) > 0 { targetKey := base.MakeDataStoreKeyWithCollectionAndDocID(f.col.Description(), string(f.doc.id)) - span := core.NewSpan(targetKey, targetKey.PrefixEnd()) - err := f.docFetcher.Start(ctx, span) + err := f.docFetcher.Start(ctx, targetKey) if err != nil { return nil, ExecInfo{}, err } diff --git a/internal/db/fetcher/mocks/fetcher.go b/internal/db/fetcher/mocks/fetcher.go index 396bf67345..a75d1c8ba9 100644 --- a/internal/db/fetcher/mocks/fetcher.go +++ b/internal/db/fetcher/mocks/fetcher.go @@ -18,6 +18,8 @@ import ( immutable "github.com/sourcenetwork/immutable" + keys "github.com/sourcenetwork/defradb/internal/keys" + mapper "github.com/sourcenetwork/defradb/internal/planner/mapper" mock "github.com/stretchr/testify/mock" @@ -201,11 +203,11 @@ func (_c *Fetcher_Init_Call) RunAndReturn(run func(context.Context, immutable.Op return _c } -// Start provides a mock function with given fields: ctx, spans -func (_m *Fetcher) Start(ctx context.Context, spans ...core.Span) error { - _va := make([]interface{}, len(spans)) - for _i := range spans { - _va[_i] = spans[_i] +// Start provides a mock function with given fields: ctx, prefixes +func (_m *Fetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { + _va := make([]interface{}, len(prefixes)) + for _i := range prefixes { + _va[_i] = prefixes[_i] } var _ca []interface{} _ca = append(_ca, ctx) @@ -217,8 +219,8 @@ func (_m *Fetcher) Start(ctx context.Context, spans ...core.Span) error { } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, ...core.Span) error); ok { - r0 = rf(ctx, spans...) + if rf, ok := ret.Get(0).(func(context.Context, ...keys.Walkable) error); ok { + r0 = rf(ctx, prefixes...) } else { r0 = ret.Error(0) } @@ -233,18 +235,18 @@ type Fetcher_Start_Call struct { // Start is a helper method to define mock.On call // - ctx context.Context -// - spans ...core.Span -func (_e *Fetcher_Expecter) Start(ctx interface{}, spans ...interface{}) *Fetcher_Start_Call { +// - prefixes ...keys.Walkable +func (_e *Fetcher_Expecter) Start(ctx interface{}, prefixes ...interface{}) *Fetcher_Start_Call { return &Fetcher_Start_Call{Call: _e.mock.On("Start", - append([]interface{}{ctx}, spans...)...)} + append([]interface{}{ctx}, prefixes...)...)} } -func (_c *Fetcher_Start_Call) Run(run func(ctx context.Context, spans ...core.Span)) *Fetcher_Start_Call { +func (_c *Fetcher_Start_Call) Run(run func(ctx context.Context, prefixes ...keys.Walkable)) *Fetcher_Start_Call { _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]core.Span, len(args)-1) + variadicArgs := make([]keys.Walkable, len(args)-1) for i, a := range args[1:] { if a != nil { - variadicArgs[i] = a.(core.Span) + variadicArgs[i] = a.(keys.Walkable) } } run(args[0].(context.Context), variadicArgs...) @@ -257,7 +259,7 @@ func (_c *Fetcher_Start_Call) Return(_a0 error) *Fetcher_Start_Call { return _c } -func (_c *Fetcher_Start_Call) RunAndReturn(run func(context.Context, ...core.Span) error) *Fetcher_Start_Call { +func (_c *Fetcher_Start_Call) RunAndReturn(run func(context.Context, ...keys.Walkable) error) *Fetcher_Start_Call { _c.Call.Return(run) return _c } diff --git a/internal/db/fetcher/versioned.go b/internal/db/fetcher/versioned.go index 24f3ab8467..c362a9c9b3 100644 --- a/internal/db/fetcher/versioned.go +++ b/internal/db/fetcher/versioned.go @@ -16,7 +16,7 @@ import ( "fmt" "github.com/ipfs/go-cid" - ds "github.com/ipfs/go-datastore" + cidlink "github.com/ipld/go-ipld-prime/linking/cid" "github.com/sourcenetwork/immutable" @@ -89,15 +89,11 @@ type VersionedFetcher struct { root datastore.Rootstore store datastore.Txn - dsKey keys.DataStoreKey - queuedCids *list.List acp immutable.Option[acp.ACP] col client.Collection - // @todo index *client.IndexDescription - mCRDTs map[client.FieldID]merklecrdt.MerkleCRDT } // Init initializes the VersionedFetcher. @@ -116,7 +112,6 @@ func (vf *VersionedFetcher) Init( vf.acp = acp vf.col = col vf.queuedCids = list.New() - vf.mCRDTs = make(map[client.FieldID]merklecrdt.MerkleCRDT) vf.txn = txn // create store @@ -152,54 +147,30 @@ func (vf *VersionedFetcher) Init( } // Start serializes the correct state according to the Key and CID. -func (vf *VersionedFetcher) Start(ctx context.Context, spans ...core.Span) error { - if vf.col == nil { - return client.NewErrUninitializeProperty("VersionedFetcher", "CollectionDescription") - } - - if len(spans) != 1 { - return ErrSingleSpanOnly - } - +func (vf *VersionedFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { // VersionedFetcher only ever recieves a headstore key //nolint:forcetypeassert - prefix := spans[0].Start.(keys.HeadstoreDocKey) - dk := prefix.DocID - cid := prefix.Cid - if dk == "" { - return client.NewErrUninitializeProperty("Spans", "DocID") - } else if !cid.Defined() { - return client.NewErrUninitializeProperty("Spans", "CID") - } + prefix := prefixes[0].(keys.HeadstoreDocKey) vf.ctx = ctx - vf.dsKey = keys.DataStoreKey{ - CollectionRootID: vf.col.Description().RootID, - DocID: dk, - } - if err := vf.seekTo(cid); err != nil { - return NewErrFailedToSeek(cid, err) + if err := vf.seekTo(prefix.Cid); err != nil { + return NewErrFailedToSeek(prefix.Cid, err) } return vf.DocumentFetcher.Start(ctx) } -// Rootstore returns the rootstore of the VersionedFetcher. -func (vf *VersionedFetcher) Rootstore() ds.Datastore { - return vf.root -} - -// Start a fetcher with the needed info (cid embedded in a span) +// Start a fetcher with the needed info (cid embedded in a prefix) /* 1. Init with DocID (VersionedFetched is scoped to a single doc) 2. - Create transient stores (head, data, block) -3. Start with a given Txn and CID span set (length 1 for now) +3. Start with a given Txn and CID prefix set (length 1 for now) 4. call traverse with the target cid 5. -err := VersionFetcher.Start(txn, spans) { +err := VersionFetcher.Start(txn, prefixes) { vf.traverse(cid) } */ @@ -339,56 +310,63 @@ func (vf *VersionedFetcher) merge(c cid.Cid) error { return err } - link, err := block.GenerateLink() - if err != nil { - return err - } + var mcrdt merklecrdt.MerkleCRDT + switch { + case block.Delta.IsCollection(): + mcrdt = merklecrdt.NewMerkleCollection( + vf.store, + keys.NewCollectionSchemaVersionKey(vf.col.Description().SchemaVersionID, vf.col.Description().ID), + keys.NewHeadstoreColKey(vf.col.Description().RootID), + ) - // first arg 0 is the index for the composite DAG in the mCRDTs cache - mcrdt, exists := vf.mCRDTs[0] - if !exists { + case block.Delta.IsComposite(): mcrdt = merklecrdt.NewMerkleCompositeDAG( vf.store, - keys.CollectionSchemaVersionKey{}, - vf.dsKey.WithFieldID(core.COMPOSITE_NAMESPACE), + keys.NewCollectionSchemaVersionKey(block.Delta.GetSchemaVersionID(), vf.col.Description().RootID), + keys.DataStoreKey{ + CollectionRootID: vf.col.Description().RootID, + DocID: string(block.Delta.GetDocID()), + FieldID: fmt.Sprint(core.COMPOSITE_NAMESPACE), + }, ) - vf.mCRDTs[0] = mcrdt - } - err = mcrdt.Clock().ProcessBlock(vf.ctx, block, link) - if err != nil { - return err - } - // handle subgraphs - for _, l := range block.Links { - // get node - subBlock, err := vf.getDAGBlock(l.Link.Cid) - if err != nil { - return err - } - - field, ok := vf.col.Definition().GetFieldByName(l.Name) + default: + field, ok := vf.col.Definition().GetFieldByName(block.Delta.GetFieldName()) if !ok { - return client.NewErrFieldNotExist(l.Name) + return client.NewErrFieldNotExist(block.Delta.GetFieldName()) } - mcrdt, exists := vf.mCRDTs[field.ID] - if !exists { - mcrdt, err = merklecrdt.FieldLevelCRDTWithStore( - vf.store, - keys.CollectionSchemaVersionKey{}, - field.Typ, - field.Kind, - vf.dsKey.WithFieldID(fmt.Sprint(field.ID)), - field.Name, - ) - if err != nil { - return err - } - vf.mCRDTs[field.ID] = mcrdt + mcrdt, err = merklecrdt.FieldLevelCRDTWithStore( + vf.store, + keys.NewCollectionSchemaVersionKey(block.Delta.GetSchemaVersionID(), vf.col.Description().RootID), + field.Typ, + field.Kind, + keys.DataStoreKey{ + CollectionRootID: vf.col.Description().RootID, + DocID: string(block.Delta.GetDocID()), + FieldID: fmt.Sprint(field.ID), + }, + field.Name, + ) + if err != nil { + return err } + } + + err = mcrdt.Clock().ProcessBlock( + vf.ctx, + block, + cidlink.Link{ + Cid: c, + }, + ) + if err != nil { + return err + } - err = mcrdt.Clock().ProcessBlock(vf.ctx, subBlock, l.Link) + // handle subgraphs + for _, l := range block.AllLinks() { + err = vf.merge(l.Cid) if err != nil { return err } diff --git a/internal/db/merge.go b/internal/db/merge.go index 47db8740b1..c361aa8a2b 100644 --- a/internal/db/merge.go +++ b/internal/db/merge.go @@ -28,6 +28,7 @@ import ( "github.com/sourcenetwork/defradb/event" "github.com/sourcenetwork/defradb/internal/core" coreblock "github.com/sourcenetwork/defradb/internal/core/block" + "github.com/sourcenetwork/defradb/internal/core/crdt" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/encryption" "github.com/sourcenetwork/defradb/internal/keys" @@ -35,30 +36,29 @@ import ( merklecrdt "github.com/sourcenetwork/defradb/internal/merkle/crdt" ) -func (db *db) executeMerge(ctx context.Context, dagMerge event.Merge) error { +func (db *db) executeMerge(ctx context.Context, col *collection, dagMerge event.Merge) error { ctx, txn, err := ensureContextTxn(ctx, db, false) if err != nil { return err } defer txn.Discard(ctx) - col, err := getCollectionFromRootSchema(ctx, db, dagMerge.SchemaRoot) - if err != nil { - return err - } - - docID, err := client.NewDocIDFromString(dagMerge.DocID) - if err != nil { - return err + var key keys.HeadstoreKey + if dagMerge.DocID != "" { + key = keys.HeadstoreDocKey{ + DocID: dagMerge.DocID, + FieldID: core.COMPOSITE_NAMESPACE, + } + } else { + key = keys.NewHeadstoreColKey(col.Description().RootID) } - dsKey := base.MakeDataStoreKeyWithCollectionAndDocID(col.Description(), docID.String()) - mp, err := db.newMergeProcessor(txn, col, dsKey) + mt, err := getHeadsAsMergeTarget(ctx, txn, key) if err != nil { return err } - mt, err := getHeadsAsMergeTarget(ctx, txn, dsKey.WithFieldID(core.COMPOSITE_NAMESPACE)) + mp, err := db.newMergeProcessor(txn, col) if err != nil { return err } @@ -73,9 +73,15 @@ func (db *db) executeMerge(ctx context.Context, dagMerge event.Merge) error { return err } - err = syncIndexedDoc(ctx, docID, col) - if err != nil { - return err + for docID := range mp.docIDs { + docID, err := client.NewDocIDFromString(docID) + if err != nil { + return err + } + err = syncIndexedDoc(ctx, docID, col) + if err != nil { + return err + } } err = txn.Commit(ctx) @@ -94,39 +100,39 @@ func (db *db) executeMerge(ctx context.Context, dagMerge event.Merge) error { // mergeQueue is synchronization source to ensure that concurrent // document merges do not cause transaction conflicts. type mergeQueue struct { - docs map[string]chan struct{} + keys map[string]chan struct{} mutex sync.Mutex } func newMergeQueue() *mergeQueue { return &mergeQueue{ - docs: make(map[string]chan struct{}), + keys: make(map[string]chan struct{}), } } -// add adds a docID to the queue. If the docID is already in the queue, it will -// wait for the docID to be removed from the queue. For every add call, done must -// be called to remove the docID from the queue. Otherwise, subsequent add calls will +// add adds a key to the queue. If the key is already in the queue, it will +// wait for the key to be removed from the queue. For every add call, done must +// be called to remove the key from the queue. Otherwise, subsequent add calls will // block forever. -func (m *mergeQueue) add(docID string) { +func (m *mergeQueue) add(key string) { m.mutex.Lock() - done, ok := m.docs[docID] + done, ok := m.keys[key] if !ok { - m.docs[docID] = make(chan struct{}) + m.keys[key] = make(chan struct{}) } m.mutex.Unlock() if ok { <-done - m.add(docID) + m.add(key) } } -func (m *mergeQueue) done(docID string) { +func (m *mergeQueue) done(key string) { m.mutex.Lock() defer m.mutex.Unlock() - done, ok := m.docs[docID] + done, ok := m.keys[key] if ok { - delete(m.docs, docID) + delete(m.keys, key) close(done) } } @@ -135,9 +141,11 @@ type mergeProcessor struct { txn datastore.Txn blockLS linking.LinkSystem encBlockLS linking.LinkSystem - mCRDTs map[string]merklecrdt.MerkleCRDT col *collection - dsKey keys.DataStoreKey + + // docIDs contains all docIDs that have been merged so far by the mergeProcessor + docIDs map[string]struct{} + // composites is a list of composites that need to be merged. composites *list.List // missingEncryptionBlocks is a list of blocks that we failed to fetch @@ -149,7 +157,6 @@ type mergeProcessor struct { func (db *db) newMergeProcessor( txn datastore.Txn, col *collection, - dsKey keys.DataStoreKey, ) (*mergeProcessor, error) { blockLS := cidlink.DefaultLinkSystem() blockLS.SetReadStorage(txn.Blockstore().AsIPLDStorage()) @@ -161,9 +168,8 @@ func (db *db) newMergeProcessor( txn: txn, blockLS: blockLS, encBlockLS: encBlockLS, - mCRDTs: make(map[string]merklecrdt.MerkleCRDT), col: col, - dsKey: dsKey, + docIDs: make(map[string]struct{}), composites: list.New(), missingEncryptionBlocks: make(map[cidlink.Link]struct{}), availableEncryptionBlocks: make(map[cidlink.Link]*coreblock.Encryption), @@ -375,7 +381,7 @@ func (mp *mergeProcessor) processBlock( } if canRead { - crdt, err := mp.initCRDTForType(dagBlock.Delta.GetFieldName()) + crdt, err := mp.initCRDTForType(dagBlock.Delta) if err != nil { return err } @@ -435,50 +441,59 @@ func decryptBlock( return newBlock, nil } -func (mp *mergeProcessor) initCRDTForType(field string) (merklecrdt.MerkleCRDT, error) { - mcrdt, exists := mp.mCRDTs[field] - if exists { - return mcrdt, nil - } - +func (mp *mergeProcessor) initCRDTForType(crdt crdt.CRDT) (merklecrdt.MerkleCRDT, error) { schemaVersionKey := keys.CollectionSchemaVersionKey{ SchemaVersionID: mp.col.Schema().VersionID, CollectionID: mp.col.ID(), } - if field == "" { - mcrdt = merklecrdt.NewMerkleCompositeDAG( + switch { + case crdt.IsComposite(): + docID := string(crdt.GetDocID()) + mp.docIDs[docID] = struct{}{} + + return merklecrdt.NewMerkleCompositeDAG( mp.txn, schemaVersionKey, - mp.dsKey.WithFieldID(core.COMPOSITE_NAMESPACE), - ) - mp.mCRDTs[field] = mcrdt - return mcrdt, nil - } + base.MakeDataStoreKeyWithCollectionAndDocID(mp.col.Description(), docID).WithFieldID(core.COMPOSITE_NAMESPACE), + ), nil - fd, ok := mp.col.Definition().GetFieldByName(field) - if !ok { - // If the field is not part of the schema, we can safely ignore it. - return nil, nil + case crdt.IsCollection(): + return merklecrdt.NewMerkleCollection( + mp.txn, + schemaVersionKey, + keys.NewHeadstoreColKey(mp.col.Description().RootID), + ), nil + + default: + docID := string(crdt.GetDocID()) + mp.docIDs[docID] = struct{}{} + + field := crdt.GetFieldName() + fd, ok := mp.col.Definition().GetFieldByName(field) + if !ok { + // If the field is not part of the schema, we can safely ignore it. + return nil, nil + } + + return merklecrdt.FieldLevelCRDTWithStore( + mp.txn, + schemaVersionKey, + fd.Typ, + fd.Kind, + base.MakeDataStoreKeyWithCollectionAndDocID(mp.col.Description(), docID).WithFieldID(fd.ID.String()), + field, + ) } +} - mcrdt, err := merklecrdt.FieldLevelCRDTWithStore( - mp.txn, - schemaVersionKey, - fd.Typ, - fd.Kind, - mp.dsKey.WithFieldID(fd.ID.String()), - field, - ) +func getCollectionFromRootSchema(ctx context.Context, db *db, rootSchema string) (*collection, error) { + ctx, txn, err := ensureContextTxn(ctx, db, false) if err != nil { return nil, err } + defer txn.Discard(ctx) - mp.mCRDTs[field] = mcrdt - return mcrdt, nil -} - -func getCollectionFromRootSchema(ctx context.Context, db *db, rootSchema string) (*collection, error) { cols, err := db.getCollections( ctx, client.CollectionFetchOptions{ @@ -498,8 +513,8 @@ func getCollectionFromRootSchema(ctx context.Context, db *db, rootSchema string) // getHeadsAsMergeTarget retrieves the heads of the composite DAG for the given document // and returns them as a merge target. -func getHeadsAsMergeTarget(ctx context.Context, txn datastore.Txn, dsKey keys.DataStoreKey) (mergeTarget, error) { - cids, err := getHeads(ctx, txn, dsKey) +func getHeadsAsMergeTarget(ctx context.Context, txn datastore.Txn, key keys.HeadstoreKey) (mergeTarget, error) { + cids, err := getHeads(ctx, txn, key) if err != nil { return mergeTarget{}, err @@ -520,8 +535,8 @@ func getHeadsAsMergeTarget(ctx context.Context, txn datastore.Txn, dsKey keys.Da } // getHeads retrieves the heads associated with the given datastore key. -func getHeads(ctx context.Context, txn datastore.Txn, dsKey keys.DataStoreKey) ([]cid.Cid, error) { - headset := clock.NewHeadSet(txn.Headstore(), dsKey.ToHeadStoreKey()) +func getHeads(ctx context.Context, txn datastore.Txn, key keys.HeadstoreKey) ([]cid.Cid, error) { + headset := clock.NewHeadSet(txn.Headstore(), key) cids, _, err := headset.List(ctx) if err != nil { diff --git a/internal/db/merge_test.go b/internal/db/merge_test.go index f9478be536..ee170bfe54 100644 --- a/internal/db/merge_test.go +++ b/internal/db/merge_test.go @@ -58,7 +58,7 @@ func TestMerge_SingleBranch_NoError(t *testing.T) { compInfo2, err := d.generateCompositeUpdate(&lsys, map[string]any{"name": "Johny"}, compInfo) require.NoError(t, err) - err = db.executeMerge(ctx, event.Merge{ + err = db.executeMerge(ctx, col.(*collection), event.Merge{ DocID: docID.String(), Cid: compInfo2.link.Cid, SchemaRoot: col.SchemaRoot(), @@ -103,7 +103,7 @@ func TestMerge_DualBranch_NoError(t *testing.T) { compInfo2, err := d.generateCompositeUpdate(&lsys, map[string]any{"name": "Johny"}, compInfo) require.NoError(t, err) - err = db.executeMerge(ctx, event.Merge{ + err = db.executeMerge(ctx, col.(*collection), event.Merge{ DocID: docID.String(), Cid: compInfo2.link.Cid, SchemaRoot: col.SchemaRoot(), @@ -113,7 +113,7 @@ func TestMerge_DualBranch_NoError(t *testing.T) { compInfo3, err := d.generateCompositeUpdate(&lsys, map[string]any{"age": 30}, compInfo) require.NoError(t, err) - err = db.executeMerge(ctx, event.Merge{ + err = db.executeMerge(ctx, col.(*collection), event.Merge{ DocID: docID.String(), Cid: compInfo3.link.Cid, SchemaRoot: col.SchemaRoot(), @@ -161,7 +161,7 @@ func TestMerge_DualBranchWithOneIncomplete_CouldNotFindCID(t *testing.T) { compInfo2, err := d.generateCompositeUpdate(&lsys, map[string]any{"name": "Johny"}, compInfo) require.NoError(t, err) - err = db.executeMerge(ctx, event.Merge{ + err = db.executeMerge(ctx, col.(*collection), event.Merge{ DocID: docID.String(), Cid: compInfo2.link.Cid, SchemaRoot: col.SchemaRoot(), @@ -180,7 +180,7 @@ func TestMerge_DualBranchWithOneIncomplete_CouldNotFindCID(t *testing.T) { compInfo3, err := d.generateCompositeUpdate(&lsys, map[string]any{"name": "Johny"}, compInfoUnkown) require.NoError(t, err) - err = db.executeMerge(ctx, event.Merge{ + err = db.executeMerge(ctx, col.(*collection), event.Merge{ DocID: docID.String(), Cid: compInfo3.link.Cid, SchemaRoot: col.SchemaRoot(), @@ -304,15 +304,15 @@ func TestMergeQueue(t *testing.T) { go q.add(testDocID) // give time for the goroutine to block time.Sleep(10 * time.Millisecond) - require.Len(t, q.docs, 1) + require.Len(t, q.keys, 1) q.done(testDocID) // give time for the goroutine to add the docID time.Sleep(10 * time.Millisecond) q.mutex.Lock() - require.Len(t, q.docs, 1) + require.Len(t, q.keys, 1) q.mutex.Unlock() q.done(testDocID) q.mutex.Lock() - require.Len(t, q.docs, 0) + require.Len(t, q.keys, 0) q.mutex.Unlock() } diff --git a/internal/db/messages.go b/internal/db/messages.go index 51efba982e..e980eb7d84 100644 --- a/internal/db/messages.go +++ b/internal/db/messages.go @@ -22,7 +22,9 @@ import ( ) func (db *db) handleMessages(ctx context.Context, sub *event.Subscription) { - queue := newMergeQueue() + docIDQueue := newMergeQueue() + schemaRootQueue := newMergeQueue() + // This is used to ensure we only trigger loadAndPublishP2PCollections and loadAndPublishReplicators // once per db instanciation. loadOnce := sync.Once{} @@ -37,17 +39,34 @@ func (db *db) handleMessages(ctx context.Context, sub *event.Subscription) { switch evt := msg.Data.(type) { case event.Merge: go func() { - // ensure only one merge per docID - queue.add(evt.DocID) - defer queue.done(evt.DocID) + col, err := getCollectionFromRootSchema(ctx, db, evt.SchemaRoot) + if err != nil { + log.ErrorContextE( + ctx, + "Failed to execute merge", + err, + corelog.Any("Event", evt)) + return + } + + if col.Description().IsBranchable { + // As collection commits link to document composite commits, all events + // recieved for branchable collections must be processed serially else + // they may otherwise cause a transaction conflict. + schemaRootQueue.add(evt.SchemaRoot) + defer schemaRootQueue.done(evt.SchemaRoot) + } else { + // ensure only one merge per docID + docIDQueue.add(evt.DocID) + defer docIDQueue.done(evt.DocID) + } // retry the merge process if a conflict occurs // // conficts occur when a user updates a document // while a merge is in progress. - var err error for i := 0; i < db.MaxTxnRetries(); i++ { - err = db.executeMerge(ctx, evt) + err = db.executeMerge(ctx, col, evt) if errors.Is(err, datastore.ErrTxnConflict) { continue // retry merge } diff --git a/internal/lens/fetcher.go b/internal/lens/fetcher.go index a441c357bd..1729aecdb4 100644 --- a/internal/lens/fetcher.go +++ b/internal/lens/fetcher.go @@ -127,8 +127,8 @@ historyLoop: ) } -func (f *lensedFetcher) Start(ctx context.Context, spans ...core.Span) error { - return f.source.Start(ctx, spans...) +func (f *lensedFetcher) Start(ctx context.Context, prefixes ...keys.Walkable) error { + return f.source.Start(ctx, prefixes...) } func (f *lensedFetcher) FetchNext(ctx context.Context) (fetcher.EncodedDocument, fetcher.ExecInfo, error) { diff --git a/internal/planner/arbitrary_join.go b/internal/planner/arbitrary_join.go index e668287028..2d510f1bdc 100644 --- a/internal/planner/arbitrary_join.go +++ b/internal/planner/arbitrary_join.go @@ -15,6 +15,7 @@ import ( "strings" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -79,13 +80,13 @@ func (n *dataSource) Start() error { return nil } -func (n *dataSource) Spans(spans []core.Span) { +func (n *dataSource) Prefixes(prefixes []keys.Walkable) { if n.parentSource != nil { - n.parentSource.Spans(spans) + n.parentSource.Prefixes(prefixes) } if n.childSource != nil { - n.childSource.Spans(spans) + n.childSource.Prefixes(prefixes) } } diff --git a/internal/planner/average.go b/internal/planner/average.go index 1d20fb3560..76bbfc107d 100644 --- a/internal/planner/average.go +++ b/internal/planner/average.go @@ -13,7 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" - "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -68,11 +68,11 @@ func (n *averageNode) Init() error { return n.plan.Init() } -func (n *averageNode) Kind() string { return "averageNode" } -func (n *averageNode) Start() error { return n.plan.Start() } -func (n *averageNode) Spans(spans []core.Span) { n.plan.Spans(spans) } -func (n *averageNode) Close() error { return n.plan.Close() } -func (n *averageNode) Source() planNode { return n.plan } +func (n *averageNode) Kind() string { return "averageNode" } +func (n *averageNode) Start() error { return n.plan.Start() } +func (n *averageNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } +func (n *averageNode) Close() error { return n.plan.Close() } +func (n *averageNode) Source() planNode { return n.plan } func (n *averageNode) Next() (bool, error) { n.execInfo.iterations++ diff --git a/internal/planner/commit.go b/internal/planner/commit.go index c73944b250..348a4b4e6a 100644 --- a/internal/planner/commit.go +++ b/internal/planner/commit.go @@ -91,13 +91,13 @@ func (n *dagScanNode) Start() error { return nil } -// Spans needs to parse the given span set. dagScanNode only -// cares about the first value in the span set. The value is +// Prefixes needs to parse the given prefix set. dagScanNode only +// cares about the first value in the prefix set. The value is // either a CID or a DocID. // If its a CID, set the node CID val // if its a DocID, set the node Key val (headset) -func (n *dagScanNode) Spans(spans []core.Span) { - if len(spans) == 0 { +func (n *dagScanNode) Prefixes(prefixes []keys.Walkable) { + if len(prefixes) == 0 { return } @@ -108,9 +108,9 @@ func (n *dagScanNode) Spans(spans []core.Span) { fieldID = core.COMPOSITE_NAMESPACE } - for _, span := range spans { + for _, prefix := range prefixes { var start keys.HeadstoreDocKey - switch s := span.Start.(type) { + switch s := prefix.(type) { case keys.DataStoreKey: start = s.ToHeadStoreKey() case keys.HeadstoreDocKey: @@ -145,20 +145,14 @@ func (n *dagScanNode) simpleExplain() (map[string]any, error) { simpleExplainMap["cid"] = nil } - // Build the explanation of the spans attribute. - spansExplainer := []map[string]any{} + // Build the explanation of the prefixes attribute. + prefixesExplainer := []string{} // Note: n.headset is `nil` for single commit selection query, so must check for it. if n.prefix.HasValue() { - spansExplainer = append( - spansExplainer, - map[string]any{ - "start": n.prefix.Value().ToString(), - "end": n.prefix.Value().PrefixEnd().ToString(), - }, - ) + prefixesExplainer = append(prefixesExplainer, keys.PrettyPrint(n.prefix.Value())) } - // Add the built spans attribute, if it was valid. - simpleExplainMap[spansLabel] = spansExplainer + // Add the built prefixes attribute, if it was valid. + simpleExplainMap[prefixesLabel] = prefixesExplainer return simpleExplainMap, nil } diff --git a/internal/planner/count.go b/internal/planner/count.go index 0e15e037e5..1b58109749 100644 --- a/internal/planner/count.go +++ b/internal/planner/count.go @@ -22,6 +22,7 @@ import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -64,7 +65,7 @@ func (n *countNode) Init() error { func (n *countNode) Start() error { return n.plan.Start() } -func (n *countNode) Spans(spans []core.Span) { n.plan.Spans(spans) } +func (n *countNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } func (n *countNode) Close() error { return n.plan.Close() } diff --git a/internal/planner/create.go b/internal/planner/create.go index 1b03857a13..58bd079e19 100644 --- a/internal/planner/create.go +++ b/internal/planner/create.go @@ -13,9 +13,9 @@ package planner import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" - "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/encryption" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -56,13 +56,12 @@ func (n *createNode) Kind() string { return "createNode" } func (n *createNode) Init() error { return nil } -func docIDsToSpans(ids []string, desc client.CollectionDescription) []core.Span { - spans := make([]core.Span, len(ids)) +func docIDsToPrefixes(ids []string, desc client.CollectionDescription) []keys.Walkable { + prefixes := make([]keys.Walkable, len(ids)) for i, id := range ids { - docID := base.MakeDataStoreKeyWithCollectionAndDocID(desc, id) - spans[i] = core.NewSpan(docID, docID.PrefixEnd()) + prefixes[i] = base.MakeDataStoreKeyWithCollectionAndDocID(desc, id) } - return spans + return prefixes } func documentsToDocIDs(docs ...*client.Document) []string { @@ -96,7 +95,7 @@ func (n *createNode) Next() (bool, error) { return false, err } - n.results.Spans(docIDsToSpans(documentsToDocIDs(n.docs...), n.collection.Description())) + n.results.Prefixes(docIDsToPrefixes(documentsToDocIDs(n.docs...), n.collection.Description())) err = n.results.Init() if err != nil { @@ -115,7 +114,7 @@ func (n *createNode) Next() (bool, error) { return next, err } -func (n *createNode) Spans(spans []core.Span) { /* no-op */ } +func (n *createNode) Prefixes(prefixes []keys.Walkable) { /* no-op */ } func (n *createNode) Close() error { return n.results.Close() diff --git a/internal/planner/delete.go b/internal/planner/delete.go index 9142a76868..fa35b16ed7 100644 --- a/internal/planner/delete.go +++ b/internal/planner/delete.go @@ -13,7 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" - "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -67,8 +67,8 @@ func (n *deleteNode) Next() (bool, error) { return true, nil } -func (n *deleteNode) Spans(spans []core.Span) { - n.source.Spans(spans) +func (n *deleteNode) Prefixes(prefixes []keys.Walkable) { + n.source.Prefixes(prefixes) } func (n *deleteNode) Kind() string { diff --git a/internal/planner/explain.go b/internal/planner/explain.go index 860ea39df1..3a6be07f94 100644 --- a/internal/planner/explain.go +++ b/internal/planner/explain.go @@ -66,7 +66,7 @@ const ( limitLabel = "limit" offsetLabel = "offset" sourcesLabel = "sources" - spansLabel = "spans" + prefixesLabel = "prefixes" ) // buildDebugExplainGraph dumps the entire plan graph as is, with all the plan nodes. diff --git a/internal/planner/group.go b/internal/planner/group.go index 2491740e81..900f0ff412 100644 --- a/internal/planner/group.go +++ b/internal/planner/group.go @@ -14,6 +14,7 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -127,9 +128,9 @@ func (n *groupNode) Start() error { return nil } -func (n *groupNode) Spans(spans []core.Span) { +func (n *groupNode) Prefixes(prefixes []keys.Walkable) { for _, dataSource := range n.dataSources { - dataSource.Spans(spans) + dataSource.Prefixes(prefixes) } } diff --git a/internal/planner/lens.go b/internal/planner/lens.go index 618642b5df..25f2254237 100644 --- a/internal/planner/lens.go +++ b/internal/planner/lens.go @@ -16,6 +16,7 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" ) // viewNode applies a lens transform to data yielded from the source node. @@ -61,8 +62,8 @@ func (n *lensNode) Start() error { return n.source.Start() } -func (n *lensNode) Spans(spans []core.Span) { - n.source.Spans(spans) +func (n *lensNode) Prefixes(prefixes []keys.Walkable) { + n.source.Prefixes(prefixes) } func (n *lensNode) Next() (bool, error) { diff --git a/internal/planner/limit.go b/internal/planner/limit.go index 5281a7e215..3ccdfbeac7 100644 --- a/internal/planner/limit.go +++ b/internal/planner/limit.go @@ -13,6 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -59,10 +60,10 @@ func (n *limitNode) Init() error { return n.plan.Init() } -func (n *limitNode) Start() error { return n.plan.Start() } -func (n *limitNode) Spans(spans []core.Span) { n.plan.Spans(spans) } -func (n *limitNode) Close() error { return n.plan.Close() } -func (n *limitNode) Value() core.Doc { return n.plan.Value() } +func (n *limitNode) Start() error { return n.plan.Start() } +func (n *limitNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } +func (n *limitNode) Close() error { return n.plan.Close() } +func (n *limitNode) Value() core.Doc { return n.plan.Value() } func (n *limitNode) Next() (bool, error) { n.execInfo.iterations++ diff --git a/internal/planner/max.go b/internal/planner/max.go index 4203aca6c3..530e60e25e 100644 --- a/internal/planner/max.go +++ b/internal/planner/max.go @@ -17,6 +17,7 @@ import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -57,13 +58,13 @@ func (p *Planner) Max( }, nil } -func (n *maxNode) Kind() string { return "maxNode" } -func (n *maxNode) Init() error { return n.plan.Init() } -func (n *maxNode) Start() error { return n.plan.Start() } -func (n *maxNode) Spans(spans []core.Span) { n.plan.Spans(spans) } -func (n *maxNode) Close() error { return n.plan.Close() } -func (n *maxNode) Source() planNode { return n.plan } -func (n *maxNode) SetPlan(p planNode) { n.plan = p } +func (n *maxNode) Kind() string { return "maxNode" } +func (n *maxNode) Init() error { return n.plan.Init() } +func (n *maxNode) Start() error { return n.plan.Start() } +func (n *maxNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } +func (n *maxNode) Close() error { return n.plan.Close() } +func (n *maxNode) Source() planNode { return n.plan } +func (n *maxNode) SetPlan(p planNode) { n.plan = p } func (n *maxNode) simpleExplain() (map[string]any, error) { sourceExplanations := make([]map[string]any, len(n.aggregateMapping)) diff --git a/internal/planner/min.go b/internal/planner/min.go index 29b999d543..be70a8ccb9 100644 --- a/internal/planner/min.go +++ b/internal/planner/min.go @@ -17,6 +17,7 @@ import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -57,13 +58,13 @@ func (p *Planner) Min( }, nil } -func (n *minNode) Kind() string { return "minNode" } -func (n *minNode) Init() error { return n.plan.Init() } -func (n *minNode) Start() error { return n.plan.Start() } -func (n *minNode) Spans(spans []core.Span) { n.plan.Spans(spans) } -func (n *minNode) Close() error { return n.plan.Close() } -func (n *minNode) Source() planNode { return n.plan } -func (n *minNode) SetPlan(p planNode) { n.plan = p } +func (n *minNode) Kind() string { return "minNode" } +func (n *minNode) Init() error { return n.plan.Init() } +func (n *minNode) Start() error { return n.plan.Start() } +func (n *minNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } +func (n *minNode) Close() error { return n.plan.Close() } +func (n *minNode) Source() planNode { return n.plan } +func (n *minNode) SetPlan(p planNode) { n.plan = p } func (n *minNode) simpleExplain() (map[string]any, error) { sourceExplanations := make([]map[string]any, len(n.aggregateMapping)) diff --git a/internal/planner/multi.go b/internal/planner/multi.go index 579f169344..37d7aa435d 100644 --- a/internal/planner/multi.go +++ b/internal/planner/multi.go @@ -91,9 +91,9 @@ func (p *parallelNode) Start() error { }) } -func (p *parallelNode) Spans(spans []core.Span) { +func (p *parallelNode) Prefixes(prefixes []keys.Walkable) { _ = p.applyToPlans(func(n planNode) error { - n.Spans(spans) + n.Prefixes(prefixes) return nil }) } @@ -156,9 +156,9 @@ func (p *parallelNode) nextAppend(index int, plan planNode) (bool, error) { return false, nil } - // pass the doc key as a reference through the spans interface - spans := []core.Span{core.NewSpan(keys.DataStoreKey{DocID: key}, keys.DataStoreKey{})} - plan.Spans(spans) + // pass the doc key as a reference through the prefixes interface + prefixes := []keys.Walkable{keys.DataStoreKey{DocID: key}} + plan.Prefixes(prefixes) err := plan.Init() if err != nil { return false, err diff --git a/internal/planner/operation.go b/internal/planner/operation.go index 6f351f92a1..faa2f0618b 100644 --- a/internal/planner/operation.go +++ b/internal/planner/operation.go @@ -13,6 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -28,9 +29,9 @@ type operationNode struct { isDone bool } -func (n *operationNode) Spans(spans []core.Span) { +func (n *operationNode) Prefixes(prefixes []keys.Walkable) { for _, child := range n.children { - child.Spans(spans) + child.Prefixes(prefixes) } } diff --git a/internal/planner/order.go b/internal/planner/order.go index 0a69ba5453..04c8fd52ea 100644 --- a/internal/planner/order.go +++ b/internal/planner/order.go @@ -14,6 +14,7 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -98,7 +99,7 @@ func (n *orderNode) Init() error { } func (n *orderNode) Start() error { return n.plan.Start() } -func (n *orderNode) Spans(spans []core.Span) { n.plan.Spans(spans) } +func (n *orderNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } func (n *orderNode) Value() core.Doc { return n.valueIter.Value() diff --git a/internal/planner/pipe.go b/internal/planner/pipe.go index b9331fce45..22026abc69 100644 --- a/internal/planner/pipe.go +++ b/internal/planner/pipe.go @@ -13,6 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/container" + "github.com/sourcenetwork/defradb/internal/keys" ) // A lazily loaded cache-node that allows retrieval of cached documents at arbitrary indexes. @@ -51,10 +52,10 @@ func (n *pipeNode) Init() error { return n.source.Init() } -func (n *pipeNode) Start() error { return n.source.Start() } -func (n *pipeNode) Spans(spans []core.Span) { n.source.Spans(spans) } -func (n *pipeNode) Close() error { return n.source.Close() } -func (n *pipeNode) Source() planNode { return n.source } +func (n *pipeNode) Start() error { return n.source.Start() } +func (n *pipeNode) Prefixes(prefixes []keys.Walkable) { n.source.Prefixes(prefixes) } +func (n *pipeNode) Close() error { return n.source.Close() } +func (n *pipeNode) Source() planNode { return n.source } func (n *pipeNode) Next() (bool, error) { // we need to load all docs up until the requested point - this allows us to diff --git a/internal/planner/planner.go b/internal/planner/planner.go index 77dac1c7a2..8390c6d5a5 100644 --- a/internal/planner/planner.go +++ b/internal/planner/planner.go @@ -22,6 +22,7 @@ import ( "github.com/sourcenetwork/defradb/datastore" "github.com/sourcenetwork/defradb/internal/connor" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/filter" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -34,9 +35,9 @@ type planNode interface { // Starts any internal logic or processes required by the planNode. Should be called *after* Init(). Start() error - // Spans sets the planNodes target spans. This is primarily only used for a scanNode, + // Prefixes sets the planNodes target prefixes. This is primarily only used for a scanNode, // but based on the tree structure, may need to be propagated Eg. From a selectNode -> scanNode. - Spans([]core.Span) + Prefixes([]keys.Walkable) // Next processes the next result doc from the request. Can only be called *after* Start(). // Can't be called again if any previous call returns false. diff --git a/internal/planner/scan.go b/internal/planner/scan.go index c00cda401c..eed370d0ae 100644 --- a/internal/planner/scan.go +++ b/internal/planner/scan.go @@ -46,8 +46,8 @@ type scanNode struct { showDeleted bool - spans []core.Span - reverse bool + prefixes []keys.Walkable + reverse bool filter *mapper.Filter slct *mapper.Select @@ -202,12 +202,12 @@ func (n *scanNode) Start() error { } func (n *scanNode) initScan() error { - if len(n.spans) == 0 { - start := base.MakeDataStoreKeyWithCollectionDescription(n.col.Description()) - n.spans = []core.Span{core.NewSpan(start, start.PrefixEnd())} + if len(n.prefixes) == 0 { + prefix := base.MakeDataStoreKeyWithCollectionDescription(n.col.Description()) + n.prefixes = []keys.Walkable{prefix} } - err := n.fetcher.Start(n.p.ctx, n.spans...) + err := n.fetcher.Start(n.p.ctx, n.prefixes...) if err != nil { return err } @@ -221,7 +221,7 @@ func (n *scanNode) initScan() error { func (n *scanNode) Next() (bool, error) { n.execInfo.iterations++ - if len(n.spans) == 0 { + if len(n.prefixes) == 0 { return false, nil } @@ -249,8 +249,8 @@ func (n *scanNode) Next() (bool, error) { return true, nil } -func (n *scanNode) Spans(spans []core.Span) { - n.spans = spans +func (n *scanNode) Prefixes(prefixes []keys.Walkable) { + n.prefixes = prefixes } func (n *scanNode) Close() error { @@ -259,19 +259,13 @@ func (n *scanNode) Close() error { func (n *scanNode) Source() planNode { return nil } -// explainSpans explains the spans attribute. -func (n *scanNode) explainSpans() []map[string]any { - spansExplainer := []map[string]any{} - for _, span := range n.spans { - spanExplainer := map[string]any{ - "start": keys.PrettyPrint(span.Start), - "end": keys.PrettyPrint(span.End), - } - - spansExplainer = append(spansExplainer, spanExplainer) +// explainPrefixes explains the prefixes attribute. +func (n *scanNode) explainPrefixes() []string { + prefixes := make([]string, len(n.prefixes)) + for i, prefix := range n.prefixes { + prefixes[i] = keys.PrettyPrint(prefix) } - - return spansExplainer + return prefixes } func (n *scanNode) simpleExplain() (map[string]any, error) { @@ -288,8 +282,8 @@ func (n *scanNode) simpleExplain() (map[string]any, error) { simpleExplainMap[collectionNameLabel] = n.col.Name().Value() simpleExplainMap[collectionIDLabel] = n.col.Description().IDString() - // Add the spans attribute. - simpleExplainMap[spansLabel] = n.explainSpans() + // Add the prefixes attribute. + simpleExplainMap[prefixesLabel] = n.explainPrefixes() return simpleExplainMap, nil } @@ -418,8 +412,8 @@ func (n *multiScanNode) Value() core.Doc { return n.scanNode.documentIterator.Value() } -func (n *multiScanNode) Spans(spans []core.Span) { - n.scanNode.Spans(spans) +func (n *multiScanNode) Prefixes(prefixes []keys.Walkable) { + n.scanNode.Prefixes(prefixes) } func (n *multiScanNode) Source() planNode { diff --git a/internal/planner/select.go b/internal/planner/select.go index 8e69510eed..d3bcbb910d 100644 --- a/internal/planner/select.go +++ b/internal/planner/select.go @@ -70,7 +70,7 @@ func (n *selectTopNode) Start() error { return n.planNode.Start() } func (n *selectTopNode) Next() (bool, error) { return n.planNode.Next() } -func (n *selectTopNode) Spans(spans []core.Span) { n.planNode.Spans(spans) } +func (n *selectTopNode) Prefixes(prefixes []keys.Walkable) { n.planNode.Prefixes(prefixes) } func (n *selectTopNode) Value() core.Doc { return n.planNode.Value() } @@ -182,8 +182,8 @@ func (n *selectNode) Next() (bool, error) { } } -func (n *selectNode) Spans(spans []core.Span) { - n.source.Spans(spans) +func (n *selectNode) Prefixes(prefixes []keys.Walkable) { + n.source.Prefixes(prefixes) } func (n *selectNode) Close() error { @@ -256,38 +256,37 @@ func (n *selectNode) initSource() ([]aggregateNode, error) { origScan.filter = n.filter n.filter = nil - // If we have both a DocID and a CID, then we need to run - // a TimeTravel (History-Traversing Versioned) query, which means - // we need to propagate the values to the underlying VersionedFetcher + // If we have a CID, then we need to run a TimeTravel (History-Traversing Versioned) + // query, which means we need to propagate the values to the underlying VersionedFetcher if n.selectReq.Cid.HasValue() { c, err := cid.Decode(n.selectReq.Cid.Value()) if err != nil { return nil, err } - origScan.Spans( - []core.Span{ - core.NewSpan( - keys.HeadstoreDocKey{ - DocID: n.selectReq.DocIDs.Value()[0], - Cid: c, - }, - keys.HeadstoreDocKey{}, - ), + + // This exists because the fetcher interface demands a []Prefixes, yet the versioned + // fetcher type (that will be the only one consuming this []Prefixes) does not use it + // as a prefix. And with this design limitation this is + // currently the least bad way of passing the cid in to the fetcher. + origScan.Prefixes( + []keys.Walkable{ + keys.HeadstoreDocKey{ + Cid: c, + }, }, ) } else if n.selectReq.DocIDs.HasValue() { // If we *just* have a DocID(s), run a FindByDocID(s) optimization - // if we have a FindByDocID filter, create a span for it + // if we have a FindByDocID filter, create a prefix for it // and propagate it to the scanNode // @todo: When running the optimizer, check if the filter object // contains a _docID equality condition, and upgrade it to a point lookup // instead of a prefix scan + filter via the Primary Index (0), like here: - spans := make([]core.Span, len(n.selectReq.DocIDs.Value())) + prefixes := make([]keys.Walkable, len(n.selectReq.DocIDs.Value())) for i, docID := range n.selectReq.DocIDs.Value() { - docIDIndexKey := base.MakeDataStoreKeyWithCollectionAndDocID(sourcePlan.collection.Description(), docID) - spans[i] = core.NewSpan(docIDIndexKey, docIDIndexKey.PrefixEnd()) + prefixes[i] = base.MakeDataStoreKeyWithCollectionAndDocID(sourcePlan.collection.Description(), docID) } - origScan.Spans(spans) + origScan.Prefixes(prefixes) } } diff --git a/internal/planner/sum.go b/internal/planner/sum.go index 6bc0aff707..a77e56da3d 100644 --- a/internal/planner/sum.go +++ b/internal/planner/sum.go @@ -16,6 +16,7 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -152,7 +153,7 @@ func (n *sumNode) Init() error { func (n *sumNode) Start() error { return n.plan.Start() } -func (n *sumNode) Spans(spans []core.Span) { n.plan.Spans(spans) } +func (n *sumNode) Prefixes(prefixes []keys.Walkable) { n.plan.Prefixes(prefixes) } func (n *sumNode) Close() error { return n.plan.Close() } diff --git a/internal/planner/top.go b/internal/planner/top.go index 6bf2d1c269..658dc66dd8 100644 --- a/internal/planner/top.go +++ b/internal/planner/top.go @@ -13,6 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client/request" "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -35,7 +36,7 @@ type topLevelNode struct { isInRecurse bool } -func (n *topLevelNode) Spans(spans []core.Span) { +func (n *topLevelNode) Prefixes(prefixes []keys.Walkable) { if n.isInRecurse { return } @@ -45,7 +46,7 @@ func (n *topLevelNode) Spans(spans []core.Span) { }() for _, child := range n.children { - child.Spans(spans) + child.Prefixes(prefixes) } } diff --git a/internal/planner/type_join.go b/internal/planner/type_join.go index a9063d07d6..5e7b83d237 100644 --- a/internal/planner/type_join.go +++ b/internal/planner/type_join.go @@ -18,6 +18,7 @@ import ( "github.com/sourcenetwork/defradb/internal/connor" "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/filter" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -114,8 +115,8 @@ func (n *typeIndexJoin) Start() error { return n.joinPlan.Start() } -func (n *typeIndexJoin) Spans(spans []core.Span) { - n.joinPlan.Spans(spans) +func (n *typeIndexJoin) Prefixes(prefixes []keys.Walkable) { + n.joinPlan.Prefixes(prefixes) } func (n *typeIndexJoin) Next() (bool, error) { @@ -444,9 +445,9 @@ func fetchDocWithID(node planNode, docID string) (bool, error) { } dsKey := base.MakeDataStoreKeyWithCollectionAndDocID(scan.col.Description(), docID) - spans := []core.Span{core.NewSpan(dsKey, dsKey.PrefixEnd())} + prefixes := []keys.Walkable{dsKey} - node.Spans(spans) + node.Prefixes(prefixes) if err := node.Init(); err != nil { return false, NewErrSubTypeInit(err) @@ -502,8 +503,8 @@ func (join *invertibleTypeJoin) Close() error { return join.childSide.plan.Close() } -func (join *invertibleTypeJoin) Spans(spans []core.Span) { - join.parentSide.plan.Spans(spans) +func (join *invertibleTypeJoin) Prefixes(prefixes []keys.Walkable) { + join.parentSide.plan.Prefixes(prefixes) } func (join *invertibleTypeJoin) Source() planNode { return join.parentSide.plan } diff --git a/internal/planner/update.go b/internal/planner/update.go index 4340625bf8..e313e17e18 100644 --- a/internal/planner/update.go +++ b/internal/planner/update.go @@ -13,7 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" - "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -107,7 +107,7 @@ func (n *updateNode) Next() (bool, error) { func (n *updateNode) Kind() string { return "updateNode" } -func (n *updateNode) Spans(spans []core.Span) { n.results.Spans(spans) } +func (n *updateNode) Prefixes(prefixes []keys.Walkable) { n.results.Prefixes(prefixes) } func (n *updateNode) Init() error { return n.results.Init() } diff --git a/internal/planner/upsert.go b/internal/planner/upsert.go index 331d1e4171..09855a81f4 100644 --- a/internal/planner/upsert.go +++ b/internal/planner/upsert.go @@ -13,7 +13,7 @@ package planner import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/client/request" - "github.com/sourcenetwork/defradb/internal/core" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -73,7 +73,7 @@ func (n *upsertNode) Next() (bool, error) { if err != nil { return false, err } - n.source.Spans(docIDsToSpans(documentsToDocIDs(doc), n.collection.Description())) + n.source.Prefixes(docIDsToPrefixes(documentsToDocIDs(doc), n.collection.Description())) } err = n.source.Init() if err != nil { @@ -96,8 +96,8 @@ func (n *upsertNode) Kind() string { return "upsertNode" } -func (n *upsertNode) Spans(spans []core.Span) { - n.source.Spans(spans) +func (n *upsertNode) Prefixes(prefixes []keys.Walkable) { + n.source.Prefixes(prefixes) } func (n *upsertNode) Init() error { diff --git a/internal/planner/values.go b/internal/planner/values.go index 4028f52594..de630679d6 100644 --- a/internal/planner/values.go +++ b/internal/planner/values.go @@ -16,6 +16,7 @@ import ( "github.com/sourcenetwork/defradb/internal/core" "github.com/sourcenetwork/defradb/internal/db/base" "github.com/sourcenetwork/defradb/internal/db/container" + "github.com/sourcenetwork/defradb/internal/keys" "github.com/sourcenetwork/defradb/internal/planner/mapper" ) @@ -46,9 +47,9 @@ func (p *Planner) newContainerValuesNode(ordering []mapper.OrderCondition) *valu } } -func (n *valuesNode) Init() error { return nil } -func (n *valuesNode) Start() error { return nil } -func (n *valuesNode) Spans(spans []core.Span) {} +func (n *valuesNode) Init() error { return nil } +func (n *valuesNode) Start() error { return nil } +func (n *valuesNode) Prefixes(prefixes []keys.Walkable) {} func (n *valuesNode) Kind() string { return "valuesNode" diff --git a/internal/planner/view.go b/internal/planner/view.go index b834d74323..87b7faba11 100644 --- a/internal/planner/view.go +++ b/internal/planner/view.go @@ -74,8 +74,8 @@ func (n *viewNode) Start() error { return n.source.Start() } -func (n *viewNode) Spans(spans []core.Span) { - n.source.Spans(spans) +func (n *viewNode) Prefixes(prefixes []keys.Walkable) { + n.source.Prefixes(prefixes) } func (n *viewNode) Next() (bool, error) { @@ -217,7 +217,7 @@ func (n *cachedViewFetcher) Start() error { return nil } -func (n *cachedViewFetcher) Spans(spans []core.Span) { +func (n *cachedViewFetcher) Prefixes(prefixes []keys.Walkable) { // no-op } diff --git a/internal/request/graphql/schema/descriptions.go b/internal/request/graphql/schema/descriptions.go index b667410c2c..b7c0373abc 100644 --- a/internal/request/graphql/schema/descriptions.go +++ b/internal/request/graphql/schema/descriptions.go @@ -73,11 +73,10 @@ An optional set of docIDs for this field. Only documents with a docID be ignored. ` cidArgDescription string = ` -An optional value that specifies the commit ID of the document to return. - This CID does not need to be the most recent for a document, if it - corresponds to an older version of a document the document will be returned - at the state it was in at the time of that commit. If a matching commit is - not found then an empty set will be returned. +An optional value that specifies the commit ID of a document or a branchable collection. + This CID does not need to be the most recent. If it corresponds to an older version + the document(s) will be returned at the state they were in at the time of that commit. + If a matching commit is not found then an empty set will be returned. ` singleFieldFilterArgDescription string = ` An optional filter for this join, if the related record does diff --git a/net/peer.go b/net/peer.go index e4ebfe8573..d59d6fe150 100644 --- a/net/peer.go +++ b/net/peer.go @@ -255,9 +255,11 @@ func (p *Peer) handleMessageLoop() { } func (p *Peer) handleLog(evt event.Update) error { - _, err := client.NewDocIDFromString(evt.DocID) - if err != nil { - return NewErrFailedToGetDocID(err) + if evt.DocID != "" { + _, err := client.NewDocIDFromString(evt.DocID) + if err != nil { + return NewErrFailedToGetDocID(err) + } } // push to each peer (replicator) @@ -273,8 +275,10 @@ func (p *Peer) handleLog(evt event.Update) error { Block: evt.Block, } - if err := p.server.publishLog(p.ctx, evt.DocID, req); err != nil { - return NewErrPublishingToDocIDTopic(err, evt.Cid.String(), evt.DocID) + if evt.DocID != "" { + if err := p.server.publishLog(p.ctx, evt.DocID, req); err != nil { + return NewErrPublishingToDocIDTopic(err, evt.Cid.String(), evt.DocID) + } } if err := p.server.publishLog(p.ctx, evt.SchemaRoot, req); err != nil { diff --git a/net/server.go b/net/server.go index c83ba3f6be..0be9def0ce 100644 --- a/net/server.go +++ b/net/server.go @@ -110,9 +110,12 @@ func (s *server) PushLog(ctx context.Context, req *pushLogRequest) (*pushLogRepl if err != nil { return nil, err } - docID, err := client.NewDocIDFromString(req.DocID) - if err != nil { - return nil, err + + if req.DocID != "" { + _, err := client.NewDocIDFromString(req.DocID) + if err != nil { + return nil, err + } } byPeer, err := libpeer.Decode(req.Creator) if err != nil { @@ -126,11 +129,11 @@ func (s *server) PushLog(ctx context.Context, req *pushLogRequest) (*pushLogRepl log.InfoContext(ctx, "Received pushlog", corelog.Any("PeerID", pid.String()), corelog.Any("Creator", byPeer.String()), - corelog.Any("DocID", docID.String())) + corelog.Any("DocID", req.DocID)) log.InfoContext(ctx, "Starting DAG sync", corelog.Any("PeerID", pid.String()), - corelog.Any("DocID", docID.String())) + corelog.Any("DocID", req.DocID)) err = syncDAG(ctx, s.peer.bserv, block) if err != nil { @@ -139,19 +142,19 @@ func (s *server) PushLog(ctx context.Context, req *pushLogRequest) (*pushLogRepl log.InfoContext(ctx, "DAG sync complete", corelog.Any("PeerID", pid.String()), - corelog.Any("DocID", docID.String())) + corelog.Any("DocID", req.DocID)) // Once processed, subscribe to the DocID topic on the pubsub network unless we already // subscribed to the collection. - if !s.hasPubSubTopicAndSubscribed(req.SchemaRoot) { - err = s.addPubSubTopic(docID.String(), true, nil) + if !s.hasPubSubTopicAndSubscribed(req.SchemaRoot) && req.DocID != "" { + _, err = s.addPubSubTopic(req.DocID, true, nil) if err != nil { return nil, err } } s.peer.bus.Publish(event.NewMessage(event.MergeName, event.Merge{ - DocID: docID.String(), + DocID: req.DocID, ByPeer: byPeer, FromPeer: pid, Cid: headCID, @@ -172,9 +175,9 @@ func (s *server) GetHeadLog( // addPubSubTopic subscribes to a topic on the pubsub network // A custom message handler can be provided to handle incoming messages. If not provided, // the default message handler will be used. -func (s *server) addPubSubTopic(topic string, subscribe bool, handler rpc.MessageHandler) error { +func (s *server) addPubSubTopic(topic string, subscribe bool, handler rpc.MessageHandler) (pubsubTopic, error) { if s.peer.ps == nil { - return nil + return pubsubTopic{}, nil } log.InfoContext(s.peer.ctx, "Adding pubsub topic", @@ -188,16 +191,16 @@ func (s *server) addPubSubTopic(topic string, subscribe bool, handler rpc.Messag // we need to close the existing topic and create a new one. if !t.subscribed && subscribe { if err := t.Close(); err != nil { - return err + return pubsubTopic{}, err } } else { - return nil + return t, nil } } t, err := rpc.NewTopic(s.peer.ctx, s.peer.ps, s.peer.host.ID(), topic, subscribe) if err != nil { - return err + return pubsubTopic{}, err } if handler == nil { @@ -206,15 +209,17 @@ func (s *server) addPubSubTopic(topic string, subscribe bool, handler rpc.Messag t.SetEventHandler(s.pubSubEventHandler) t.SetMessageHandler(handler) - s.topics[topic] = pubsubTopic{ + pst := pubsubTopic{ Topic: t, subscribed: subscribe, } - return nil + s.topics[topic] = pst + return pst, nil } func (s *server) AddPubSubTopic(topicName string, handler rpc.MessageHandler) error { - return s.addPubSubTopic(topicName, true, handler) + _, err := s.addPubSubTopic(topicName, true, handler) + return err } // hasPubSubTopicAndSubscribed checks if we are subscribed to a topic. @@ -274,13 +279,23 @@ func (s *server) publishLog(ctx context.Context, topic string, req *pushLogReque s.mu.Unlock() if !ok { subscribe := topic != req.SchemaRoot && !s.hasPubSubTopicAndSubscribed(req.SchemaRoot) - err := s.addPubSubTopic(topic, subscribe, nil) + _, err := s.addPubSubTopic(topic, subscribe, nil) if err != nil { return errors.Wrap(fmt.Sprintf("failed to created single use topic %s", topic), err) } return s.publishLog(ctx, topic, req) } + if topic == req.SchemaRoot && req.DocID == "" && !t.subscribed { + // If the push log request is scoped to the schema and not to a document, subscribe to the + // schema. + var err error + t, err = s.addPubSubTopic(topic, true, nil) + if err != nil { + return errors.Wrap(fmt.Sprintf("failed to created single use topic %s", topic), err) + } + } + log.InfoContext(ctx, "Publish log", corelog.String("PeerID", s.peer.PeerID().String()), corelog.String("Topic", topic)) @@ -356,7 +371,7 @@ func peerIDFromContext(ctx context.Context) (libpeer.ID, error) { func (s *server) updatePubSubTopics(evt event.P2PTopic) { for _, topic := range evt.ToAdd { - err := s.addPubSubTopic(topic, true, nil) + _, err := s.addPubSubTopic(topic, true, nil) if err != nil { log.ErrorE("Failed to add pubsub topic.", err) } diff --git a/playground/package-lock.json b/playground/package-lock.json index 0c226c3c46..42c3faa7aa 100644 --- a/playground/package-lock.json +++ b/playground/package-lock.json @@ -8,30 +8,30 @@ "name": "playground", "version": "0.0.0", "dependencies": { - "graphiql": "^3.7.1", + "graphiql": "^3.7.2", "graphql": "^16.9.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "swagger-ui-react": "^5.17.14" + "swagger-ui-react": "^5.18.2" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.12.2", - "@typescript-eslint/parser": "^8.12.2", - "@vitejs/plugin-react-swc": "^3.7.1", - "eslint": "^9.14.0", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "@vitejs/plugin-react-swc": "^3.7.2", + "eslint": "^9.16.0", "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.14", - "typescript": "^5.6.3", - "vite": "^5.4.10" + "eslint-plugin-react-refresh": "^0.4.15", + "typescript": "^5.7.2", + "vite": "^6.0.2" } }, "node_modules/@babel/runtime": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.4.tgz", - "integrity": "sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -41,9 +41,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.25.0.tgz", - "integrity": "sha512-BOehWE7MgQ8W8Qn0CQnMtg2tHPHPulcS/5AVpFvs2KCK1ET+0WqZqPvnpRpFN81gYoFopdIEJX9Sgjw3ZBccPg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", "license": "MIT", "dependencies": { "core-js-pure": "^3.30.2", @@ -54,9 +54,9 @@ } }, "node_modules/@braintree/sanitize-url": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.0.2.tgz", - "integrity": "sha512-NVf/1YycDMs6+FxS0Tb/W8MjJRDQdXF+tBfDtZ5UZeiRUkTmwKc4vmYCKZTyymfJk1gnMsauvZSX/HiV9jOABw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.0.4.tgz", + "integrity": "sha512-hPYRrKFoI+nuckPgDJfyYAkybFvheo4usS0Vw0HNAe+fmGBQA5Az37b/yStO284atBoqqdOUhKJ3d9Zw3PQkcQ==", "license": "MIT" }, "node_modules/@codemirror/language": { @@ -80,9 +80,9 @@ "peer": true }, "node_modules/@codemirror/view": { - "version": "6.33.0", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.33.0.tgz", - "integrity": "sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==", + "version": "6.35.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.35.0.tgz", + "integrity": "sha512-I0tYy63q5XkaWsJ8QRv5h6ves7kvtrBWjBcnf/bzohFJQc5c14a1AQRdE8QpPF9eMp5Mq2FMm59TCj1gDfE7kw==", "peer": true, "dependencies": { "@codemirror/state": "^6.4.0", @@ -94,6 +94,7 @@ "version": "0.8.8", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "license": "MIT", "optional": true, "dependencies": { "@emotion/memoize": "0.7.4" @@ -103,411 +104,408 @@ "version": "0.7.4", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", + "license": "MIT", "optional": true }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", + "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", + "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", + "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", + "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", + "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", + "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", + "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", + "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", + "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", + "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", + "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", + "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", + "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", + "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", + "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", + "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", + "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", + "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", + "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", + "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", + "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", + "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", + "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -517,15 +515,17 @@ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", @@ -540,6 +540,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -550,6 +551,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -558,18 +560,19 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "license": "MIT", "dependencies": { @@ -615,9 +618,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -628,15 +631,17 @@ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "levn": "^0.4.1" }, @@ -645,26 +650,29 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "license": "MIT", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.0.0" }, @@ -674,14 +682,16 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" }, "node_modules/@graphiql/react": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/@graphiql/react/-/react-0.26.2.tgz", - "integrity": "sha512-aO4GWf/kJmqrjO+PORT/NPxwGvPGlg+mwye1v8xAlf8Q9j7P0hVtVBawYaSLUCCfJ/QnH7JAP+0VRamyooZZCw==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@graphiql/react/-/react-0.27.0.tgz", + "integrity": "sha512-K9ZKWd+ewodbS/1kewedmITeeKLUQswMOXwIv8XFLPt3Ondodji0vr1XXXsttlyl+V2QG/9tYVV2RJ9Ch5LdrA==", + "license": "MIT", "dependencies": { "@graphiql/toolkit": "^0.11.0", "@headlessui/react": "^1.7.15", @@ -701,21 +711,22 @@ "set-value": "^4.1.0" }, "peerDependencies": { - "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "react": "^16.8.0 || ^17 || ^18", "react-dom": "^16.8.0 || ^17 || ^18" } }, "node_modules/@graphiql/toolkit": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.11.0.tgz", - "integrity": "sha512-VqqQrvkMwgbGhj7J5907yfuAy5B1OCgOTIPi7gtRneG1jYmnqvSxi8Yrmu0B8G8fZxkxKVsYi8dE8EtsOBrTGQ==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.11.1.tgz", + "integrity": "sha512-G02te70/oYYna5UhbH6TXwNxeQyWa+ChlPonUrKwC5Ot9ItraGJ9yUU4sS+YRaA+EvkzNoHG79XcW2k1QaAMiw==", + "license": "MIT", "dependencies": { "@n1ru4l/push-pull-async-iterable-iterator": "^3.1.0", "meros": "^1.1.4" }, "peerDependencies": { - "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "graphql-ws": ">= 4.5.0" }, "peerDependenciesMeta": { @@ -728,6 +739,7 @@ "version": "1.7.19", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.19.tgz", "integrity": "sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==", + "license": "MIT", "dependencies": { "@tanstack/react-virtual": "^3.0.0-beta.60", "client-only": "^0.0.1" @@ -745,6 +757,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -754,6 +767,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -767,6 +781,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -790,10 +805,11 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", - "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -803,9 +819,9 @@ } }, "node_modules/@lezer/common": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", - "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", "peer": true }, "node_modules/@lezer/highlight": { @@ -830,6 +846,7 @@ "version": "10.18.0", "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz", "integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==", + "license": "MIT", "dependencies": { "@motionone/easing": "^10.18.0", "@motionone/types": "^10.17.1", @@ -841,6 +858,7 @@ "version": "10.12.0", "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz", "integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==", + "license": "MIT", "dependencies": { "@motionone/animation": "^10.12.0", "@motionone/generators": "^10.12.0", @@ -854,6 +872,7 @@ "version": "10.18.0", "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz", "integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==", + "license": "MIT", "dependencies": { "@motionone/utils": "^10.18.0", "tslib": "^2.3.1" @@ -863,6 +882,7 @@ "version": "10.18.0", "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz", "integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==", + "license": "MIT", "dependencies": { "@motionone/types": "^10.17.1", "@motionone/utils": "^10.18.0", @@ -872,12 +892,14 @@ "node_modules/@motionone/types": { "version": "10.17.1", "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz", - "integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==" + "integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==", + "license": "MIT" }, "node_modules/@motionone/utils": { "version": "10.18.0", "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz", "integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==", + "license": "MIT", "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", @@ -888,6 +910,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@n1ru4l/push-pull-async-iterable-iterator/-/push-pull-async-iterable-iterator-3.2.0.tgz", "integrity": "sha512-3fkKj25kEjsfObL6IlKPAlHYPq/oYwUkkQ03zsTTiDjD7vg/RxjdiLeCydqtxHZP0JgsXL3D/X5oAkMGzuUp/Q==", + "license": "MIT", "engines": { "node": ">=12" } @@ -933,12 +956,14 @@ "node_modules/@radix-ui/primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz", - "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==" + "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==", + "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.0.0" }, @@ -961,6 +986,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz", "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-context": "1.1.0", @@ -982,10 +1008,26 @@ } } }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz", "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -997,9 +1039,10 @@ } }, "node_modules/@radix-ui/react-context": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", - "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1011,24 +1054,25 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz", - "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz", + "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.0", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-slot": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "react-remove-scroll": "2.6.0" }, "peerDependencies": { "@types/react": "*", @@ -1049,6 +1093,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1060,9 +1105,10 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz", - "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz", + "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", @@ -1086,15 +1132,16 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz", - "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz", + "integrity": "sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", - "@radix-ui/react-menu": "2.1.1", + "@radix-ui/react-menu": "2.1.2", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, @@ -1114,9 +1161,10 @@ } }, "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz", - "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1131,6 +1179,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz", "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-primitive": "2.0.0", @@ -1155,6 +1204,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, @@ -1169,28 +1219,29 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz", - "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz", + "integrity": "sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-collection": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", + "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", - "@radix-ui/react-focus-guards": "1.1.0", + "@radix-ui/react-dismissable-layer": "1.1.1", + "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-roving-focus": "1.1.0", "@radix-ui/react-slot": "1.1.0", "@radix-ui/react-use-callback-ref": "1.1.0", "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.7" + "react-remove-scroll": "2.6.0" }, "peerDependencies": { "@types/react": "*", @@ -1211,6 +1262,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz", "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==", + "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.0", @@ -1238,10 +1290,26 @@ } } }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz", - "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz", + "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-use-layout-effect": "1.1.0" @@ -1262,9 +1330,10 @@ } }, "node_modules/@radix-ui/react-presence": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz", - "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz", + "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" @@ -1288,6 +1357,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz", "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==", + "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.1.0" }, @@ -1310,6 +1380,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz", "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-collection": "1.1.0", @@ -1336,10 +1407,26 @@ } } }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz", + "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz", "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==", + "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.0" }, @@ -1354,18 +1441,19 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.2.tgz", - "integrity": "sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.4.tgz", + "integrity": "sha512-QpObUH/ZlpaO4YgHSaYzrLO2VuO+ZBFFgGzjMUPwtiYnAzzNNDPJeEGRrT7qNOrWm/Jr08M1vlp+vTHtnSQ0Uw==", + "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.0", "@radix-ui/react-compose-refs": "1.1.0", - "@radix-ui/react-context": "1.1.0", - "@radix-ui/react-dismissable-layer": "1.1.0", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.0", - "@radix-ui/react-portal": "1.1.1", - "@radix-ui/react-presence": "1.1.0", + "@radix-ui/react-portal": "1.1.2", + "@radix-ui/react-presence": "1.1.1", "@radix-ui/react-primitive": "2.0.0", "@radix-ui/react-slot": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", @@ -1390,6 +1478,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1404,6 +1493,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, @@ -1421,6 +1511,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, @@ -1438,6 +1529,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1452,6 +1544,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.0" }, @@ -1469,6 +1562,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, @@ -1486,6 +1580,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz", "integrity": "sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==", + "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.0.0" }, @@ -1507,224 +1602,276 @@ "node_modules/@radix-ui/rect": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", - "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", - "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", - "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", - "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", - "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", - "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", - "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", - "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", - "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", - "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", - "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", - "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", - "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", - "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", - "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", - "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", - "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, "node_modules/@swagger-api/apidom-ast": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.0.0-alpha.9.tgz", - "integrity": "sha512-SAOQrFSFwgDiI4QSIPDwAIJEb4Za+8bu45sNojgV3RMtCz+n4Agw66iqGsDib5YSI/Cg1h4AKFovT3iWdfGWfw==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.0.0-beta.3.tgz", + "integrity": "sha512-JOXGfadL3ucJH+MY9BDT7dJOwFy0jX3XaAY/CWR92EnliEYfaEzZvH08FGnyqyYHcfT8T0DLKna5CWUHaskZuw==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", + "@swagger-api/apidom-error": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1732,14 +1879,14 @@ } }, "node_modules/@swagger-api/apidom-core": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-1.0.0-alpha.9.tgz", - "integrity": "sha512-vGl8BWRf6ODl39fxElcIOjRE2QG5AJhn8tTNMqjjHB/2WppNBuxOVStYZeVJoWfK03OPK8v4Fp/TAcaP9+R7DQ==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-core/-/apidom-core-1.0.0-beta.3.tgz", + "integrity": "sha512-oRcv3PgwSAvfxvai0afGt/rC2Kk9Zs2ArLPZ6FnVCv/GSnMsuvIQJc5UH29P9eGFcLJIZpQtEHnU6W+u8u0zAA==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", + "@swagger-api/apidom-ast": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "minim": "~0.23.8", "ramda": "~0.30.0", @@ -1749,39 +1896,39 @@ } }, "node_modules/@swagger-api/apidom-error": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-1.0.0-alpha.9.tgz", - "integrity": "sha512-FU/2sFSgsICB9HYFELJ79caRpXXzlAV41QTHsAM46WfRehbzZUQpOBQm4jRi3qJGSa/Jk+mQ7Vt8HLRFMpJFfg==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-error/-/apidom-error-1.0.0-beta.3.tgz", + "integrity": "sha512-cW1tzehphuxA0uM+1m4/0G1d/WjDQyF+RL9D9t1mfhuVxr8AorgYUgY+bjg0pkLfiSTwjrDiuTbYM+jZwrHx8w==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7" } }, "node_modules/@swagger-api/apidom-json-pointer": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.0.0-alpha.9.tgz", - "integrity": "sha512-/W8Ktbgbs29zdhed6KHTFk0qmuIRbvEFi8wu2MHGQ5UT4i99Bdu2OyUiayhnpejWztfQxDgL08pjrQPEwgY8Yg==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-1.0.0-beta.3.tgz", + "integrity": "sha512-r6Gvbj2XDcK1wIULoclHcGYPAVXeUkj5ECRslB/Zle/fOU0Jb8s4mmFARyQE/DT+fQggXn8nUJBda3NWPK4GcA==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-ns-api-design-systems": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-1.0.0-alpha.9.tgz", - "integrity": "sha512-aduC2vbwGgn6ia9IkKpqBYBaKyIDGM/80M3oU3DFgaYIIwynzuwVpN1TkBOLIFy3mAzkWoYKUS0jdZJhMy/6Ug==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-1.0.0-beta.3.tgz", + "integrity": "sha512-x+NiLR0xZ0VB8AMJr7ii+6A27AP2CGjLyPQr6JutnifXG+vpkjbgXCPyz2qlmrvuLIkBJIE2lBuyX3+qQXmgCw==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1789,15 +1936,15 @@ } }, "node_modules/@swagger-api/apidom-ns-asyncapi-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-hZjxXJgMt517ADnAauWJh01k7WNRwkbWT5p6b7AXF2H3tl549A2hhLnIg3BBSE3GwB3Nv25GyrI3aA/1dFVC8A==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-1.0.0-beta.3.tgz", + "integrity": "sha512-9E4/kTf/OzV3vgRjZOB+6TRqQX2ljirD+UBQ8QPSJKBUTtq8+F7U9a8Z9AGYrKCQUMgbge5JMYCqHmOmrJKVUA==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-json-schema-draft-7": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-json-schema-draft-7": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1805,14 +1952,14 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-4": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.0.0-alpha.9.tgz", - "integrity": "sha512-OfX4UBb08C0xD5+F80dQAM2yt5lXxcURWkVEeCwxz7i23BB3nNEbnZXNV91Qo9eaJflPh8dO9iiHQxvfw5IgSg==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-1.0.0-beta.3.tgz", + "integrity": "sha512-Sc/ywYCHFIMwhZX0Yo+OTmHUvszv3JE3xsvpd18nu7rH+jNyA10oUdTMgnRsTNMnL7siVO+32OKQkdLOSKsEHA==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^1.0.0-alpha.9", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", + "@swagger-api/apidom-ast": "^1.0.0-beta.3", + "@swagger-api/apidom-core": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1820,16 +1967,16 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-6": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.0.0-alpha.9.tgz", - "integrity": "sha512-qzUVRSSrnlYGMhK6w57o/RboNvy1FO0iFgEnTk56dD4wN49JRNuFqKI18IgXc1W2r9tTTG70nG1khe4cPE8TNg==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-1.0.0-beta.3.tgz", + "integrity": "sha512-UuGfaJfWzsTCTEyxyKtM86SNdS4EsWB/+j8JWw88h7nFK59YNDmnuXk9PpFyuccpIAHnDq7UJypD3lRvNkJdhQ==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1837,16 +1984,16 @@ } }, "node_modules/@swagger-api/apidom-ns-json-schema-draft-7": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.0.0-alpha.9.tgz", - "integrity": "sha512-Zml8Z8VCckdFjvTogaec1dabd85hg1+xZDseWcCuD0tYkaTY/sZ8zzI0dz6/4HsKCb58qjiWSa0w60N8Syr6WQ==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-1.0.0-beta.3.tgz", + "integrity": "sha512-7Snaf8/qZ3Q9xnjEXo2cJ8L4pvDbHA+k/j7rqbY4o3h5EeMy93ClVUwoeJ2y/JWax/V1DWTyYMhq+9dXlcIUYQ==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-json-schema-draft-6": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-json-schema-draft-6": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1854,16 +2001,16 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-WUZxt7Gs7P4EQsGtoD6cKAjf0uDJhkUxsIW9Bb4EAgO6tdp7LlXhbJ0fJ2QycCLY717SfJbvGLfhuSfTYo4Iow==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-1.0.0-beta.3.tgz", + "integrity": "sha512-eBNUkQdIDE2fWUXdIeRpN9OMxwfxU2WJFMRHst204Doanh8iJVp3Mz/+z9agHJ6Pkqth2XTXA0EDd1QiI37t+g==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1871,15 +2018,15 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-3-0": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-1.0.0-alpha.9.tgz", - "integrity": "sha512-7ra5uoZGrfCn1LabfJLueChPcYXyg24//LCYBtjTstyueqd5Vp7JCPeP5NnJSAaqVAP47r8ygceBPoxNp9k1EQ==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-1.0.0-beta.3.tgz", + "integrity": "sha512-wKMdk5nplkT2PA1sRFZ2WOLmb7xi9++T6UnCeivmV+sy5NtUPpwkJLUWWIlZdZLyiGKmhZQ1gVvhsbyWRoAVPw==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-json-schema-draft-4": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1887,16 +2034,16 @@ } }, "node_modules/@swagger-api/apidom-ns-openapi-3-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-nQOwNQgf0C8EVjf2loAAl4ifRuVOdcqycvXUdcTpsUfHN3fbndR8IKpb26mQNmnACmqgmX+LkbMdW9b+K6089g==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-1.0.0-beta.3.tgz", + "integrity": "sha512-XltfOZNTjrBvrWx1hPU6pHn7lHKKY9jXmiQzojX/jhMjZ6Kp6TLGjMMU3SmEUPU6sTaXKUeO5UUTxe2v6VmqMA==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^1.0.0-alpha.9", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-json-pointer": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-alpha.9", + "@swagger-api/apidom-ast": "^1.0.0-beta.3", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-json-pointer": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1904,15 +2051,15 @@ } }, "node_modules/@swagger-api/apidom-ns-workflows-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-workflows-1/-/apidom-ns-workflows-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-yKo0p8OkQmDib93Kt1yqWmI7JsD6D9qUHxr/SCuAmNNWny1hxm7cZGoKJwJlGd0uAg84j4vmzWOlG3AsJbnT8g==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ns-workflows-1/-/apidom-ns-workflows-1-1.0.0-beta.3.tgz", + "integrity": "sha512-+7i8CZAC+TypSYuxTtwXH2qIyQC1ATn8r+1pW4NWCs4F2Yr4K2gGG4ZmOE6ckNa+Q53yyx+Spt7xhLfZDJZp/w==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", @@ -1920,272 +2067,272 @@ } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-json": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-1.0.0-alpha.9.tgz", - "integrity": "sha512-xfVMR4HrTzXU0HB4TtxwkNbUIa/cQrPa0BWutJZ0fMYMAtUox2s8GsFYnJfZP52XfpSHFM1VPclivorZqET14g==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-1.0.0-beta.3.tgz", + "integrity": "sha512-IpnxjLDVdRaY+ewNW8zbiMzYu5eKifpioFPGDlHc2MoTW6zqo5UKViZKL4MbsncySWBj7+URvTIFYjip3TvkKg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-api-design-systems": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-api-design-systems": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-api-design-systems-yaml": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-1.0.0-alpha.9.tgz", - "integrity": "sha512-lJZkrhZ8qRTtc5fSLKefCv8j7Xzo8UBfMjpqTJhmETAtU8YfVV2i2znjgxJpm0QwV6FVQqGfK1+ASZQWPLiVcA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-1.0.0-beta.3.tgz", + "integrity": "sha512-Pvj+4OMIzKMx77Ulbp/CdWGAQhor88q5BJlY3cuSNd2Oth+mfe6r7NUXWVSpG6H9+9Y6YJdnGOzQ1PHWJPOlqA==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-api-design-systems": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-api-design-systems": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-json-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-65nmKdPzw4C1bmtYn+3zoxXCI6Gnobr0StI9XE0YWiK+lpso7RH3Cgyl1yPZ0DBRVGzP+Fn9FVzmDNulEfR95w==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-1.0.0-beta.3.tgz", + "integrity": "sha512-Z8xIy3pirwAapLgZ18BqRVua5rh0NsvQNpx+5Bi5yJD+SD6Syk5OqsgFkqN7T/LmyqpivQiYRgItUBaHXuDnxg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-RLI4FpVB3vB6mIuT77yrsv5V2LMZ80dW9XpV+Fmbd4Jkdj+ysAFwT38cI4AsUMOxixpTDIXY1oWD7AjvylHhQQ==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-1.0.0-beta.3.tgz", + "integrity": "sha512-Xl9MU1+24ZTDuGzy/mKVPlnMSvgA/lS+AoqwMzxLMuiIsTmnQX3gEdiM+pXmK7rg1KV/k0aLwDLKt3e00CPiXQ==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-json": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-1.0.0-alpha.9.tgz", - "integrity": "sha512-aOewp8/3zobf/O+5Jx8y7+bX3BPRfRlHIv15qp4YVTsLs6gLISWSzTO9JpWe9cR+AfhpsAalFq4t1LwIkmLk4A==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-1.0.0-beta.3.tgz", + "integrity": "sha512-28zQdF8oeaUmNxZNU0De4JUY9jvxiaN+QCJ1GZN9aQ6NQ/eOAuGg+HRuL8+RrSe4STacdi1FCX46jHcMGQeqfg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^1.0.0-alpha.9", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", + "@swagger-api/apidom-ast": "^1.0.0-beta.3", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", - "tree-sitter": "=0.20.4", - "tree-sitter-json": "=0.20.2", - "web-tree-sitter": "=0.20.3" + "tree-sitter": "=0.21.1", + "tree-sitter-json": "=0.24.8", + "web-tree-sitter": "=0.24.3" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-zgtsAfkplCFusX2P/saqdn10J8P3kQizCXxHLvxd2j0EhMJk2wfu4HYN5Pej/7/qf/OR1QZxqtacwebd4RfpXA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-1.0.0-beta.3.tgz", + "integrity": "sha512-ufiQMl89sTGf09qlh/QvFLEUs9FH9ZZV4mjz1xIB127rnNbWg/sSGr0WIcJGKoLrioI9orb+7aqIhmSDw/plmw==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-2": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-2": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-0": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-1.0.0-alpha.9.tgz", - "integrity": "sha512-iPuHf0cAZSUhSv8mB0FnVgatTc26cVYohgqz2cvjoGofdqoh5KKIfxOkWlIhm+qGuBp71CfZUrPYPRsd0dHgeg==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-1.0.0-beta.3.tgz", + "integrity": "sha512-yINlDTIZCywuKRsBeJJDmQLV4+r9FaWDezb4omw6xFQnQZQV1tHgIb549OsV6lT70TabLj+HoMYNLQ9/Bm59Yw==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-3-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-jwkfO7tzZyyrAgok+O9fKFOv1q/5njMb9DBc3D/ZF3ZLTcnEw8uj4V2HkjKxUweH5k8ip/gc8ueKmO/i7p2fng==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-1.0.0-beta.3.tgz", + "integrity": "sha512-kBZsyNHtp6w41g9N5c+PF4FqoE8vosxgYJEfhQeQs4qXK7T7d8sfjXwcnWRjqlOM4X8dt5R359h58AfwyEF20w==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-2/-/apidom-parser-adapter-openapi-yaml-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-jEIDpjbjwFKXQXS/RHJeA4tthsguLoz+nJPYS3AOLfuSiby5QXsKTxgqHXxG/YJqF1xJbZL+5KcF8UyiDePumw==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-2/-/apidom-parser-adapter-openapi-yaml-2-1.0.0-beta.3.tgz", + "integrity": "sha512-K/FRLCuB0UD9Nq/CNqfjkSVfQfzcpA7lJCg6QueZKd0dQJ54dyHFU9AroshutXHTmEjBleoL7V1K3PNh10HiYQ==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-2": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-2": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-1.0.0-alpha.9.tgz", - "integrity": "sha512-ieJL8dfIF8fmP3uJRNh/duJa3cCIIv6MzUe6o4uPT/oTDroy4qIATvnq9Dq/gtAv6rcPRpA9VhyghJ1DmjKsZQ==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-1.0.0-beta.3.tgz", + "integrity": "sha512-EUdpzJnqZqCu2keEyOxlCED/u0oaA05c6dO48XzbdyENONY/etoN5wrEoqxqxOz+1cC+FZWj/cnmsXdFfbJlEg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-EatIH7PZQSNDsRn9ompc62MYzboY7wAkjfYz+2FzBaSA8Vl5/+740qGQj22tu/xhwW4K72aV2NNL1m47QVF7hA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-1.0.0-beta.3.tgz", + "integrity": "sha512-2Q9vmrgTQ4cA5WALGyTLp8tF984R9C7QmDOjGf/ngrTIQLyyrQZ0ZDaXL7RHTmT6K9Lg6axMpKquBNiO+Aff6g==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-workflows-json-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-json-1/-/apidom-parser-adapter-workflows-json-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-LylC2cQdAmvR7bXqwMwBt6FHTMVGinwIdI8pjl4EbPT9hCVm1rdED53caTYM4gCm+CJGRw20r4gb9vn3+N6RrA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-json-1/-/apidom-parser-adapter-workflows-json-1-1.0.0-beta.3.tgz", + "integrity": "sha512-OsKz09YcfQfTbiNZueTLHBrn7umnMjtuN0ZzuNiBs5txaLS196grpzyTiG+4UJ1zIWvjvZmLZEbQqbKZ9qTw8A==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-workflows-1": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-workflows-1": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-workflows-yaml-1": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-yaml-1/-/apidom-parser-adapter-workflows-yaml-1-1.0.0-alpha.9.tgz", - "integrity": "sha512-TlA4+1ca33D7fWxO5jKBytSCv86IGI4Lze4JfrawWUXZ5efhi4LiNmW5TrGlZUyvL7yJtZcA4tn3betlj6jVwA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-workflows-yaml-1/-/apidom-parser-adapter-workflows-yaml-1-1.0.0-beta.3.tgz", + "integrity": "sha512-IifK3T6UtqBkIoHOQe6QRGpFU9LFqmJ5T1JzbWnVX+gazoVE+N9ZkFWQfb9pKCaCfAwPVp+vai6bQ2eUsGh4CA==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-ns-workflows-1": "^1.0.0-alpha.9", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-ns-workflows-1": "^1.0.0-beta.3", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" } }, "node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.0.0-alpha.9.tgz", - "integrity": "sha512-jSIHEB7lbh+MP3BhYIXFkeivDR01kugXN70e5FskW7oet2TIARsVEPheWKQFSP1U8bUZA4bsp9h9gOQ9xEeErw==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-1.0.0-beta.3.tgz", + "integrity": "sha512-sSGxnMTNNTqhJBeUOge4Q/5l/7170maoxyrK6J57kRxqkchSAqam73VIBpKa8c/sJ7zhdZI7CZ9aTJe/q7vc7w==", "license": "Apache-2.0", "optional": true, "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-ast": "^1.0.0-alpha.9", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", - "@swagger-api/apidom-error": "^1.0.0-alpha.9", + "@swagger-api/apidom-ast": "^1.0.0-beta.3", + "@swagger-api/apidom-core": "^1.0.0-beta.3", + "@swagger-api/apidom-error": "^1.0.0-beta.3", + "@tree-sitter-grammars/tree-sitter-yaml": "=0.6.1", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0", - "tree-sitter": "=0.20.4", - "tree-sitter-yaml": "=0.5.0", - "web-tree-sitter": "=0.20.3" + "tree-sitter": "=0.21.1", + "web-tree-sitter": "=0.24.3" } }, "node_modules/@swagger-api/apidom-reference": { - "version": "1.0.0-alpha.9", - "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.0.0-alpha.9.tgz", - "integrity": "sha512-KQ6wB5KplqdSsjxdA8BaQulj5zlF5VBCd5KP3RN/9vvixgsD/gyrVY59nisdzmPTqiL6yjhk612eQ96MgG8KiA==", + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.0.0-beta.3.tgz", + "integrity": "sha512-MkSW/uKA+iCUeQ5HqICGxXPZI1y5vbXnOZLT+22+ZvaO3+5j7tD2aS9mAF+140VaaE5AkpZE28XC9TaYyjEwDg==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-alpha.9", + "@swagger-api/apidom-core": "^1.0.0-beta.3", "@types/ramda": "~0.30.0", - "axios": "^1.4.0", + "axios": "^1.7.4", "minimatch": "^7.4.3", "process": "^0.11.10", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" }, "optionalDependencies": { - "@swagger-api/apidom-error": "^1.0.0-alpha.1", - "@swagger-api/apidom-json-pointer": "^1.0.0-alpha.1", - "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-ns-openapi-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-alpha.1", - "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-ns-workflows-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-json": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-json-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-yaml-2": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-workflows-json-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-workflows-yaml-1": "^1.0.0-alpha.1", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-alpha.1" + "@swagger-api/apidom-error": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-json-pointer": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-asyncapi-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-openapi-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-openapi-3-0": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-openapi-3-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-workflows-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-api-design-systems-json": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-asyncapi-json-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-json": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-json-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-json-3-0": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-json-3-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-yaml-2": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-workflows-json-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-workflows-yaml-1": "^1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.3 <1.0.0-rc.0" } }, "node_modules/@swagger-api/apidom-reference/node_modules/minimatch": { @@ -2204,14 +2351,15 @@ } }, "node_modules/@swc/core": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz", - "integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.9.3.tgz", + "integrity": "sha512-oRj0AFePUhtatX+BscVhnzaAmWjpfAeySpM1TCbxA1rtBDeH/JDhi5yYzAKneDYtVtBvA7ApfeuzhMC9ye4xSg==", "dev": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.12" + "@swc/types": "^0.1.17" }, "engines": { "node": ">=10" @@ -2221,16 +2369,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.7.26", - "@swc/core-darwin-x64": "1.7.26", - "@swc/core-linux-arm-gnueabihf": "1.7.26", - "@swc/core-linux-arm64-gnu": "1.7.26", - "@swc/core-linux-arm64-musl": "1.7.26", - "@swc/core-linux-x64-gnu": "1.7.26", - "@swc/core-linux-x64-musl": "1.7.26", - "@swc/core-win32-arm64-msvc": "1.7.26", - "@swc/core-win32-ia32-msvc": "1.7.26", - "@swc/core-win32-x64-msvc": "1.7.26" + "@swc/core-darwin-arm64": "1.9.3", + "@swc/core-darwin-x64": "1.9.3", + "@swc/core-linux-arm-gnueabihf": "1.9.3", + "@swc/core-linux-arm64-gnu": "1.9.3", + "@swc/core-linux-arm64-musl": "1.9.3", + "@swc/core-linux-x64-gnu": "1.9.3", + "@swc/core-linux-x64-musl": "1.9.3", + "@swc/core-win32-arm64-msvc": "1.9.3", + "@swc/core-win32-ia32-msvc": "1.9.3", + "@swc/core-win32-x64-msvc": "1.9.3" }, "peerDependencies": { "@swc/helpers": "*" @@ -2242,13 +2390,14 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz", - "integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.9.3.tgz", + "integrity": "sha512-hGfl/KTic/QY4tB9DkTbNuxy5cV4IeejpPD4zo+Lzt4iLlDWIeANL4Fkg67FiVceNJboqg48CUX+APhDHO5G1w==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" @@ -2258,13 +2407,14 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz", - "integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.9.3.tgz", + "integrity": "sha512-IaRq05ZLdtgF5h9CzlcgaNHyg4VXuiStnOFpfNEMuI5fm5afP2S0FHq8WdakUz5WppsbddTdplL+vpeApt/WCQ==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "darwin" @@ -2274,13 +2424,14 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz", - "integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.9.3.tgz", + "integrity": "sha512-Pbwe7xYprj/nEnZrNBvZfjnTxlBIcfApAGdz2EROhjpPj+FBqBa3wOogqbsuGGBdCphf8S+KPprL1z+oDWkmSQ==", "cpu": [ "arm" ], "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" @@ -2290,13 +2441,14 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz", - "integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.9.3.tgz", + "integrity": "sha512-AQ5JZiwNGVV/2K2TVulg0mw/3LYfqpjZO6jDPtR2evNbk9Yt57YsVzS+3vHSlUBQDRV9/jqMuZYVU3P13xrk+g==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2306,13 +2458,14 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz", - "integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.9.3.tgz", + "integrity": "sha512-tzVH480RY6RbMl/QRgh5HK3zn1ZTFsThuxDGo6Iuk1MdwIbdFYUY034heWUTI4u3Db97ArKh0hNL0xhO3+PZdg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2322,13 +2475,14 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz", - "integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.9.3.tgz", + "integrity": "sha512-ivXXBRDXDc9k4cdv10R21ccBmGebVOwKXT/UdH1PhxUn9m/h8erAWjz5pcELwjiMf27WokqPgaWVfaclDbgE+w==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2338,13 +2492,14 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz", - "integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.9.3.tgz", + "integrity": "sha512-ILsGMgfnOz1HwdDz+ZgEuomIwkP1PHT6maigZxaCIuC6OPEhKE8uYna22uU63XvYcLQvZYDzpR3ms47WQPuNEg==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "linux" @@ -2354,13 +2509,14 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz", - "integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.9.3.tgz", + "integrity": "sha512-e+XmltDVIHieUnNJHtspn6B+PCcFOMYXNJB1GqoCcyinkEIQNwC8KtWgMqUucUbEWJkPc35NHy9k8aCXRmw9Kg==", "cpu": [ "arm64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2370,13 +2526,14 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz", - "integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.9.3.tgz", + "integrity": "sha512-rqpzNfpAooSL4UfQnHhkW8aL+oyjqJniDP0qwZfGnjDoJSbtPysHg2LpcOBEdSnEH+uIZq6J96qf0ZFD8AGfXA==", "cpu": [ "ia32" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2386,13 +2543,14 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.7.26", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz", - "integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.9.3.tgz", + "integrity": "sha512-3YJJLQ5suIEHEKc1GHtqVq475guiyqisKSoUnoaRtxkDaW5g1yvPt9IoSLOe2mRs7+FFhGGU693RsBUSwOXSdQ==", "cpu": [ "x64" ], "dev": true, + "license": "Apache-2.0 AND MIT", "optional": true, "os": [ "win32" @@ -2405,23 +2563,26 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@swc/types": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz", - "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==", + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz", + "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" } }, "node_modules/@tanstack/react-virtual": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.4.tgz", - "integrity": "sha512-Y2y1QJN3e5gNTG4wlZcoW2IAFrVCuho80oyeODKKFVSbAhJAXmkDNH3ZztM6EQij5ueqpqgz5FlsgKP9TGjImA==", + "version": "3.10.9", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.10.9.tgz", + "integrity": "sha512-OXO2uBjFqA4Ibr2O3y0YMnkrRWGVNqcvHQXmGvMu6IK8chZl3PrDxFXdGZ2iZkSrKh3/qUYoFqYe+Rx23RoU0g==", + "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.10.4" + "@tanstack/virtual-core": "3.10.9" }, "funding": { "type": "github", @@ -2433,26 +2594,48 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.4.tgz", - "integrity": "sha512-yHyli4RHVsI+eJ0RjmOsjA9RpHp3/Zah9t+iRjmFa72dq00TeG/NwuLYuCV6CB4RkWD4i5RD421j1eb6BdKgvQ==", + "version": "3.10.9", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.9.tgz", + "integrity": "sha512-kBknKOKzmeR7lN+vSadaKWXaLS0SZZG+oqpQ/k80Q6g9REn6zRHS/ZYdrIzHnpHgy/eWs00SujveUN/GJT2qTw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tree-sitter-grammars/tree-sitter-yaml": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@tree-sitter-grammars/tree-sitter-yaml/-/tree-sitter-yaml-0.6.1.tgz", + "integrity": "sha512-FqgUNdtMuPpk5D/9YQvCxTK4tzlUEVq/yNewdcxJbMv0KVt/yDfuuUn5ZvxphftKyOco+1e/6/oNHCKVQ5A83Q==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.8.0" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree_sitter": { + "optional": true + } + } + }, "node_modules/@types/codemirror": { "version": "5.60.15", "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.15.tgz", "integrity": "sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==", + "license": "MIT", "dependencies": { "@types/tern": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, "node_modules/@types/hast": { @@ -2468,19 +2651,20 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", "devOptional": true, "license": "MIT" }, "node_modules/@types/ramda": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.30.1.tgz", - "integrity": "sha512-aoyF/ADPL6N+/NXXfhPWF+Qj6w1Cql59m9wX0Gi15uyF+bpzXeLd63HPdiTDE2bmLXfNcVufsDPKmbfOrOzTBA==", + "version": "0.30.2", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.30.2.tgz", + "integrity": "sha512-PyzHvjCalm2BRYjAU6nIB3TprYwMNOUY/7P/N8bSzp9W/yM2YrtGtAnnVtaCNSeOZ8DzKyFDvaqQs7LnWwwmBA==", "license": "MIT", "dependencies": { "types-ramda": "^0.30.1" @@ -2491,6 +2675,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "devOptional": true, + "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2501,6 +2686,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "devOptional": true, + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -2519,6 +2705,7 @@ "version": "0.23.9", "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "license": "MIT", "dependencies": { "@types/estree": "*" } @@ -2536,16 +2723,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", - "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz", + "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/type-utils": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/type-utils": "8.16.0", + "@typescript-eslint/utils": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2568,63 +2756,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", - "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", + "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4" }, "engines": { @@ -2643,90 +2785,15 @@ } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz", - "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", + "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0" + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2737,13 +2804,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", - "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz", + "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/utils": "8.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2754,46 +2822,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -2801,27 +2831,10 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/types": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz", - "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", + "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", "dev": true, "license": "MIT", "engines": { @@ -2833,14 +2846,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz", - "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", + "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.11.0", - "@typescript-eslint/visitor-keys": "8.11.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2862,15 +2875,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", - "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", + "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2" + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2881,59 +2895,6 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" }, "peerDependenciesMeta": { "typescript": { @@ -2941,14 +2902,15 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", + "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.16.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2958,34 +2920,29 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz", - "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.11.0", - "eslint-visitor-keys": "^3.4.3" - }, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, "node_modules/@vitejs/plugin-react-swc": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.1.tgz", - "integrity": "sha512-vgWOY0i1EROUK0Ctg1hwhtC3SdcDjZcdit4Ups4aPkDcB1jYhmo+RMYWY87cmXMhvtD5uf8lV89j2w16vkdSVg==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.2.tgz", + "integrity": "sha512-y0byko2b2tSVVf5Gpng1eEhX1OvPC7x8yns1Fx8jDzlJp4LS6CMkCPfLw47cjyoMrshQDoQw4qcgjsU9VvlCew==", "dev": true, "dependencies": { "@swc/core": "^1.7.26" }, "peerDependencies": { - "vite": "^4 || ^5" + "vite": "^4 || ^5 || ^6" } }, "node_modules/acorn": { @@ -2993,6 +2950,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3059,6 +3017,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz", "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3082,9 +3041,9 @@ } }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -3118,18 +3077,6 @@ ], "license": "MIT" }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -3152,31 +3099,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3234,13 +3156,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC", - "optional": true - }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", @@ -3250,25 +3165,29 @@ "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/codemirror": { - "version": "5.65.17", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.17.tgz", - "integrity": "sha512-1zOsUx3lzAOu/gnMAZkQ9kpIHcPYOc9y1Fbm2UVk5UBPkdq380nhkelG0qUwm1f7wPvTbndu9ZYlug35EwAZRQ==" + "version": "5.65.18", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.18.tgz", + "integrity": "sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==", + "license": "MIT" }, "node_modules/codemirror-graphql": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-2.1.1.tgz", "integrity": "sha512-qVNd+H4OqkeBLDztB5bYllAmToxmZASOoELgbf+csNcoovIHKqSB/eppkzWI5jdQGd8bvLK1lTePfqXsCBFryw==", + "license": "MIT", "dependencies": { "@types/codemirror": "^0.0.90", "graphql-language-service": "5.3.0" @@ -3283,6 +3202,7 @@ "version": "0.0.90", "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.90.tgz", "integrity": "sha512-8Z9+tSg27NPRGubbUPUCrt5DDG/OWzLph5BvcDykwR5D7RyZh5mhHG0uS1ePKV1YFCA+/cwc4Ey2AJAEFfV3IA==", + "license": "MIT", "dependencies": { "@types/tern": "*" } @@ -3337,9 +3257,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3355,9 +3275,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", - "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.39.0.tgz", + "integrity": "sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -3366,9 +3286,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3396,16 +3316,17 @@ "node_modules/debounce-promise": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/debounce-promise/-/debounce-promise-3.1.2.tgz", - "integrity": "sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==" + "integrity": "sha512-rZHcgBkbYavBeD9ej6sP56XfG53d51CD4dnaw989YX/nZ/ZJfgRx/9ePKmTNiUiyQvh4mtrMoS3OAWW+yoYtpg==", + "license": "MIT" }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3416,22 +3337,6 @@ } } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -3466,25 +3371,16 @@ "node": ">=0.4.0" } }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" }, "node_modules/dompurify": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.4.tgz", - "integrity": "sha512-2gnshi6OshmuKil8rMZuQCGiUF3cUxHY3NGDzUAdUx/NPEe5DVnO8BDoAQouvgwnx0R/+a6jUn36Z0FSdq8vww==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", "license": "(MPL-2.0 OR Apache-2.0)" }, "node_modules/drange": { @@ -3496,20 +3392,11 @@ "node": ">=4" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -3518,42 +3405,42 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", + "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.24.0", + "@esbuild/android-arm": "0.24.0", + "@esbuild/android-arm64": "0.24.0", + "@esbuild/android-x64": "0.24.0", + "@esbuild/darwin-arm64": "0.24.0", + "@esbuild/darwin-x64": "0.24.0", + "@esbuild/freebsd-arm64": "0.24.0", + "@esbuild/freebsd-x64": "0.24.0", + "@esbuild/linux-arm": "0.24.0", + "@esbuild/linux-arm64": "0.24.0", + "@esbuild/linux-ia32": "0.24.0", + "@esbuild/linux-loong64": "0.24.0", + "@esbuild/linux-mips64el": "0.24.0", + "@esbuild/linux-ppc64": "0.24.0", + "@esbuild/linux-riscv64": "0.24.0", + "@esbuild/linux-s390x": "0.24.0", + "@esbuild/linux-x64": "0.24.0", + "@esbuild/netbsd-x64": "0.24.0", + "@esbuild/openbsd-arm64": "0.24.0", + "@esbuild/openbsd-x64": "0.24.0", + "@esbuild/sunos-x64": "0.24.0", + "@esbuild/win32-arm64": "0.24.0", + "@esbuild/win32-ia32": "0.24.0", + "@esbuild/win32-x64": "0.24.0" } }, "node_modules/escape-string-regexp": { @@ -3570,26 +3457,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.16.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.5", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -3608,8 +3495,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -3634,6 +3520,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3642,12 +3529,12 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz", - "integrity": "sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==", + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.15.tgz", + "integrity": "sha512-poU5qfmwLS5WO69drZnB9J1vXv+NQkE0p+oIY4B85Z9IuvpaIdHa+9IE/sFrN79QW49QcHQIP6c7NHpDMQ9TvA==", "dev": true, "peerDependencies": { - "eslint": ">=7" + "eslint": ">=8.40" } }, "node_modules/eslint-scope": { @@ -3655,6 +3542,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3679,12 +3567,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3701,6 +3583,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3726,6 +3609,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", @@ -3743,6 +3627,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3768,6 +3653,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3795,16 +3681,6 @@ "node": ">=0.10.0" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3943,16 +3819,16 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", @@ -3970,9 +3846,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -3995,6 +3871,7 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz", "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==", + "license": "MIT", "dependencies": { "@motionone/dom": "10.12.0", "framesync": "6.0.1", @@ -4015,17 +3892,11 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz", "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==", + "license": "MIT", "dependencies": { "tslib": "^2.1.0" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT", - "optional": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4045,6 +3916,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4053,6 +3925,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz", "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==", + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -4060,13 +3933,6 @@ "node": ">=6.0" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT", - "optional": true - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -4101,14 +3967,15 @@ "license": "MIT" }, "node_modules/graphiql": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-3.7.1.tgz", - "integrity": "sha512-kmummedOrFYs0BI5evrVY0AerOYlaMt/Sc/e+Sta1x8X6vEMYWNeUUz/kKF2NQT5BcsR3FnNdFt1Gk2QMgueGQ==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-3.7.2.tgz", + "integrity": "sha512-DL+KrX+aQdyzl+KwcqjlmdYdjyKegm7FcZJKkIQ1e56xn6Eoe8lw5F4t65gFex/45fHzv8e8CpaIcljxfJhO7A==", + "license": "MIT", "dependencies": { - "@graphiql/react": "^0.26.2" + "@graphiql/react": "^0.27.0" }, "peerDependencies": { - "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "react": "^16.8.0 || ^17 || ^18", "react-dom": "^16.8.0 || ^17 || ^18" } @@ -4126,6 +3993,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-5.3.0.tgz", "integrity": "sha512-gCQIIy7lM9CB1KPLEb+DNZLczA9zuTLEOJE2hEQZTFYInogdmMDRa6RAkvM4LL0LcgcS+3uPs6KtHlcjCqRbUg==", + "license": "MIT", "dependencies": { "debounce-promise": "^3.1.2", "nullthrows": "^1.0.0", @@ -4178,7 +4046,8 @@ "node_modules/hey-listen": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", - "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==" + "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==", + "license": "MIT" }, "node_modules/highlight.js": { "version": "10.7.3", @@ -4189,6 +4058,12 @@ "node": "*" } }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -4261,13 +4136,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC", - "optional": true - }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -4358,6 +4226,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -4369,6 +4238,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4384,6 +4254,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4461,6 +4332,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" } @@ -4530,6 +4402,7 @@ "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -4545,7 +4418,8 @@ "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==" + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", @@ -4561,6 +4435,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz", "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==", + "license": "MIT", "engines": { "node": ">=13" }, @@ -4608,19 +4483,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minim": { "version": "0.23.8", "resolved": "https://registry.npmjs.org/minim/-/minim-0.23.8.tgz", @@ -4649,37 +4511,13 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT", - "optional": true - }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, - "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -4691,6 +4529,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4698,13 +4537,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT", - "optional": true - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4721,25 +4553,22 @@ "node": ">= 10" } }, - "node_modules/node-abi": { - "version": "3.67.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", - "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==", - "license": "MIT", - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", "license": "MIT" }, + "node_modules/node-addon-api": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.2.2.tgz", + "integrity": "sha512-9emqXAKhVoNrQ792nLI/wpzPpJ/bj/YXxW0CvAau1+RdGBcCRF1Dmz7719zgVsQNrzHl9Tzn3ImZ4qWFarWL0A==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -4776,10 +4605,23 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", - "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" }, "node_modules/object-assign": { "version": "4.1.1", @@ -4790,16 +4632,6 @@ "node": ">=0.10.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/openapi-path-templating": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/openapi-path-templating/-/openapi-path-templating-1.6.0.tgz", @@ -4926,10 +4758,11 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4948,6 +4781,7 @@ "version": "11.0.3", "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz", "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==", + "license": "MIT", "dependencies": { "framesync": "6.0.1", "hey-listen": "^1.0.8", @@ -4956,9 +4790,9 @@ } }, "node_modules/postcss": { - "version": "8.4.45", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", - "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -4974,42 +4808,16 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5068,17 +4876,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "license": "MIT", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5093,6 +4890,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -5172,32 +4970,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -5311,11 +5083,12 @@ } }, "node_modules/react-remove-scroll": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", - "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz", + "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==", + "license": "MIT", "dependencies": { - "react-remove-scroll-bar": "^2.3.4", + "react-remove-scroll-bar": "^2.3.6", "react-style-singleton": "^2.2.1", "tslib": "^2.1.0", "use-callback-ref": "^1.3.0", @@ -5338,6 +5111,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz", "integrity": "sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==", + "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.1", "tslib": "^2.0.0" @@ -5359,6 +5133,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", "invariant": "^2.2.4", @@ -5378,13 +5153,14 @@ } }, "node_modules/react-syntax-highlighter": { - "version": "15.5.0", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", - "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", + "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.3.1", "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", "lowlight": "^1.17.0", "prismjs": "^1.27.0", "refractor": "^3.6.0" @@ -5393,21 +5169,6 @@ "react": ">= 0.14.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/redux": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", @@ -5530,12 +5291,13 @@ } }, "node_modules/rollup": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", - "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -5545,22 +5307,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.22.4", - "@rollup/rollup-android-arm64": "4.22.4", - "@rollup/rollup-darwin-arm64": "4.22.4", - "@rollup/rollup-darwin-x64": "4.22.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", - "@rollup/rollup-linux-arm-musleabihf": "4.22.4", - "@rollup/rollup-linux-arm64-gnu": "4.22.4", - "@rollup/rollup-linux-arm64-musl": "4.22.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", - "@rollup/rollup-linux-riscv64-gnu": "4.22.4", - "@rollup/rollup-linux-s390x-gnu": "4.22.4", - "@rollup/rollup-linux-x64-gnu": "4.22.4", - "@rollup/rollup-linux-x64-musl": "4.22.4", - "@rollup/rollup-win32-arm64-msvc": "4.22.4", - "@rollup/rollup-win32-ia32-msvc": "4.22.4", - "@rollup/rollup-win32-x64-msvc": "4.22.4", + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", "fsevents": "~2.3.2" } }, @@ -5621,7 +5385,7 @@ "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5654,6 +5418,7 @@ "https://paypal.me/jonathanschlinkert", "https://jonschlinkert.dev/sponsor" ], + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "is-primitive": "^3.0.1" @@ -5708,58 +5473,12 @@ "suid": "bin/short-unique-id" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5780,16 +5499,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5813,6 +5522,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz", "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==", + "license": "MIT", "dependencies": { "hey-listen": "^1.0.8", "tslib": "^2.1.0" @@ -5832,18 +5542,19 @@ } }, "node_modules/swagger-client": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.29.2.tgz", - "integrity": "sha512-7dOIAodJeUsYbvWTpDODY2+bfJcZ34WG84TByMet76OJ/ZjOLHZtJSgMFxEvnh9+yR0qn8wvHUdfg27ylg2eiQ==", + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.32.1.tgz", + "integrity": "sha512-vXRjuiUU8QbyniRwv/cOcv2glJS3eLrj3JRmge+R/Kwb+xH9t9SzWAyoalhpAkOlm+NEqpJe9wmbOJbYGR74+g==", "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.22.15", - "@swagger-api/apidom-core": ">=1.0.0-alpha.9 <1.0.0-beta.0", - "@swagger-api/apidom-error": ">=1.0.0-alpha.9 <1.0.0-beta.0", - "@swagger-api/apidom-json-pointer": ">=1.0.0-alpha.9 <1.0.0-beta.0", - "@swagger-api/apidom-ns-openapi-3-1": ">=1.0.0-alpha.9 <1.0.0-beta.0", - "@swagger-api/apidom-reference": ">=1.0.0-alpha.9 <1.0.0-beta.0", - "cookie": "~0.6.0", + "@scarf/scarf": "=1.4.0", + "@swagger-api/apidom-core": ">=1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-error": ">=1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-json-pointer": ">=1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-ns-openapi-3-1": ">=1.0.0-beta.3 <1.0.0-rc.0", + "@swagger-api/apidom-reference": ">=1.0.0-beta.3 <1.0.0-rc.0", + "cookie": "~0.7.2", "deepmerge": "~4.3.0", "fast-json-patch": "^3.0.0-1", "js-yaml": "^4.1.0", @@ -5852,22 +5563,24 @@ "node-fetch-commonjs": "^3.3.2", "openapi-path-templating": "^1.5.1", "openapi-server-url-templating": "^1.0.0", + "ramda": "^0.30.1", "ramda-adjunct": "^5.0.0" } }, "node_modules/swagger-ui-react": { - "version": "5.17.14", - "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.17.14.tgz", - "integrity": "sha512-mCXerZrbcn4ftPYifUF0+iKIRTHoVCv0HcJc/sXl9nCe3oeWdsjmOWVqKabzzAkAa0NwsbKNJFv2UL/Ivnf6VQ==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-5.18.2.tgz", + "integrity": "sha512-vpW7AmkRYdz578iq7C5WrPsg6reBgRzj5xL/fIYR6KTfvY3lvBchpzegFaqg09LWDoL3U2MZvIgOS/1Q9kSJ9g==", "license": "Apache-2.0", "dependencies": { - "@babel/runtime-corejs3": "^7.24.5", - "@braintree/sanitize-url": "=7.0.2", + "@babel/runtime-corejs3": "^7.24.7", + "@braintree/sanitize-url": "=7.0.4", + "@scarf/scarf": "=1.4.0", "base64-js": "^1.5.1", "classnames": "^2.5.1", "css.escape": "1.5.1", "deep-extend": "0.6.0", - "dompurify": "=3.1.4", + "dompurify": "=3.1.6", "ieee754": "^1.2.1", "immutable": "^3.x.x", "js-file-download": "^0.4.12", @@ -5886,10 +5599,10 @@ "redux": "^5.0.1", "redux-immutable": "^4.0.0", "remarkable": "^2.0.1", - "reselect": "^5.1.0", + "reselect": "^5.1.1", "serialize-error": "^8.1.0", "sha.js": "^2.4.11", - "swagger-client": "^3.28.1", + "swagger-client": "^3.31.0", "url-parse": "^1.5.10", "xml": "=1.0.1", "xml-but-prettier": "^1.0.1", @@ -5900,43 +5613,6 @@ "react-dom": ">=16.8.0 <19" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "license": "MIT", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5957,43 +5633,41 @@ "license": "MIT" }, "node_modules/tree-sitter": { - "version": "0.20.4", - "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.20.4.tgz", - "integrity": "sha512-rjfR5dc4knG3jnJNN/giJ9WOoN1zL/kZyrS0ILh+eqq8RNcIbiXA63JsMEgluug0aNvfQvK4BfCErN1vIzvKog==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz", + "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==", "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { - "nan": "^2.17.0", - "prebuild-install": "^7.1.1" + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.8.0" } }, "node_modules/tree-sitter-json": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.20.2.tgz", - "integrity": "sha512-eUxrowp4F1QEGk/i7Sa+Xl8Crlfp7J0AXxX1QdJEQKQYMWhgMbCIgyQvpO3Q0P9oyTrNQxRLlRipDS44a8EtRw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "nan": "^2.18.0" - } - }, - "node_modules/tree-sitter-yaml": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/tree-sitter-yaml/-/tree-sitter-yaml-0.5.0.tgz", - "integrity": "sha512-POJ4ZNXXSWIG/W4Rjuyg36MkUD4d769YRUGKRqN+sVaj/VCo6Dh6Pkssn1Rtewd5kybx+jT1BWMyWN0CijXnMA==", + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.24.8.tgz", + "integrity": "sha512-Tc9ZZYwHyWZ3Tt1VEw7Pa2scu1YO7/d2BCBbKTx5hXwig3UfdQjsOPkPyLpDJOn/m1UBEWYAtSdGAwCSyagBqQ==", "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { - "nan": "^2.14.0" + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.1.tgz", + "integrity": "sha512-5RU2/lxTA3YUZxju61HO2U6EoZLvBLtmV2mbTvqyu4a/7s7RmJPT+1YekhMVsQhznRWk/czIwDUg+V8Q9ZuG4w==", "dev": true, "license": "MIT", "engines": { @@ -6016,24 +5690,11 @@ "license": "Apache-2.0" }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6069,10 +5730,11 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6084,7 +5746,8 @@ "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" }, "node_modules/unraw": { "version": "3.0.0", @@ -6116,6 +5779,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz", "integrity": "sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -6136,6 +5800,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" @@ -6162,28 +5827,21 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT", - "optional": true - }, "node_modules/vite": { - "version": "5.4.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", - "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.2.tgz", + "integrity": "sha512-XdQ+VsY2tJpBsKGs0wf3U/+azx8BBpYRHFAyKm5VeEZNOJZRB63q7Sc8Iup3k0TrN3KO6QgyzFf+opSbfY1y0g==", "dev": true, "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.24.0", + "postcss": "^8.4.49", + "rollup": "^4.23.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -6192,19 +5850,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -6225,13 +5889,20 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, "node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" }, "node_modules/w3c-keyname": { "version": "2.2.8", @@ -6249,9 +5920,9 @@ } }, "node_modules/web-tree-sitter": { - "version": "0.20.3", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.20.3.tgz", - "integrity": "sha512-zKGJW9r23y3BcJusbgvnOH2OYAW40MXAOi9bi3Gcc7T4Gms9WWgXF8m6adsJWpGJEhgOzCrfiz1IzKowJWrtYw==", + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.3.tgz", + "integrity": "sha512-uR9YNewr1S2EzPKE+y39nAwaTyobBaZRG/IsfkB/OT4v0lXtNj5WjtHKgn2h7eOYUWIZh5rK9Px7tI6S9CRKdA==", "license": "MIT", "optional": true }, @@ -6281,13 +5952,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "optional": true - }, "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", diff --git a/playground/package.json b/playground/package.json index 3f16d6cc6e..cea10661a4 100644 --- a/playground/package.json +++ b/playground/package.json @@ -10,23 +10,23 @@ "preview": "vite preview" }, "dependencies": { - "graphiql": "^3.7.1", + "graphiql": "^3.7.2", "graphql": "^16.9.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "swagger-ui-react": "^5.17.14" + "swagger-ui-react": "^5.18.2" }, "devDependencies": { "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "@types/swagger-ui-react": "^4.18.3", - "@typescript-eslint/eslint-plugin": "^8.12.2", - "@typescript-eslint/parser": "^8.12.2", - "@vitejs/plugin-react-swc": "^3.7.1", - "eslint": "^9.14.0", + "@typescript-eslint/eslint-plugin": "^8.15.0", + "@typescript-eslint/parser": "^8.15.0", + "@vitejs/plugin-react-swc": "^3.7.2", + "eslint": "^9.16.0", "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.14", - "typescript": "^5.6.3", - "vite": "^5.4.10" + "eslint-plugin-react-refresh": "^0.4.15", + "typescript": "^5.7.2", + "vite": "^6.0.2" } } diff --git a/tests/clients/cli/wrapper_collection.go b/tests/clients/cli/wrapper_collection.go index cfa49b9e8e..eb9c5f5466 100644 --- a/tests/clients/cli/wrapper_collection.go +++ b/tests/clients/cli/wrapper_collection.go @@ -348,10 +348,24 @@ func (c *Collection) CreateIndex( } fields := make([]string, len(indexDesc.Fields)) + orders := make([]bool, len(indexDesc.Fields)) + for i := range indexDesc.Fields { fields[i] = indexDesc.Fields[i].Name + orders[i] = indexDesc.Fields[i].Descending + } + + orderedFields := make([]string, len(fields)) + + for i := range fields { + if orders[i] { + orderedFields[i] = fields[i] + ":DESC" + } else { + orderedFields[i] = fields[i] + ":ASC" + } } - args = append(args, "--fields", strings.Join(fields, ",")) + + args = append(args, "--fields", strings.Join(orderedFields, ",")) data, err := c.cmd.execute(ctx, args) if err != nil { diff --git a/tests/integration/acp.go b/tests/integration/acp.go index b98be7a059..5983ad228a 100644 --- a/tests/integration/acp.go +++ b/tests/integration/acp.go @@ -88,7 +88,7 @@ type AddPolicy struct { Policy string // The policy creator identity, i.e. actor creating the policy. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // The expected policyID generated based on the Policy loaded in to the ACP system. ExpectedPolicyID string @@ -159,13 +159,13 @@ type AddDocActorRelationship struct { // The target public identity, i.e. the identity of the actor to tie the document's relation with. // // This is a required field. To test the invalid usage of not having this arg, use NoIdentity() or leave default. - TargetIdentity immutable.Option[identityRef] + TargetIdentity immutable.Option[identity] // The requestor identity, i.e. identity of the actor creating the relationship. // Note: This identity must either own or have managing access defined in the policy. // // This is a required field. To test the invalid usage of not having this arg, use NoIdentity() or leave default. - RequestorIdentity immutable.Option[identityRef] + RequestorIdentity immutable.Option[identity] // Result returns true if it was a no-op due to existing before, and false if a new relationship was made. ExpectedExistence bool @@ -215,7 +215,11 @@ func addDocActorRelationshipACP( } if action.ExpectedError == "" && !action.ExpectedExistence { - waitForUpdateEvents(s, actionNodeID, map[string]struct{}{docID: {}}) + expect := map[string]struct{}{ + docID: {}, + } + + waitForUpdateEvents(s, actionNodeID, action.CollectionID, expect) } } @@ -247,13 +251,13 @@ type DeleteDocActorRelationship struct { // The target public identity, i.e. the identity of the actor with whom the relationship is with. // // This is a required field. To test the invalid usage of not having this arg, use NoIdentity() or leave default. - TargetIdentity immutable.Option[identityRef] + TargetIdentity immutable.Option[identity] // The requestor identity, i.e. identity of the actor deleting the relationship. // Note: This identity must either own or have managing access defined in the policy. // // This is a required field. To test the invalid usage of not having this arg, use NoIdentity() or leave default. - RequestorIdentity immutable.Option[identityRef] + RequestorIdentity immutable.Option[identity] // Result returns true if the relationship record was expected to be found and deleted, // and returns false if no matching relationship record was found (no-op). @@ -304,7 +308,7 @@ func getCollectionAndDocInfo(s *state, collectionID, docInd, nodeID int) (string collectionName := "" docID := "" if collectionID != -1 { - collection := s.collections[nodeID][collectionID] + collection := s.nodes[nodeID].collections[collectionID] if !collection.Description().Name.HasValue() { require.Fail(s.t, "Expected non-empty collection name, but it was empty.", s.testCase.Description) } @@ -617,7 +621,7 @@ func getNodeAudience(s *state, nodeIndex int) immutable.Option[string] { if nodeIndex >= len(s.nodes) { return immutable.None[string]() } - switch client := s.nodes[nodeIndex].(type) { + switch client := s.nodes[nodeIndex].Client.(type) { case *http.Wrapper: return immutable.Some(strings.TrimPrefix(client.Host(), "http://")) case *cli.Wrapper: diff --git a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go new file mode 100644 index 0000000000..c05380d8e0 --- /dev/null +++ b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_gql_test.go @@ -0,0 +1,250 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_doc_actor_add + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesOnlyReadAccessToAllActors_GQL_AllActorsCanReadButNotUpdateOrDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to all actors (gql), but the other actor can't update or delete", + + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + // GQL mutation will return no error when wrong identity is used so test that separately. + testUtils.GQLRequestMutationType, + }, + ), + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ // Since it can't read, it can't delete either. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.UpdateDoc{ // Since it can't read, it can't update either. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + SkipLocalUpdateEvent: true, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Now any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Now any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ // But doesn't mean they can update. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ // But doesn't mean they can delete. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go new file mode 100644 index 0000000000..4ee858345b --- /dev/null +++ b/tests/integration/acp/relationship/doc_actor/add/with_target_all_actors_test.go @@ -0,0 +1,250 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_doc_actor_add + +import ( + "fmt" + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerGivesOnlyReadAccessToAllActors_AllActorsCanReadButNotUpdateOrDelete(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner gives read access to all actors, but the other actor can't update or delete", + + SupportedMutationTypes: immutable.Some( + []testUtils.MutationType{ + testUtils.CollectionNamedMutationType, + testUtils.CollectionSaveMutationType, + }, + ), + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // This identity can not read yet. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents yet + }, + }, + + testUtils.DeleteDoc{ // Since it can't read, it can't delete either. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.UpdateDoc{ // Since it can't read, it can't update either. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Now any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Now any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.UpdateDoc{ // But doesn't mean they can update. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + Doc: ` + { + "name": "Shahzad Lone" + } + `, + + ExpectedError: "document not found or not authorized to access", + }, + + testUtils.DeleteDoc{ // But doesn't mean they can delete. + CollectionID: 0, + + Identity: testUtils.ClientIdentity(2), + + DocID: 0, + + ExpectedError: "document not found or not authorized to access", + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go b/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go new file mode 100644 index 0000000000..14c0121a41 --- /dev/null +++ b/tests/integration/acp/relationship/doc_actor/delete/with_target_all_actors_test.go @@ -0,0 +1,548 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package test_acp_relationship_doc_actor_delete + +import ( + "fmt" + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_ActorsCanNotReadAnymore(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner revokes read access from actors that were given read access implicitly", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), // Give implicit access to all identities. + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, not explictly allowed. + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedRecordFound: true, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Can not read anymore + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents now + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Can not read anymore + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents now + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestACP_OwnerRevokesAccessFromAllNonExplicitActors_ExplicitActorsCanStillRead(t *testing.T) { + expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4" + + test := testUtils.TestCase{ + + Description: "Test acp, owner revokes read access from actors that were given read access implicitly", + + Actions: []any{ + testUtils.AddPolicy{ + + Identity: testUtils.ClientIdentity(1), + + Policy: ` + name: Test Policy + + description: A Policy + + actor: + name: actor + + resources: + users: + permissions: + read: + expr: owner + reader + writer + + write: + expr: owner + writer + + nothing: + expr: dummy + + relations: + owner: + types: + - actor + + reader: + types: + - actor + + writer: + types: + - actor + + admin: + manages: + - reader + types: + - actor + + dummy: + types: + - actor + `, + + ExpectedPolicyID: expectedPolicyID, + }, + + testUtils.SchemaUpdate{ + Schema: fmt.Sprintf(` + type Users @policy( + id: "%s", + resource: "users" + ) { + name: String + age: Int + } + `, + expectedPolicyID, + ), + }, + + testUtils.CreateDoc{ + Identity: testUtils.ClientIdentity(1), + + CollectionID: 0, + + Doc: ` + { + "name": "Shahzad", + "age": 28 + } + `, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.ClientIdentity(2), // Give access to this identity explictly before. + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), // Give implicit access to all identities. + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.AddDocActorRelationship{ + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.ClientIdentity(4), // Give access to this identity explictly after. + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedExistence: false, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(4), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(5), // Any identity can read + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.DeleteDocActorRelationship{ // Revoke access from all actors, not explictly allowed. + RequestorIdentity: testUtils.ClientIdentity(1), + + TargetIdentity: testUtils.AllClientIdentities(), + + CollectionID: 0, + + DocID: 0, + + Relation: "reader", + + ExpectedRecordFound: true, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(3), // Can not read anymore, because it gained access implicitly. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents now + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(5), // Can not read anymore, because it gained access implicitly. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{}, // Can't see the documents now + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(2), // Can still read because it was given access explictly. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + + testUtils.Request{ + Identity: testUtils.ClientIdentity(4), // Can still read because it was given access explictly. + + Request: ` + query { + Users { + _docID + name + age + } + } + `, + + Results: map[string]any{ + "Users": []map[string]any{ + { + "_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b", + "name": "Shahzad", + "age": int64(28), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/db.go b/tests/integration/db.go index 784ff6952f..8a099e0a94 100644 --- a/tests/integration/db.go +++ b/tests/integration/db.go @@ -22,6 +22,7 @@ import ( "github.com/sourcenetwork/defradb/client" "github.com/sourcenetwork/defradb/crypto" "github.com/sourcenetwork/defradb/internal/kms" + "github.com/sourcenetwork/defradb/net" "github.com/sourcenetwork/defradb/node" changeDetector "github.com/sourcenetwork/defradb/tests/change_detector" ) @@ -140,7 +141,7 @@ func getDefaultNodeOpts() []node.Option { // setupNode returns the database implementation for the current // testing state. The database type on the test state is used to // select the datastore implementation to use. -func setupNode(s *state, opts ...node.Option) (*node.Node, string, error) { +func setupNode(s *state, opts ...node.Option) (*nodeState, error) { opts = append(getDefaultNodeOpts(), opts...) switch acpType { @@ -189,20 +190,51 @@ func setupNode(s *state, opts ...node.Option) (*node.Node, string, error) { opts = append(opts, node.WithStoreType(node.MemoryStore)) default: - return nil, "", fmt.Errorf("invalid database type: %v", s.dbt) + return nil, fmt.Errorf("invalid database type: %v", s.dbt) } if s.kms == PubSubKMSType { opts = append(opts, node.WithKMS(kms.PubSubServiceType)) } + netOpts := make([]net.NodeOpt, 0) + for _, opt := range opts { + if opt, ok := opt.(net.NodeOpt); ok { + netOpts = append(netOpts, opt) + } + } + + if s.isNetworkEnabled { + opts = append(opts, node.WithDisableP2P(false)) + } + node, err := node.New(s.ctx, opts...) if err != nil { - return nil, "", err + return nil, err } + err = node.Start(s.ctx) if err != nil { - return nil, "", err + return nil, err } - return node, path, nil + + c, err := setupClient(s, node) + require.Nil(s.t, err) + + eventState, err := newEventState(c.Events()) + require.NoError(s.t, err) + + st := &nodeState{ + Client: c, + event: eventState, + p2p: newP2PState(), + dbPath: path, + netOpts: netOpts, + } + + if node.Peer != nil { + st.peerInfo = node.Peer.PeerInfo() + } + + return st, nil } diff --git a/tests/integration/events.go b/tests/integration/events.go index bbe19ce391..12fc58f8b7 100644 --- a/tests/integration/events.go +++ b/tests/integration/events.go @@ -39,13 +39,13 @@ func waitForNetworkSetupEvents(s *state, nodeID int) { for p2pTopicEvent && replicatorEvents > 0 { select { - case _, ok := <-s.nodeEvents[nodeID].replicator.Message(): + case _, ok := <-s.nodes[nodeID].event.replicator.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for network setup events") } replicatorEvents-- - case _, ok := <-s.nodeEvents[nodeID].p2pTopic.Message(): + case _, ok := <-s.nodes[nodeID].event.p2pTopic.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for network setup events") } @@ -63,7 +63,7 @@ func waitForNetworkSetupEvents(s *state, nodeID int) { // Expected document heads will be updated for the targeted node. func waitForReplicatorConfigureEvent(s *state, cfg ConfigureReplicator) { select { - case _, ok := <-s.nodeEvents[cfg.SourceNodeID].replicator.Message(): + case _, ok := <-s.nodes[cfg.SourceNodeID].event.replicator.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for replicator event") } @@ -73,21 +73,21 @@ func waitForReplicatorConfigureEvent(s *state, cfg ConfigureReplicator) { } // all previous documents should be merged on the subscriber node - for key, val := range s.nodeP2P[cfg.SourceNodeID].actualDocHeads { - s.nodeP2P[cfg.TargetNodeID].expectedDocHeads[key] = val.cid + for key, val := range s.nodes[cfg.SourceNodeID].p2p.actualDAGHeads { + s.nodes[cfg.TargetNodeID].p2p.expectedDAGHeads[key] = val.cid } // update node connections and replicators - s.nodeP2P[cfg.TargetNodeID].connections[cfg.SourceNodeID] = struct{}{} - s.nodeP2P[cfg.SourceNodeID].connections[cfg.TargetNodeID] = struct{}{} - s.nodeP2P[cfg.SourceNodeID].replicators[cfg.TargetNodeID] = struct{}{} + s.nodes[cfg.TargetNodeID].p2p.connections[cfg.SourceNodeID] = struct{}{} + s.nodes[cfg.SourceNodeID].p2p.connections[cfg.TargetNodeID] = struct{}{} + s.nodes[cfg.SourceNodeID].p2p.replicators[cfg.TargetNodeID] = struct{}{} } // waitForReplicatorConfigureEvent waits for a node to publish a // replicator completed event on the local event bus. func waitForReplicatorDeleteEvent(s *state, cfg DeleteReplicator) { select { - case _, ok := <-s.nodeEvents[cfg.SourceNodeID].replicator.Message(): + case _, ok := <-s.nodes[cfg.SourceNodeID].event.replicator.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for replicator event") } @@ -96,9 +96,9 @@ func waitForReplicatorDeleteEvent(s *state, cfg DeleteReplicator) { require.Fail(s.t, "timeout waiting for replicator event") } - delete(s.nodeP2P[cfg.TargetNodeID].connections, cfg.SourceNodeID) - delete(s.nodeP2P[cfg.SourceNodeID].connections, cfg.TargetNodeID) - delete(s.nodeP2P[cfg.SourceNodeID].replicators, cfg.TargetNodeID) + delete(s.nodes[cfg.TargetNodeID].p2p.connections, cfg.SourceNodeID) + delete(s.nodes[cfg.SourceNodeID].p2p.connections, cfg.TargetNodeID) + delete(s.nodes[cfg.SourceNodeID].p2p.replicators, cfg.TargetNodeID) } // waitForSubscribeToCollectionEvent waits for a node to publish a @@ -107,7 +107,7 @@ func waitForReplicatorDeleteEvent(s *state, cfg DeleteReplicator) { // Expected document heads will be updated for the subscriber node. func waitForSubscribeToCollectionEvent(s *state, action SubscribeToCollection) { select { - case _, ok := <-s.nodeEvents[action.NodeID].p2pTopic.Message(): + case _, ok := <-s.nodes[action.NodeID].event.p2pTopic.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for p2p topic event") } @@ -121,7 +121,7 @@ func waitForSubscribeToCollectionEvent(s *state, action SubscribeToCollection) { if collectionIndex == NonExistentCollectionID { continue // don't track non existent collections } - s.nodeP2P[action.NodeID].peerCollections[collectionIndex] = struct{}{} + s.nodes[action.NodeID].p2p.peerCollections[collectionIndex] = struct{}{} } } @@ -129,7 +129,7 @@ func waitForSubscribeToCollectionEvent(s *state, action SubscribeToCollection) { // p2p topic completed event on the local event bus. func waitForUnsubscribeToCollectionEvent(s *state, action UnsubscribeToCollection) { select { - case _, ok := <-s.nodeEvents[action.NodeID].p2pTopic.Message(): + case _, ok := <-s.nodes[action.NodeID].event.p2pTopic.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for p2p topic event") } @@ -142,7 +142,7 @@ func waitForUnsubscribeToCollectionEvent(s *state, action UnsubscribeToCollectio if collectionIndex == NonExistentCollectionID { continue // don't track non existent collections } - delete(s.nodeP2P[action.NodeID].peerCollections, collectionIndex) + delete(s.nodes[action.NodeID].p2p.peerCollections, collectionIndex) } } @@ -153,6 +153,7 @@ func waitForUnsubscribeToCollectionEvent(s *state, action UnsubscribeToCollectio func waitForUpdateEvents( s *state, nodeID immutable.Option[int], + collectionIndex int, docIDs map[string]struct{}, ) { for i := 0; i < len(s.nodes); i++ { @@ -160,11 +161,17 @@ func waitForUpdateEvents( continue // node is not selected } - if _, ok := s.closedNodes[i]; ok { + node := s.nodes[i] + if node.closed { continue // node is closed } expect := make(map[string]struct{}, len(docIDs)) + + col := node.collections[collectionIndex] + if col.Description().IsBranchable { + expect[col.SchemaRoot()] = struct{}{} + } for k := range docIDs { expect[k] = struct{}{} } @@ -172,7 +179,7 @@ func waitForUpdateEvents( for len(expect) > 0 { var evt event.Update select { - case msg, ok := <-s.nodeEvents[i].update.Message(): + case msg, ok := <-node.event.update.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for update event", "Node %d", i) } @@ -182,41 +189,36 @@ func waitForUpdateEvents( require.Fail(s.t, "timeout waiting for update event", "Node %d", i) } - if evt.DocID == "" { - // Todo: This will almost certainly need to change once P2P for collection-level commits - // is enabled. See: https://github.com/sourcenetwork/defradb/issues/3212 - continue - } - // make sure the event is expected - _, ok := expect[evt.DocID] - require.True(s.t, ok, "unexpected document update", "Node %d", i) - delete(expect, evt.DocID) + _, ok := expect[getUpdateEventKey(evt)] + require.True(s.t, ok, "unexpected document update", getUpdateEventKey(evt)) + delete(expect, getUpdateEventKey(evt)) // we only need to update the network state if the nodes // are configured for networking - if i < len(s.nodeConfigs) { + if s.isNetworkEnabled { updateNetworkState(s, i, evt) } } } } -// waitForMergeEvents waits for all expected document heads to be merged to all nodes. +// waitForMergeEvents waits for all expected heads to be merged to all nodes. // // Will fail the test if an event is not received within the expected time interval to prevent tests // from running forever. func waitForMergeEvents(s *state, action WaitForSync) { for nodeID := 0; nodeID < len(s.nodes); nodeID++ { - if _, ok := s.closedNodes[nodeID]; ok { + node := s.nodes[nodeID] + if node.closed { continue // node is closed } - expect := s.nodeP2P[nodeID].expectedDocHeads + expect := node.p2p.expectedDAGHeads - // remove any docs that are already merged - // up to the expected document head - for key, val := range s.nodeP2P[nodeID].actualDocHeads { + // remove any heads that are already merged + // up to the expected head + for key, val := range node.p2p.actualDAGHeads { if head, ok := expect[key]; ok && head.String() == val.cid.String() { delete(expect, key) } @@ -228,13 +230,13 @@ func waitForMergeEvents(s *state, action WaitForSync) { require.Fail(s.t, "doc index %d out of range", docIndex) } docID := s.docIDs[0][docIndex].String() - actual, hasActual := s.nodeP2P[nodeID].actualDocHeads[docID] + actual, hasActual := node.p2p.actualDAGHeads[docID] if !hasActual || !actual.decrypted { expectDecrypted[docID] = struct{}{} } } - // wait for all expected doc heads to be merged + // wait for all expected heads to be merged // // the order of merges does not matter as we only // expect the latest head to eventually be merged @@ -243,7 +245,7 @@ func waitForMergeEvents(s *state, action WaitForSync) { for len(expect) > 0 || len(expectDecrypted) > 0 { var evt event.MergeComplete select { - case msg, ok := <-s.nodeEvents[nodeID].merge.Message(): + case msg, ok := <-node.event.merge.Message(): if !ok { require.Fail(s.t, "subscription closed waiting for merge complete event") } @@ -258,11 +260,11 @@ func waitForMergeEvents(s *state, action WaitForSync) { delete(expectDecrypted, evt.Merge.DocID) } - head, ok := expect[evt.Merge.DocID] + head, ok := expect[getMergeEventKey(evt.Merge)] if ok && head.String() == evt.Merge.Cid.String() { - delete(expect, evt.Merge.DocID) + delete(expect, getMergeEventKey(evt.Merge)) } - s.nodeP2P[nodeID].actualDocHeads[evt.Merge.DocID] = docHeadState{cid: evt.Merge.Cid, decrypted: evt.Decrypted} + node.p2p.actualDAGHeads[getMergeEventKey(evt.Merge)] = docHeadState{cid: evt.Merge.Cid, decrypted: evt.Decrypted} } } } @@ -272,31 +274,33 @@ func waitForMergeEvents(s *state, action WaitForSync) { func updateNetworkState(s *state, nodeID int, evt event.Update) { // find the correct collection index for this update collectionID := -1 - for i, c := range s.collections[nodeID] { + for i, c := range s.nodes[nodeID].collections { if c.SchemaRoot() == evt.SchemaRoot { collectionID = i } } + node := s.nodes[nodeID] + // update the actual document head on the node that updated it // as the node created the document, it is already decrypted - s.nodeP2P[nodeID].actualDocHeads[evt.DocID] = docHeadState{cid: evt.Cid, decrypted: true} + node.p2p.actualDAGHeads[getUpdateEventKey(evt)] = docHeadState{cid: evt.Cid, decrypted: true} // update the expected document heads of replicator targets - for id := range s.nodeP2P[nodeID].replicators { + for id := range node.p2p.replicators { // replicator target nodes push updates to source nodes - s.nodeP2P[id].expectedDocHeads[evt.DocID] = evt.Cid + s.nodes[id].p2p.expectedDAGHeads[getUpdateEventKey(evt)] = evt.Cid } // update the expected document heads of connected nodes - for id := range s.nodeP2P[nodeID].connections { + for id := range node.p2p.connections { // connected nodes share updates of documents they have in common - if _, ok := s.nodeP2P[id].actualDocHeads[evt.DocID]; ok { - s.nodeP2P[id].expectedDocHeads[evt.DocID] = evt.Cid + if _, ok := s.nodes[id].p2p.actualDAGHeads[getUpdateEventKey(evt)]; ok { + s.nodes[id].p2p.expectedDAGHeads[getUpdateEventKey(evt)] = evt.Cid } // peer collection subscribers receive updates from any other subscriber node - if _, ok := s.nodeP2P[id].peerCollections[collectionID]; ok { - s.nodeP2P[id].expectedDocHeads[evt.DocID] = evt.Cid + if _, ok := s.nodes[id].p2p.peerCollections[collectionID]; ok { + s.nodes[id].p2p.expectedDAGHeads[getUpdateEventKey(evt)] = evt.Cid } } @@ -325,15 +329,15 @@ func getEventsForUpdateDoc(s *state, action UpdateDoc) map[string]struct{} { func getEventsForCreateDoc(s *state, action CreateDoc) map[string]struct{} { var collection client.Collection if action.NodeID.HasValue() { - collection = s.collections[action.NodeID.Value()][action.CollectionID] + collection = s.nodes[action.NodeID.Value()].collections[action.CollectionID] } else { - collection = s.collections[0][action.CollectionID] + collection = s.nodes[0].collections[action.CollectionID] } docs, err := parseCreateDocs(action, collection) require.NoError(s.t, err) - expect := make(map[string]struct{}) + expect := make(map[string]struct{}, action.CollectionID+1) for _, doc := range docs { expect[doc.ID().String()] = struct{}{} @@ -357,7 +361,7 @@ func getEventsForUpdateWithFilter( err := json.Unmarshal([]byte(action.Updater), &docPatch) require.NoError(s.t, err) - expect := make(map[string]struct{}) + expect := make(map[string]struct{}, len(result.DocIDs)) for _, docID := range result.DocIDs { expect[docID] = struct{}{} @@ -365,3 +369,27 @@ func getEventsForUpdateWithFilter( return expect } + +// getUpdateEventKey gets the identifier to which this event is scoped to. +// +// For example, if this is scoped to a document, the document ID will be +// returned. If it is scoped to a schema, the schema root will be returned. +func getUpdateEventKey(evt event.Update) string { + if evt.DocID == "" { + return evt.SchemaRoot + } + + return evt.DocID +} + +// getMergeEventKey gets the identifier to which this event is scoped to. +// +// For example, if this is scoped to a document, the document ID will be +// returned. If it is scoped to a schema, the schema root will be returned. +func getMergeEventKey(evt event.Merge) string { + if evt.DocID == "" { + return evt.SchemaRoot + } + + return evt.DocID +} diff --git a/tests/integration/explain/default/basic_test.go b/tests/integration/explain/default/basic_test.go index 69089cd15d..d74d5e38e2 100644 --- a/tests/integration/explain/default/basic_test.go +++ b/tests/integration/explain/default/basic_test.go @@ -71,11 +71,8 @@ func TestDefaultExplainRequestWithFullBasicGraph(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/dagscan_test.go b/tests/integration/explain/default/dagscan_test.go index c19058c258..45b894af2d 100644 --- a/tests/integration/explain/default/dagscan_test.go +++ b/tests/integration/explain/default/dagscan_test.go @@ -58,11 +58,8 @@ func TestDefaultExplainCommitsDagScanQueryOp(t *testing.T) { ExpectedAttributes: dataMap{ "cid": nil, "fieldId": "1", - "spans": []dataMap{ - { - "start": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/1", - "end": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/2", - }, + "prefixes": []string{ + "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/1", }, }, }, @@ -101,11 +98,8 @@ func TestDefaultExplainCommitsDagScanQueryOpWithoutField(t *testing.T) { ExpectedAttributes: dataMap{ "cid": nil, "fieldId": nil, - "spans": []dataMap{ - { - "start": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84", - "end": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e85", - }, + "prefixes": []string{ + "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84", }, }, }, @@ -145,11 +139,8 @@ func TestDefaultExplainLatestCommitsDagScanQueryOp(t *testing.T) { ExpectedAttributes: dataMap{ "cid": nil, "fieldId": "1", - "spans": []dataMap{ - { - "start": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/1", - "end": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/2", - }, + "prefixes": []string{ + "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/1", }, }, }, @@ -189,11 +180,8 @@ func TestDefaultExplainLatestCommitsDagScanQueryOpWithoutField(t *testing.T) { ExpectedAttributes: dataMap{ "cid": nil, "fieldId": "C", - "spans": []dataMap{ - { - "start": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/C", - "end": "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/D", - }, + "prefixes": []string{ + "/d/bae-7aabc9d2-fbbc-5911-b0d0-b49a2a1d0e84/C", }, }, }, diff --git a/tests/integration/explain/default/delete_test.go b/tests/integration/explain/default/delete_test.go index 39b3b732d5..16005cea30 100644 --- a/tests/integration/explain/default/delete_test.go +++ b/tests/integration/explain/default/delete_test.go @@ -76,11 +76,8 @@ func TestDefaultExplainMutationRequestWithDeleteUsingFilter(t *testing.T) { "_eq": "Shahzad", }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -127,11 +124,8 @@ func TestDefaultExplainMutationRequestWithDeleteUsingFilterToMatchEverything(t * "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -180,11 +174,8 @@ func TestDefaultExplainMutationRequestWithDeleteUsingId(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, @@ -237,15 +228,9 @@ func TestDefaultExplainMutationRequestWithDeleteUsingIds(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - }, - { - "end": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67g", - "start": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", + "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", }, }, }, @@ -292,11 +277,8 @@ func TestDefaultExplainMutationRequestWithDeleteUsingNoIds(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -380,15 +362,9 @@ func TestDefaultExplainMutationRequestWithDeleteUsingFilterAndIds(t *testing.T) }, }, }, - "spans": []dataMap{ - { - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - }, - { - "end": "/3/tesu", - "start": "/3/test", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", + "/3/test", }, }, }, diff --git a/tests/integration/explain/default/group_with_doc_id_child_test.go b/tests/integration/explain/default/group_with_doc_id_child_test.go index 38a8d27fe5..4e43f27465 100644 --- a/tests/integration/explain/default/group_with_doc_id_child_test.go +++ b/tests/integration/explain/default/group_with_doc_id_child_test.go @@ -65,11 +65,8 @@ func TestDefaultExplainRequestWithDocIDsOnInnerGroupSelection(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/group_with_doc_id_test.go b/tests/integration/explain/default/group_with_doc_id_test.go index 8146a26566..9c1e4614e7 100644 --- a/tests/integration/explain/default/group_with_doc_id_test.go +++ b/tests/integration/explain/default/group_with_doc_id_test.go @@ -59,11 +59,8 @@ func TestDefaultExplainRequestWithDocIDOnParentGroupBy(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2254", - "end": "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2255", - }, + "prefixes": []string{ + "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2254", }, }, }, @@ -125,15 +122,9 @@ func TestDefaultExplainRequestWithDocIDsAndFilterOnParentGroupBy(t *testing.T) { "_eq": int32(20), }, }, - "spans": []dataMap{ - { - "start": "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2254", - "end": "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2255", - }, - { - "start": "/3/bae-4ea9d148-13f3-5a48-a0ef-9ffd344caeed", - "end": "/3/bae-4ea9d148-13f3-5a48-a0ef-9ffd344caeee", - }, + "prefixes": []string{ + "/3/bae-6a4c5bc5-b044-5a03-a868-8260af6f2254", + "/3/bae-4ea9d148-13f3-5a48-a0ef-9ffd344caeed", }, }, }, diff --git a/tests/integration/explain/default/group_with_filter_child_test.go b/tests/integration/explain/default/group_with_filter_child_test.go index e6f4a42a0d..ff49db2655 100644 --- a/tests/integration/explain/default/group_with_filter_child_test.go +++ b/tests/integration/explain/default/group_with_filter_child_test.go @@ -67,11 +67,8 @@ func TestDefaultExplainRequestWithFilterOnInnerGroupSelection(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -140,11 +137,8 @@ func TestDefaultExplainRequestWithFilterOnParentGroupByAndInnerGroupSelection(t }, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/group_with_filter_test.go b/tests/integration/explain/default/group_with_filter_test.go index 23651934e3..bef0be6ccb 100644 --- a/tests/integration/explain/default/group_with_filter_test.go +++ b/tests/integration/explain/default/group_with_filter_test.go @@ -63,11 +63,8 @@ func TestDefaultExplainRequestWithFilterOnGroupByParent(t *testing.T) { "_gt": int32(63), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/top_with_average_test.go b/tests/integration/explain/default/top_with_average_test.go index 1921a142f7..e76730a49f 100644 --- a/tests/integration/explain/default/top_with_average_test.go +++ b/tests/integration/explain/default/top_with_average_test.go @@ -76,11 +76,8 @@ func TestDefaultExplainTopLevelAverageRequest(t *testing.T) { "_ne": nil, }, }, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -168,11 +165,8 @@ func TestDefaultExplainTopLevelAverageRequestWithFilter(t *testing.T) { "_ne": nil, }, }, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/top_with_count_test.go b/tests/integration/explain/default/top_with_count_test.go index 6ac039f764..09ffbf409a 100644 --- a/tests/integration/explain/default/top_with_count_test.go +++ b/tests/integration/explain/default/top_with_count_test.go @@ -62,11 +62,8 @@ func TestDefaultExplainTopLevelCountRequest(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -126,11 +123,8 @@ func TestDefaultExplainTopLevelCountRequestWithFilter(t *testing.T) { "_gt": int32(26), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/top_with_max_test.go b/tests/integration/explain/default/top_with_max_test.go index 16d53b5007..0342941dcb 100644 --- a/tests/integration/explain/default/top_with_max_test.go +++ b/tests/integration/explain/default/top_with_max_test.go @@ -66,11 +66,8 @@ func TestDefaultExplain_WithTopLevelMaxRequest_Succeeds(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -132,11 +129,8 @@ func TestDefaultExplain_WithTopLevelMaxRequestWithFilter_Succeeds(t *testing.T) "_gt": int32(26), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/top_with_min_test.go b/tests/integration/explain/default/top_with_min_test.go index b212953a60..41a5394763 100644 --- a/tests/integration/explain/default/top_with_min_test.go +++ b/tests/integration/explain/default/top_with_min_test.go @@ -66,11 +66,8 @@ func TestDefaultExplain_WithTopLevelMinRequest_Succeeds(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -132,11 +129,8 @@ func TestDefaultExplain_WithTopLevelMinRequestWithFilter_Succeeds(t *testing.T) "_gt": int32(26), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/top_with_sum_test.go b/tests/integration/explain/default/top_with_sum_test.go index a2927beb25..0de7bd5466 100644 --- a/tests/integration/explain/default/top_with_sum_test.go +++ b/tests/integration/explain/default/top_with_sum_test.go @@ -66,11 +66,8 @@ func TestDefaultExplainTopLevelSumRequest(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -132,11 +129,8 @@ func TestDefaultExplainTopLevelSumRequestWithFilter(t *testing.T) { "_gt": int32(26), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/type_join_many_test.go b/tests/integration/explain/default/type_join_many_test.go index 3790d43dfa..d21af2de24 100644 --- a/tests/integration/explain/default/type_join_many_test.go +++ b/tests/integration/explain/default/type_join_many_test.go @@ -71,11 +71,8 @@ func TestDefaultExplainRequestWithAOneToManyJoin(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -94,11 +91,8 @@ func TestDefaultExplainRequestWithAOneToManyJoin(t *testing.T) { "filter": nil, "collectionID": "1", "collectionName": "Article", - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/type_join_one_test.go b/tests/integration/explain/default/type_join_one_test.go index 97b17fbf1d..35c6de1001 100644 --- a/tests/integration/explain/default/type_join_one_test.go +++ b/tests/integration/explain/default/type_join_one_test.go @@ -72,11 +72,8 @@ func TestDefaultExplainRequestWithAOneToOneJoin(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -95,11 +92,8 @@ func TestDefaultExplainRequestWithAOneToOneJoin(t *testing.T) { "filter": nil, "collectionID": "4", "collectionName": "AuthorContact", - "spans": []dataMap{ - { - "start": "/4", - "end": "/5", - }, + "prefixes": []string{ + "/4", }, }, }, @@ -182,11 +176,8 @@ func TestDefaultExplainRequestWithTwoLevelDeepNestedJoins(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -215,11 +206,8 @@ func TestDefaultExplainRequestWithTwoLevelDeepNestedJoins(t *testing.T) { "filter": nil, "collectionID": "4", "collectionName": "AuthorContact", - "spans": []dataMap{ - { - "start": "/4", - "end": "/5", - }, + "prefixes": []string{ + "/4", }, }, }, @@ -237,11 +225,8 @@ func TestDefaultExplainRequestWithTwoLevelDeepNestedJoins(t *testing.T) { "filter": nil, "collectionID": "5", "collectionName": "ContactAddress", - "spans": []dataMap{ - { - "start": "/5", - "end": "/6", - }, + "prefixes": []string{ + "/5", }, }, }, diff --git a/tests/integration/explain/default/type_join_test.go b/tests/integration/explain/default/type_join_test.go index c88c7980be..918fe04d30 100644 --- a/tests/integration/explain/default/type_join_test.go +++ b/tests/integration/explain/default/type_join_test.go @@ -105,11 +105,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -129,11 +126,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "4", "collectionName": "AuthorContact", - "spans": []dataMap{ - { - "start": "/4", - "end": "/5", - }, + "prefixes": []string{ + "/4", }, }, }, @@ -163,11 +157,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -187,11 +178,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "1", "collectionName": "Article", - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, @@ -222,11 +210,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -240,11 +225,8 @@ func TestDefaultExplainRequestWith2SingleJoinsAnd1ManyJoin(t *testing.T) { "filter": nil, "collectionID": "4", "collectionName": "AuthorContact", - "spans": []dataMap{ - { - "start": "/4", - "end": "/5", - }, + "prefixes": []string{ + "/4", }, }, }, diff --git a/tests/integration/explain/default/type_join_with_filter_doc_id_test.go b/tests/integration/explain/default/type_join_with_filter_doc_id_test.go index 8a29156009..5dc9cbabf2 100644 --- a/tests/integration/explain/default/type_join_with_filter_doc_id_test.go +++ b/tests/integration/explain/default/type_join_with_filter_doc_id_test.go @@ -85,15 +85,9 @@ func TestDefaultExplainRequestWithRelatedAndRegularFilterAndDocIDs(t *testing.T) "_eq": "John Grisham", }, }, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f8e", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f8f", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f8e", }, }, }, @@ -182,11 +176,8 @@ func TestDefaultExplainRequestWithManyRelatedFiltersAndDocID(t *testing.T) { "_eq": "Cornelia Funke", }, }, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, diff --git a/tests/integration/explain/default/type_join_with_filter_test.go b/tests/integration/explain/default/type_join_with_filter_test.go index 1c7a35c1ba..275b7c2c8b 100644 --- a/tests/integration/explain/default/type_join_with_filter_test.go +++ b/tests/integration/explain/default/type_join_with_filter_test.go @@ -78,11 +78,8 @@ func TestDefaultExplainRequestWithRelatedAndRegularFilter(t *testing.T) { "_eq": "John Grisham", }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -168,11 +165,8 @@ func TestDefaultExplainRequestWithManyRelatedFilters(t *testing.T) { "_eq": "Cornelia Funke", }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/update_test.go b/tests/integration/explain/default/update_test.go index 8941a710ec..26f9c538b6 100644 --- a/tests/integration/explain/default/update_test.go +++ b/tests/integration/explain/default/update_test.go @@ -87,11 +87,8 @@ func TestDefaultExplainMutationRequestWithUpdateUsingBooleanFilter(t *testing.T) "_eq": true, }, }, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -151,15 +148,9 @@ func TestDefaultExplainMutationRequestWithUpdateUsingIds(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "end": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67g", - "start": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", - }, - { - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - }, + "prefixes": []string{ + "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, @@ -215,11 +206,8 @@ func TestDefaultExplainMutationRequestWithUpdateUsingId(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", - "end": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67g", - }, + "prefixes": []string{ + "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", }, }, }, @@ -292,15 +280,9 @@ func TestDefaultExplainMutationRequestWithUpdateUsingIdsAndFilter(t *testing.T) "_eq": true, }, }, - "spans": []dataMap{ - { - "start": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", - "end": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67g", - }, - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, + "prefixes": []string{ + "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, diff --git a/tests/integration/explain/default/upsert_test.go b/tests/integration/explain/default/upsert_test.go index 7cc38294e8..8ff2a964e6 100644 --- a/tests/integration/explain/default/upsert_test.go +++ b/tests/integration/explain/default/upsert_test.go @@ -87,11 +87,8 @@ func TestDefaultExplainMutationRequest_WithUpsert_Succeeds(t *testing.T) { "_eq": "Bob", }, }, - "spans": []dataMap{ - { - "end": "/4", - "start": "/3", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/with_average_join_test.go b/tests/integration/explain/default/with_average_join_test.go index 5d65408540..455f0023b3 100644 --- a/tests/integration/explain/default/with_average_join_test.go +++ b/tests/integration/explain/default/with_average_join_test.go @@ -114,11 +114,8 @@ func TestDefaultExplainRequestWithAverageOnJoinedField(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -134,11 +131,8 @@ func TestDefaultExplainRequestWithAverageOnJoinedField(t *testing.T) { "_ne": nil, }, }, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -273,11 +267,8 @@ func TestDefaultExplainRequestWithAverageOnMultipleJoinedFieldsWithFilter(t *tes "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -293,11 +284,8 @@ func TestDefaultExplainRequestWithAverageOnMultipleJoinedFieldsWithFilter(t *tes "_ne": nil, }, }, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -319,11 +307,8 @@ func TestDefaultExplainRequestWithAverageOnMultipleJoinedFieldsWithFilter(t *tes "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -340,11 +325,8 @@ func TestDefaultExplainRequestWithAverageOnMultipleJoinedFieldsWithFilter(t *tes "_ne": nil, }, }, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_average_test.go b/tests/integration/explain/default/with_average_test.go index 71a66aa6f8..132632cb4c 100644 --- a/tests/integration/explain/default/with_average_test.go +++ b/tests/integration/explain/default/with_average_test.go @@ -94,11 +94,8 @@ func TestDefaultExplainRequestWithAverageOnArrayField(t *testing.T) { "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, diff --git a/tests/integration/explain/default/with_count_join_test.go b/tests/integration/explain/default/with_count_join_test.go index a406855b71..a4c7e16f28 100644 --- a/tests/integration/explain/default/with_count_join_test.go +++ b/tests/integration/explain/default/with_count_join_test.go @@ -84,11 +84,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedField(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -100,11 +97,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedField(t *testing.T) { "filter": nil, "collectionID": "2", "collectionName": "Book", - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -195,11 +189,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedFieldWithManySources(t * "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -211,11 +202,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedFieldWithManySources(t * "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -237,11 +225,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedFieldWithManySources(t * "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -253,11 +238,8 @@ func TestDefaultExplainRequestWithCountOnOneToManyJoinedFieldWithManySources(t * "collectionID": "1", "collectionName": "Article", "filter": nil, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_count_test.go b/tests/integration/explain/default/with_count_test.go index 311c52d599..8c5e0f5d76 100644 --- a/tests/integration/explain/default/with_count_test.go +++ b/tests/integration/explain/default/with_count_test.go @@ -72,11 +72,8 @@ func TestDefaultExplainRequestWithCountOnInlineArrayField(t *testing.T) { "filter": nil, "collectionID": "2", "collectionName": "Book", - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, diff --git a/tests/integration/explain/default/with_filter_doc_id_test.go b/tests/integration/explain/default/with_filter_doc_id_test.go index 3e08aedb3b..a453716293 100644 --- a/tests/integration/explain/default/with_filter_doc_id_test.go +++ b/tests/integration/explain/default/with_filter_doc_id_test.go @@ -53,11 +53,8 @@ func TestDefaultExplainRequestWithDocIDFilter(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, @@ -105,11 +102,8 @@ func TestDefaultExplainRequestWithDocIDsFilterUsingOneID(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, @@ -163,15 +157,9 @@ func TestDefaultExplainRequestWithDocIDsFilterUsingMultipleButDuplicateIDs(t *te "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, }, @@ -225,15 +213,9 @@ func TestDefaultExplainRequestWithDocIDsFilterUsingMultipleUniqueIDs(t *testing. "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", - "end": "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9e", - }, - { - "start": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", - "end": "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67g", - }, + "prefixes": []string{ + "/3/bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", + "/3/bae-bfbfc89c-0d63-5ea4-81a3-3ebd295be67f", }, }, }, @@ -289,11 +271,8 @@ func TestDefaultExplainRequestWithMatchingIDFilter(t *testing.T) { "_eq": "bae-079d0bd8-4b1b-5f5f-bd95-4d915c277f9d", }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/explain/default/with_filter_test.go b/tests/integration/explain/default/with_filter_test.go index 96e99e19ac..b22afeb60d 100644 --- a/tests/integration/explain/default/with_filter_test.go +++ b/tests/integration/explain/default/with_filter_test.go @@ -48,11 +48,8 @@ func TestDefaultExplainRequestWithStringEqualFilter(t *testing.T) { "_eq": "Lone", }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -95,11 +92,8 @@ func TestDefaultExplainRequestWithIntegerEqualFilter(t *testing.T) { "_eq": int32(26), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -142,11 +136,8 @@ func TestDefaultExplainRequestWithGreaterThanFilter(t *testing.T) { "_gt": int32(20), }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -198,11 +189,8 @@ func TestDefaultExplainRequestWithLogicalCompoundAndFilter(t *testing.T) { }, }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -254,11 +242,8 @@ func TestDefaultExplainRequestWithLogicalCompoundOrFilter(t *testing.T) { }, }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -305,11 +290,8 @@ func TestDefaultExplainRequestWithMatchInsideList(t *testing.T) { }, }, }, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -354,11 +336,8 @@ func TestDefaultExplainRequest_WithJSONEqualFilter_Succeeds(t *testing.T) { }, }, }, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_max_join_test.go b/tests/integration/explain/default/with_max_join_test.go index a282f9f134..f6c69f470f 100644 --- a/tests/integration/explain/default/with_max_join_test.go +++ b/tests/integration/explain/default/with_max_join_test.go @@ -88,11 +88,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedField_Succeeds(t *testing "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -104,11 +101,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedField_Succeeds(t *testing "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -183,11 +177,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithFilter_Succeeds( "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -203,11 +194,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithFilter_Succeeds( "_eq": "To my dear readers", }, }, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, @@ -300,11 +288,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -316,11 +301,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -342,11 +324,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -358,11 +337,8 @@ func TestDefaultExplainRequest_WithMaxOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "1", "collectionName": "Article", "filter": nil, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_max_test.go b/tests/integration/explain/default/with_max_test.go index 823e3d5def..1c3f90e7c8 100644 --- a/tests/integration/explain/default/with_max_test.go +++ b/tests/integration/explain/default/with_max_test.go @@ -73,11 +73,8 @@ func TestDefaultExplainRequest_WithMaxOnInlineArrayField_ChildFieldWillBeEmpty(t "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, diff --git a/tests/integration/explain/default/with_min_join_test.go b/tests/integration/explain/default/with_min_join_test.go index 2e12bf1788..5e1fa6c1bb 100644 --- a/tests/integration/explain/default/with_min_join_test.go +++ b/tests/integration/explain/default/with_min_join_test.go @@ -88,11 +88,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedField_Succeeds(t *testing "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -104,11 +101,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedField_Succeeds(t *testing "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -183,11 +177,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithFilter_Succeeds( "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -203,11 +194,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithFilter_Succeeds( "_eq": "To my dear readers", }, }, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, @@ -300,11 +288,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -316,11 +301,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -342,11 +324,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -358,11 +337,8 @@ func TestDefaultExplainRequest_WithMinOnOneToManyJoinedFieldWithManySources_Succ "collectionID": "1", "collectionName": "Article", "filter": nil, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_min_test.go b/tests/integration/explain/default/with_min_test.go index 63da42909e..aabf3c6903 100644 --- a/tests/integration/explain/default/with_min_test.go +++ b/tests/integration/explain/default/with_min_test.go @@ -73,11 +73,8 @@ func TestDefaultExplainRequest_WithMinOnInlineArrayField_ChildFieldWillBeEmpty(t "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, diff --git a/tests/integration/explain/default/with_sum_join_test.go b/tests/integration/explain/default/with_sum_join_test.go index d2b7b6dc64..47a4f1fb96 100644 --- a/tests/integration/explain/default/with_sum_join_test.go +++ b/tests/integration/explain/default/with_sum_join_test.go @@ -88,11 +88,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedField(t *testing.T) { "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -104,11 +101,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedField(t *testing.T) { "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -183,11 +177,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithFilter(t *testing "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -203,11 +194,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithFilter(t *testing "_eq": "To my dear readers", }, }, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, @@ -300,11 +288,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithManySources(t *te "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -316,11 +301,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithManySources(t *te "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, @@ -342,11 +324,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithManySources(t *te "collectionID": "3", "collectionName": "Author", "filter": nil, - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, @@ -358,11 +337,8 @@ func TestDefaultExplainRequestWithSumOnOneToManyJoinedFieldWithManySources(t *te "collectionID": "1", "collectionName": "Article", "filter": nil, - "spans": []dataMap{ - { - "start": "/1", - "end": "/2", - }, + "prefixes": []string{ + "/1", }, }, }, diff --git a/tests/integration/explain/default/with_sum_test.go b/tests/integration/explain/default/with_sum_test.go index 2f1673ce3a..aac2836c81 100644 --- a/tests/integration/explain/default/with_sum_test.go +++ b/tests/integration/explain/default/with_sum_test.go @@ -73,11 +73,8 @@ func TestDefaultExplainRequestWithSumOnInlineArrayField_ChildFieldWillBeEmpty(t "collectionID": "2", "collectionName": "Book", "filter": nil, - "spans": []dataMap{ - { - "start": "/2", - "end": "/3", - }, + "prefixes": []string{ + "/2", }, }, }, diff --git a/tests/integration/explain/simple/basic_test.go b/tests/integration/explain/simple/basic_test.go index f061785fde..24969ac6ba 100644 --- a/tests/integration/explain/simple/basic_test.go +++ b/tests/integration/explain/simple/basic_test.go @@ -47,11 +47,8 @@ func TestSimpleExplainRequest(t *testing.T) { "filter": nil, "collectionID": "3", "collectionName": "Author", - "spans": []dataMap{ - { - "start": "/3", - "end": "/4", - }, + "prefixes": []string{ + "/3", }, }, }, diff --git a/tests/integration/identity.go b/tests/integration/identity.go index 7c56d81375..d8efe506df 100644 --- a/tests/integration/identity.go +++ b/tests/integration/identity.go @@ -13,6 +13,7 @@ package tests import ( "context" "math/rand" + "strconv" "github.com/decred/dcrd/dcrec/secp256k1/v4" "github.com/sourcenetwork/immutable" @@ -21,31 +22,56 @@ import ( acpIdentity "github.com/sourcenetwork/defradb/acp/identity" ) -// identityRef is a type that refers to a specific identity of a certain type. -type identityRef struct { - isClient bool - index int +type identityType int + +const ( + clientIdentityType identityType = iota + nodeIdentityType +) + +// identity helps specify identity type info and selector/index of identity to use in a test case. +type identity struct { + // type of identity + kind identityType + + // selector can be a valid identity index or a selecting pattern like "*". + // Note: "*" means to select all identities of the specified [kind] type. + selector string } // NoIdentity returns an reference to an identity that represents no identity. -func NoIdentity() immutable.Option[identityRef] { - return immutable.None[identityRef]() +func NoIdentity() immutable.Option[identity] { + return immutable.None[identity]() } -// ClientIdentity returns a reference to a user identity with a given index. -func ClientIdentity(index int) immutable.Option[identityRef] { - return immutable.Some(identityRef{ - isClient: true, - index: index, - }) +// AllClientIdentities returns user identity selector specified with the "*". +func AllClientIdentities() immutable.Option[identity] { + return immutable.Some( + identity{ + kind: clientIdentityType, + selector: "*", + }, + ) } -// NodeIdentity returns a reference to a node identity with a given index. -func NodeIdentity(index int) immutable.Option[identityRef] { - return immutable.Some(identityRef{ - isClient: false, - index: index, - }) +// ClientIdentity returns a user identity at the given index. +func ClientIdentity(indexSelector int) immutable.Option[identity] { + return immutable.Some( + identity{ + kind: clientIdentityType, + selector: strconv.Itoa(indexSelector), + }, + ) +} + +// ClientIdentity returns a node identity at the given index. +func NodeIdentity(indexSelector int) immutable.Option[identity] { + return immutable.Some( + identity{ + kind: nodeIdentityType, + selector: strconv.Itoa(indexSelector), + }, + ) } // identityHolder holds an identity and the generated tokens for each target node. @@ -66,30 +92,37 @@ func newIdentityHolder(ident acpIdentity.Identity) *identityHolder { // getIdentity returns the identity for the given reference. // If the identity does not exist, it will be generated. -func getIdentity(s *state, ref immutable.Option[identityRef]) acpIdentity.Identity { - if !ref.HasValue() { +func getIdentity(s *state, identity immutable.Option[identity]) acpIdentity.Identity { + if !identity.HasValue() { return acpIdentity.Identity{} } - return getIdentityHolder(s, ref.Value()).Identity + + // The selector must never be "*" here because this function returns a specific identity from the + // stored identities, if "*" string needs to be signaled to the acp module then it should be handled + // a call before this function. + if identity.Value().selector == "*" { + require.Fail(s.t, "Used the \"*\" selector for identity incorrectly.", s.testCase.Description) + } + return getIdentityHolder(s, identity.Value()).Identity } // getIdentityHolder returns the identity holder for the given reference. // If the identity does not exist, it will be generated. -func getIdentityHolder(s *state, ref identityRef) *identityHolder { - ident, ok := s.identities[ref] +func getIdentityHolder(s *state, identity identity) *identityHolder { + ident, ok := s.identities[identity] if ok { return ident } - s.identities[ref] = newIdentityHolder(generateIdentity(s)) - return s.identities[ref] + s.identities[identity] = newIdentityHolder(generateIdentity(s)) + return s.identities[identity] } // getIdentityForRequest returns the identity for the given reference and node index. // It prepares the identity for a request by generating a token if needed, i.e. it will // return an identity with [Identity.BearerToken] set. -func getIdentityForRequest(s *state, ref identityRef, nodeIndex int) acpIdentity.Identity { - identHolder := getIdentityHolder(s, ref) +func getIdentityForRequest(s *state, identity identity, nodeIndex int) acpIdentity.Identity { + identHolder := getIdentityHolder(s, identity) ident := identHolder.Identity token, ok := identHolder.NodeTokens[nodeIndex] @@ -129,19 +162,30 @@ func generateIdentity(s *state) acpIdentity.Identity { func getContextWithIdentity( ctx context.Context, s *state, - ref immutable.Option[identityRef], + identity immutable.Option[identity], nodeIndex int, ) context.Context { - if !ref.HasValue() { + if !identity.HasValue() { return ctx } - ident := getIdentityForRequest(s, ref.Value(), nodeIndex) - return acpIdentity.WithContext(ctx, immutable.Some(ident)) + return acpIdentity.WithContext( + ctx, + immutable.Some( + getIdentityForRequest( + s, + identity.Value(), + nodeIndex, + ), + ), + ) } -func getIdentityDID(s *state, ref immutable.Option[identityRef]) string { - if ref.HasValue() { - return getIdentity(s, ref).DID +func getIdentityDID(s *state, identity immutable.Option[identity]) string { + if identity.HasValue() { + if identity.Value().selector == "*" { + return identity.Value().selector + } + return getIdentity(s, identity).DID } return "" } diff --git a/tests/integration/index/create_unique_composite_test.go b/tests/integration/index/create_unique_composite_test.go index 7a7e9fc5e0..88778d2e64 100644 --- a/tests/integration/index/create_unique_composite_test.go +++ b/tests/integration/index/create_unique_composite_test.go @@ -178,3 +178,79 @@ func TestUniqueCompositeIndexCreate_IfFieldValuesAreUnique_Succeed(t *testing.T) testUtils.ExecuteTestCase(t, test) } + +func TestUniqueCompositeIndexCreate_IfFieldValuesAreOrdered_Succeed(t *testing.T) { + test := testUtils.TestCase{ + Description: "create unique composite index if all docs have unique fields combinations", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + age: Int + email: String + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: ` + { + "name": "John", + "age": 21, + "email": "some@gmail.com" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: ` + { + "name": "John", + "age": 35, + "email": "another@gmail.com" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: ` + { + "name": "Andy", + "age": 35, + "email": "different@gmail.com" + }`, + }, + testUtils.CreateIndex{ + CollectionID: 0, + Fields: []testUtils.IndexedField{{Name: "name", Descending: true}, {Name: "age", Descending: false}, {Name: "email"}}, + IndexName: "name_age_unique_index", + Unique: true, + }, + testUtils.GetIndexes{ + CollectionID: 0, + ExpectedIndexes: []client.IndexDescription{ + { + Name: "name_age_unique_index", + ID: 1, + Unique: true, + Fields: []client.IndexedFieldDescription{ + { + Name: "name", + Descending: true, + }, + { + Name: "age", + Descending: false, + }, + { + Name: "email", + Descending: false, + }, + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/lens.go b/tests/integration/lens.go index c361c55342..fb002f076f 100644 --- a/tests/integration/lens.go +++ b/tests/integration/lens.go @@ -59,7 +59,7 @@ func configureMigration( ) { _, nodes := getNodesWithIDs(action.NodeID, s.nodes) for _, node := range nodes { - txn := getTransaction(s, node, action.TransactionID, action.ExpectedError) + txn := getTransaction(s, node.Client, action.TransactionID, action.ExpectedError) ctx := db.SetContextTxn(s.ctx, txn) err := node.SetMigration(ctx, action.LensConfig) diff --git a/tests/integration/mutation/create/field_kinds/field_kind_json_test.go b/tests/integration/mutation/create/field_kinds/field_kind_json_test.go index b578bf3928..5cb6fdd966 100644 --- a/tests/integration/mutation/create/field_kinds/field_kind_json_test.go +++ b/tests/integration/mutation/create/field_kinds/field_kind_json_test.go @@ -39,7 +39,6 @@ func TestMutationCreate_WithJSONFieldGivenObjectValue_Succeeds(t *testing.T) { testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -47,10 +46,9 @@ func TestMutationCreate_WithJSONFieldGivenObjectValue_Succeeds(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-a948a3b2-3e89-5654-b0f0-71685a66b4d7", "custom": map[string]any{ "tree": "maple", - "age": uint64(250), + "age": float64(250), }, "name": "John", }, @@ -84,7 +82,6 @@ func TestMutationCreate_WithJSONFieldGivenListOfScalarsValue_Succeeds(t *testing testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -92,8 +89,7 @@ func TestMutationCreate_WithJSONFieldGivenListOfScalarsValue_Succeeds(t *testing Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-90fd8b1b-bd11-56b5-a78c-2fb6f7b4dca0", - "custom": []any{"maple", uint64(250)}, + "custom": []any{"maple", float64(250)}, "name": "John", }, }, @@ -129,7 +125,6 @@ func TestMutationCreate_WithJSONFieldGivenListOfObjectsValue_Succeeds(t *testing testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -137,7 +132,6 @@ func TestMutationCreate_WithJSONFieldGivenListOfObjectsValue_Succeeds(t *testing Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-dd7c12f5-a7c5-55c6-8b35-ece853ae7f9e", "custom": []any{ map[string]any{"tree": "maple"}, map[string]any{"tree": "oak"}, @@ -174,7 +168,6 @@ func TestMutationCreate_WithJSONFieldGivenIntValue_Succeeds(t *testing.T) { testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -182,8 +175,7 @@ func TestMutationCreate_WithJSONFieldGivenIntValue_Succeeds(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-59731737-8793-5794-a9a5-0ed0ad696d5c", - "custom": uint64(250), + "custom": float64(250), "name": "John", }, }, @@ -216,7 +208,6 @@ func TestMutationCreate_WithJSONFieldGivenStringValue_Succeeds(t *testing.T) { testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -224,7 +215,6 @@ func TestMutationCreate_WithJSONFieldGivenStringValue_Succeeds(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-608582c3-979e-5f34-80f8-a70fce875d05", "custom": "hello", "name": "John", }, @@ -258,7 +248,6 @@ func TestMutationCreate_WithJSONFieldGivenBooleanValue_Succeeds(t *testing.T) { testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -266,7 +255,6 @@ func TestMutationCreate_WithJSONFieldGivenBooleanValue_Succeeds(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-0c4b39cf-433c-5a9c-9bed-1e2796c35d14", "custom": true, "name": "John", }, @@ -300,7 +288,6 @@ func TestMutationCreate_WithJSONFieldGivenNullValue_Succeeds(t *testing.T) { testUtils.Request{ Request: `query { Users { - _docID name custom } @@ -308,7 +295,6 @@ func TestMutationCreate_WithJSONFieldGivenNullValue_Succeeds(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "_docID": "bae-f405f600-56d9-5de4-8d02-75fdced35e3b", "custom": nil, "name": "John", }, diff --git a/tests/integration/p2p.go b/tests/integration/p2p.go index 87e224dce4..0123fc1787 100644 --- a/tests/integration/p2p.go +++ b/tests/integration/p2p.go @@ -156,8 +156,8 @@ func connectPeers( err := sourceNode.Connect(s.ctx, targetNode.PeerInfo()) require.NoError(s.t, err) - s.nodeP2P[cfg.SourceNodeID].connections[cfg.TargetNodeID] = struct{}{} - s.nodeP2P[cfg.TargetNodeID].connections[cfg.SourceNodeID] = struct{}{} + s.nodes[cfg.SourceNodeID].p2p.connections[cfg.TargetNodeID] = struct{}{} + s.nodes[cfg.TargetNodeID].p2p.connections[cfg.SourceNodeID] = struct{}{} // Bootstrap triggers a bunch of async stuff for which we have no good way of waiting on. It must be // allowed to complete before documentation begins or it will not even try and sync it. So for now, we @@ -219,7 +219,7 @@ func subscribeToCollection( continue } - col := s.collections[action.NodeID][collectionIndex] + col := s.nodes[action.NodeID].collections[collectionIndex] schemaRoots = append(schemaRoots, col.SchemaRoot()) } @@ -253,7 +253,7 @@ func unsubscribeToCollection( continue } - col := s.collections[action.NodeID][collectionIndex] + col := s.nodes[action.NodeID].collections[collectionIndex] schemaRoots = append(schemaRoots, col.SchemaRoot()) } @@ -281,7 +281,7 @@ func getAllP2PCollections( ) { expectedCollections := []string{} for _, collectionIndex := range action.ExpectedCollectionIDs { - col := s.collections[action.NodeID][collectionIndex] + col := s.nodes[action.NodeID].collections[collectionIndex] expectedCollections = append(expectedCollections, col.SchemaRoot()) } @@ -294,8 +294,8 @@ func getAllP2PCollections( // reconnectPeers makes sure that all peers are connected after a node restart action. func reconnectPeers(s *state) { - for i, n := range s.nodeP2P { - for j := range n.connections { + for i, n := range s.nodes { + for j := range n.p2p.connections { sourceNode := s.nodes[i] targetNode := s.nodes[j] diff --git a/tests/integration/query/commits/branchables/peer_index_test.go b/tests/integration/query/commits/branchables/peer_index_test.go new file mode 100644 index 0000000000..ab03eb3c56 --- /dev/null +++ b/tests/integration/query/commits/branchables/peer_index_test.go @@ -0,0 +1,68 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package branchables + +import ( + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryCommitsBranchables_SyncsIndexAcrossPeerConnection(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.RandomNetworkingConfig(), + testUtils.RandomNetworkingConfig(), + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String @index + } + `, + }, + testUtils.ConnectPeers{ + SourceNodeID: 1, + TargetNodeID: 0, + }, + testUtils.SubscribeToCollection{ + NodeID: 1, + CollectionIDs: []int{0}, + }, + testUtils.CreateDoc{ + NodeID: immutable.Some(0), + Doc: `{ + "name": "John" + }`, + }, + testUtils.WaitForSync{}, + testUtils.Request{ + // This query errors out if the document's index has not been correctly + // constructed + Request: `query { + Users (filter: {name: {_eq: "John"}}){ + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "John", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/commits/branchables/peer_test.go b/tests/integration/query/commits/branchables/peer_test.go index 81ff77a240..6d864ad9d1 100644 --- a/tests/integration/query/commits/branchables/peer_test.go +++ b/tests/integration/query/commits/branchables/peer_test.go @@ -18,8 +18,6 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -// TODO: This test documents an unimplemented feature. Tracked by: -// https://github.com/sourcenetwork/defradb/issues/3212 func TestQueryCommitsBranchables_SyncsAcrossPeerConnection(t *testing.T) { test := testUtils.TestCase{ Actions: []any{ @@ -50,15 +48,14 @@ func TestQueryCommitsBranchables_SyncsAcrossPeerConnection(t *testing.T) { }, testUtils.WaitForSync{}, testUtils.Request{ - NodeID: immutable.Some(0), Request: `query { - commits { - cid - links { + commits { cid + links { + cid + } } - } - }`, + }`, Results: map[string]any{ "commits": []map[string]any{ { @@ -91,35 +88,113 @@ func TestQueryCommitsBranchables_SyncsAcrossPeerConnection(t *testing.T) { }, }, }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestQueryCommitsBranchables_SyncsMultipleAcrossPeerConnection(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.RandomNetworkingConfig(), + testUtils.RandomNetworkingConfig(), + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + age: Int + } + `, + }, + testUtils.ConnectPeers{ + SourceNodeID: 1, + TargetNodeID: 0, + }, + testUtils.SubscribeToCollection{ + NodeID: 1, + CollectionIDs: []int{0}, + }, + testUtils.CreateDoc{ + NodeID: immutable.Some(0), + Doc: `{ + "name": "John", + "age": 21 + }`, + }, + testUtils.CreateDoc{ + NodeID: immutable.Some(0), + Doc: `{ + "name": "Fred", + "age": 25 + }`, + }, + testUtils.WaitForSync{}, testUtils.Request{ - NodeID: immutable.Some(1), Request: `query { - commits { - cid - links { + commits { cid + links { + cid + } } - } - }`, + }`, Results: map[string]any{ "commits": []map[string]any{ - // Note: The collection commit has not synced. { - "cid": testUtils.NewUniqueCid("age"), + "cid": testUtils.NewUniqueCid("collection, doc2 create"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, doc1 create"), + }, + { + "cid": testUtils.NewUniqueCid("doc2 create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("collection, doc1 create"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc1 create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc1 name"), "links": []map[string]any{}, }, { - "cid": testUtils.NewUniqueCid("name"), + "cid": testUtils.NewUniqueCid("doc1 age"), "links": []map[string]any{}, }, { - "cid": testUtils.NewUniqueCid("composite"), + "cid": testUtils.NewUniqueCid("doc1 create"), "links": []map[string]any{ { - "cid": testUtils.NewUniqueCid("age"), + "cid": testUtils.NewUniqueCid("doc1 name"), }, { - "cid": testUtils.NewUniqueCid("name"), + "cid": testUtils.NewUniqueCid("doc1 age"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc2 name"), + "links": []map[string]any{}, + }, + { + "cid": testUtils.NewUniqueCid("doc2 age"), + "links": []map[string]any{}, + }, + { + "cid": testUtils.NewUniqueCid("doc2 create"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc2 name"), + }, + { + "cid": testUtils.NewUniqueCid("doc2 age"), }, }, }, diff --git a/tests/integration/query/commits/branchables/peer_update_test.go b/tests/integration/query/commits/branchables/peer_update_test.go new file mode 100644 index 0000000000..01789a3bc4 --- /dev/null +++ b/tests/integration/query/commits/branchables/peer_update_test.go @@ -0,0 +1,260 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package branchables + +import ( + "testing" + + "github.com/sourcenetwork/immutable" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryCommitsBranchables_HandlesConcurrentUpdatesAcrossPeerConnection(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.RandomNetworkingConfig(), + testUtils.RandomNetworkingConfig(), + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.UpdateDoc{ + NodeID: immutable.Some(0), + Doc: `{ + "name": "Fred" + }`, + }, + testUtils.UpdateDoc{ + NodeID: immutable.Some(1), + Doc: `{ + "name": "Shahzad" + }`, + }, + testUtils.ConnectPeers{ + SourceNodeID: 1, + TargetNodeID: 0, + }, + testUtils.WaitForSync{}, + testUtils.UpdateDoc{ + // Update node 1 after the peer connection has been established, this will cause the `Shahzad` commit + // to be synced to node 0, as well as the related collection commits. + NodeID: immutable.Some(1), + Doc: `{ + "name": "Chris" + }`, + }, + testUtils.WaitForSync{}, + testUtils.UpdateDoc{ + // Update node 0 after `Chris` and `Shahzad` have synced to node 0. As this update happens after the peer + // connection has been established, this will cause the `Fred` and `Addo` doc commits, and their corresponding + // collection-level commits to sync to node 1. + // + // Now, all nodes should have a full history, including the 'offline' changes made before establishing the + // peer connection. + NodeID: immutable.Some(0), + Doc: `{ + "name": "Addo" + }`, + }, + testUtils.WaitForSync{}, + testUtils.Request{ + // Strong eventual consistency must now have been established across both nodes, the result of this query + // *must* exactly match across both nodes. + Request: `query { + commits { + cid + links { + cid + } + } + }`, + Results: map[string]any{ + "commits": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, node0 update3"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, node1 update2"), + }, + { + "cid": testUtils.NewUniqueCid("collection, node1 update1"), + }, + { + "cid": testUtils.NewUniqueCid("doc, node0 update3"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("collection, node1 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, create"), + }, + { + "cid": testUtils.NewUniqueCid("doc, node1 update1"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("collection, create"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc, create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("collection, node1 update2"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, node0 update1"), + }, + { + "cid": testUtils.NewUniqueCid("doc, node1 update2"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("collection, node0 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("collection, create"), + }, + { + "cid": testUtils.NewUniqueCid("doc, node0 update1"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("name, node0 update3"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("name, node1 update1"), + }, + { + "cid": testUtils.NewUniqueCid("name, node1 update2"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("name, node1 update2"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("name, node0 update1"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("name, node0 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("name, create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("name, create"), + "links": []map[string]any{}, + }, + { + "cid": testUtils.NewUniqueCid("name, node1 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("name, create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc, node0 update3"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc, node1 update2"), + }, + { + "cid": testUtils.NewUniqueCid("doc, node1 update1"), + }, + { + "cid": testUtils.NewUniqueCid("name, node0 update3"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc, node1 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc, create"), + }, + { + "cid": testUtils.NewUniqueCid("name, node1 update1"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc, create"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("name, create"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc, node1 update2"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc, node0 update1"), + }, + { + "cid": testUtils.NewUniqueCid("name, node1 update2"), + }, + }, + }, + { + "cid": testUtils.NewUniqueCid("doc, node0 update1"), + "links": []map[string]any{ + { + "cid": testUtils.NewUniqueCid("doc, create"), + }, + { + "cid": testUtils.NewUniqueCid("name, node0 update1"), + }, + }, + }, + }, + }, + }, + testUtils.Request{ + Request: `query { + Users { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Addo", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/inline_array/with_max_doc_id_test.go b/tests/integration/query/inline_array/with_max_doc_id_test.go index 3a473db9f2..449d673073 100644 --- a/tests/integration/query/inline_array/with_max_doc_id_test.go +++ b/tests/integration/query/inline_array/with_max_doc_id_test.go @@ -16,7 +16,7 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -// This test is meant to provide coverage of the planNode.Spans +// This test is meant to provide coverage of the planNode.Prefixes // func by targeting a specific docID in the parent select. func TestQueryInlineNillableFloatArray_WithDocIDAndMax_Succeeds(t *testing.T) { test := testUtils.TestCase{ diff --git a/tests/integration/query/inline_array/with_min_doc_id_test.go b/tests/integration/query/inline_array/with_min_doc_id_test.go index b8ad3d2c98..0c34388a36 100644 --- a/tests/integration/query/inline_array/with_min_doc_id_test.go +++ b/tests/integration/query/inline_array/with_min_doc_id_test.go @@ -16,7 +16,7 @@ import ( testUtils "github.com/sourcenetwork/defradb/tests/integration" ) -// This test is meant to provide coverage of the planNode.Spans +// This test is meant to provide coverage of the planNode.Prefixes // func by targeting a specific docID in the parent select. func TestQueryInlineNillableFloatArray_WithDocIDAndMin_Succeeds(t *testing.T) { test := testUtils.TestCase{ diff --git a/tests/integration/query/json/with_ge_test.go b/tests/integration/query/json/with_ge_test.go index bfb574170e..4a9afc403e 100644 --- a/tests/integration/query/json/with_ge_test.go +++ b/tests/integration/query/json/with_ge_test.go @@ -270,10 +270,10 @@ func TestQueryJSON_WithGreaterEqualFilterWithNestedNullValue_ShouldFilter(t *tes Results: map[string]any{ "Users": []map[string]any{ { - "Name": "John", + "Name": "David", }, { - "Name": "David", + "Name": "John", }, }, }, diff --git a/tests/integration/query/json/with_gt_test.go b/tests/integration/query/json/with_gt_test.go index 3a2972320b..07d08ce7ca 100644 --- a/tests/integration/query/json/with_gt_test.go +++ b/tests/integration/query/json/with_gt_test.go @@ -182,7 +182,7 @@ func TestQueryJSON_WithGreaterThanFilterBlockWithNestedGreaterValue_ShouldFilter { "Name": "John", "Custom": map[string]any{ - "age": uint64(21), + "age": float64(21), }, }, }, diff --git a/tests/integration/query/json/with_lt_test.go b/tests/integration/query/json/with_lt_test.go index 14a422d5ad..636139c05d 100644 --- a/tests/integration/query/json/with_lt_test.go +++ b/tests/integration/query/json/with_lt_test.go @@ -178,7 +178,7 @@ func TestQueryJSON_WithLesserThanFilterBlockWithNestedGreaterValue_ShouldFilter( { "Name": "Bob", "Custom": map[string]any{ - "age": uint64(19), + "age": float64(19), }, }, }, diff --git a/tests/integration/query/json/with_nlike_test.go b/tests/integration/query/json/with_nlike_test.go index db0615b2ca..6de741f61b 100644 --- a/tests/integration/query/json/with_nlike_test.go +++ b/tests/integration/query/json/with_nlike_test.go @@ -65,16 +65,16 @@ func TestQueryJSON_WithNotLikeFilter_ShouldFilter(t *testing.T) { Results: map[string]any{ "Users": []map[string]any{ { - "custom": uint64(32), + "custom": map[string]any{"one": float64(1)}, }, { - "custom": "Viserys I Targaryen, King of the Andals", + "custom": float64(32), }, { - "custom": map[string]any{"one": uint64(1)}, + "custom": []any{float64(1), float64(2)}, }, { - "custom": []any{uint64(1), uint64(2)}, + "custom": "Viserys I Targaryen, King of the Andals", }, { "custom": false, diff --git a/tests/integration/query/one_to_many/with_count_order_test.go b/tests/integration/query/one_to_many/with_count_order_test.go new file mode 100644 index 0000000000..11b26ae396 --- /dev/null +++ b/tests/integration/query/one_to_many/with_count_order_test.go @@ -0,0 +1,87 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package one_to_many + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryOneToMany_WithCountAliasOrder_ShouldOrderResults(t *testing.T) { + test := testUtils.TestCase{ + Description: "One-to-many relation query from many side with order alias", + Actions: []any{ + testUtils.CreateDoc{ + CollectionID: 1, + Doc: `{ + "name": "John Grisham", + "age": 65, + "verified": true + }`, + }, + testUtils.CreateDoc{ + CollectionID: 1, + Doc: `{ + "name": "Cornelia Funke", + "age": 62, + "verified": false + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "Painted House", + "rating": 4.9, + "author_id": testUtils.NewDocIndex(1, 0), + }, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "A Time for Mercy", + "rating": 4.5, + "author_id": testUtils.NewDocIndex(1, 0), + }, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "Theif Lord", + "rating": 4.8, + "author_id": testUtils.NewDocIndex(1, 1), + }, + }, + testUtils.Request{ + Request: `query { + Author(order: {_alias: {publishedCount: DESC}}) { + name + publishedCount: _count(published: {}) + } + }`, + Results: map[string]any{ + "Author": []map[string]any{ + { + "name": "John Grisham", + "publishedCount": int64(2), + }, + { + "name": "Cornelia Funke", + "publishedCount": int64(1), + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/query/one_to_many/with_sum_order_test.go b/tests/integration/query/one_to_many/with_sum_order_test.go new file mode 100644 index 0000000000..4c6c7aa0bf --- /dev/null +++ b/tests/integration/query/one_to_many/with_sum_order_test.go @@ -0,0 +1,95 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package one_to_many + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQueryOneToMany_WithSumWithAliasOrder_ShouldOrderResults(t *testing.T) { + test := testUtils.TestCase{ + Description: "One-to-many relation query from many side with sum with order alias", + Actions: []any{ + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "Painted House", + "rating": 4.9, + "author_id": "bae-e1ea288f-09fa-55fa-b0b5-0ac8941ea35b" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "A Time for Mercy", + "rating": 4.5, + "author_id": "bae-e1ea288f-09fa-55fa-b0b5-0ac8941ea35b" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "The Associate", + "rating": 4.2, + "author_id": "bae-e1ea288f-09fa-55fa-b0b5-0ac8941ea35b" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 0, + Doc: `{ + "name": "Theif Lord", + "rating": 4.8, + "author_id": "bae-72e8c691-9f20-55e7-9228-8af1cf54cace" + }`, + }, + testUtils.CreateDoc{ + CollectionID: 1, + Doc: `{ + "name": "John Grisham", + "age": 65, + "verified": true + }`, + }, + testUtils.CreateDoc{ + CollectionID: 1, + Doc: `{ + "name": "Cornelia Funke", + "age": 62, + "verified": false + }`, + }, + testUtils.Request{ + Request: `query { + Author(order: {_alias: {totalRating: DESC}}) { + name + totalRating: _sum(published: {field: rating}) + } + }`, + Results: map[string]any{ + "Author": []map[string]any{ + { + "name": "John Grisham", + "totalRating": 13.600000000000001, + }, + { + "name": "Cornelia Funke", + "totalRating": 4.8, + }, + }, + }, + }, + }, + } + + executeTestCase(t, test) +} diff --git a/tests/integration/query/simple/simple_test.go b/tests/integration/query/simple/simple_test.go index eff5b09d65..98e8bca42a 100644 --- a/tests/integration/query/simple/simple_test.go +++ b/tests/integration/query/simple/simple_test.go @@ -214,3 +214,81 @@ func TestQuerySimpleWithDefaultValue(t *testing.T) { executeTestCase(t, test) } + +// This test is to ensure that deleted docs from the next collection ID are not returned in the query results. +// It documents the fixing of the bug described in #3242. +func TestQuerySimple_WithDeletedDocsInCollection2_ShouldNotYieldDeletedDocsOnCollection1Query(t *testing.T) { + test := testUtils.TestCase{ + Description: "Deleted docs in collection 2 should not yield deleted docs on collection 1 query", + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type User { + name: String + } + type Friend { + name: String + } + `, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "Shahzad", + }, + }, + testUtils.CreateDoc{ + CollectionID: 0, + DocMap: map[string]any{ + "name": "John", + }, + }, + testUtils.CreateDoc{ + CollectionID: 1, + DocMap: map[string]any{ + "name": "Andy", + }, + }, + testUtils.Request{ + Request: `query { + User { + _docID + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + { + "_docID": testUtils.NewDocIndex(0, 1), + }, + { + "_docID": testUtils.NewDocIndex(0, 0), + }, + }, + }, + }, + testUtils.DeleteDoc{ + CollectionID: 1, + DocID: 0, + }, + testUtils.Request{ + Request: `query { + User { + _docID + } + }`, + Results: map[string]any{ + "User": []map[string]any{ + { + "_docID": testUtils.NewDocIndex(0, 1), + }, + { + "_docID": testUtils.NewDocIndex(0, 0), + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_cid_branchable_test.go b/tests/integration/query/simple/with_cid_branchable_test.go new file mode 100644 index 0000000000..58590a5d5a --- /dev/null +++ b/tests/integration/query/simple/with_cid_branchable_test.go @@ -0,0 +1,161 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimpleWithCidOfBranchableCollection_FirstCid(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred" + }`, + }, + testUtils.UpdateDoc{ + Doc: `{ + "name": "Freddddd" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.Request{ + Request: `query { + Users ( + cid: "bafyreiewwsnu2ld5qlntamdm77ayb7xtmxz3p5difvaaakaome7zbtpo4u" + ) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestQuerySimpleWithCidOfBranchableCollection_MiddleCid(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred" + }`, + }, + testUtils.UpdateDoc{ + Doc: `{ + "name": "Freddddd" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.Request{ + Request: `query { + Users ( + cid: "bafyreifpamlyhcbriztgbhds5ctgi5rm6w5wcar2py7246lo6j5v7iusxm" + ) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Freddddd", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} + +func TestQuerySimpleWithCidOfBranchableCollection_LastCid(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred" + }`, + }, + testUtils.UpdateDoc{ + Doc: `{ + "name": "Freddddd" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.Request{ + Request: `query { + Users ( + cid: "bafyreigmt6ytph32jjxts2bij7fkne5ntionldsnklp35vcamvvl2x3a5i" + ) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Freddddd", + }, + { + "name": "John", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_cid_doc_id_branchable_test.go b/tests/integration/query/simple/with_cid_doc_id_branchable_test.go new file mode 100644 index 0000000000..18b8a55ad6 --- /dev/null +++ b/tests/integration/query/simple/with_cid_doc_id_branchable_test.go @@ -0,0 +1,67 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package simple + +import ( + "testing" + + testUtils "github.com/sourcenetwork/defradb/tests/integration" +) + +func TestQuerySimpleWithCidOfBranchableCollectionAndDocID(t *testing.T) { + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users @branchable { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred" + }`, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.UpdateDoc{ + Doc: `{ + "name": "Freddddd" + }`, + }, + testUtils.Request{ + // This is the cid of the collection-commit when the second doc (John) is created. + // Without the docID param both John and Fred should be returned. + Request: `query { + Users ( + cid: "bafyreiboen2mw2unu4fty2pyyd5nicqi57vcdahrrag6bjm54md5myj54u", + docID: "bae-3a7df128-bfa9-559a-a9c5-96f2bf6d1038" + ) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "Fred", + }, + }, + }, + }, + }, + } + + testUtils.ExecuteTestCase(t, test) +} diff --git a/tests/integration/query/simple/with_cid_doc_id_test.go b/tests/integration/query/simple/with_cid_doc_id_test.go index 8c6476b1e5..29a630ac19 100644 --- a/tests/integration/query/simple/with_cid_doc_id_test.go +++ b/tests/integration/query/simple/with_cid_doc_id_test.go @@ -335,7 +335,7 @@ func TestCidAndDocIDQuery_ContainsPNCounterWithIntKind_NoError(t *testing.T) { Request: `query { Users ( cid: "bafyreihsqayh6zvmjrvmma3sjmrb4bkeiyy6l56nt6y2t2tm4xajkif3gu", - docID: "bae-d8cb53d4-ac5a-5c55-8306-64df633d400d" + docID: "bae-bc5464e4-26a6-5307-b516-aada0abeb089" ) { name points @@ -389,7 +389,7 @@ func TestCidAndDocIDQuery_ContainsPNCounterWithFloatKind_NoError(t *testing.T) { Request: `query { Users ( cid: "bafyreigkdjnvkpqfjoqoke3aqc3b6ibb45xjuxx5djpk7c6tart2lw3dcm", - docID: "bae-d420ebcd-023a-5800-ae2e-8ea89442318e" + docID: "bae-2c7c40a7-92c1-5ed4-8a00-9e8595514945" ) { name points diff --git a/tests/integration/query/simple/with_cid_test.go b/tests/integration/query/simple/with_cid_test.go index e4c07987e0..4bf6d5e224 100644 --- a/tests/integration/query/simple/with_cid_test.go +++ b/tests/integration/query/simple/with_cid_test.go @@ -13,10 +13,6 @@ package simple import ( "testing" - "github.com/sourcenetwork/immutable" - "github.com/stretchr/testify/require" - - "github.com/sourcenetwork/defradb/tests/change_detector" testUtils "github.com/sourcenetwork/defradb/tests/integration" ) @@ -44,20 +40,45 @@ func TestQuerySimpleWithInvalidCid(t *testing.T) { executeTestCase(t, test) } -// This test documents a bug: -// https://github.com/sourcenetwork/defradb/issues/3214 func TestQuerySimpleWithCid(t *testing.T) { - if change_detector.Enabled { - t.Skipf("Change detector does not support requiring panics") + test := testUtils.TestCase{ + Actions: []any{ + testUtils.SchemaUpdate{ + Schema: ` + type Users { + name: String + } + `, + }, + testUtils.CreateDoc{ + Doc: `{ + "name": "John" + }`, + }, + testUtils.Request{ + Request: `query { + Users ( + cid: "bafyreib7afkd5hepl45wdtwwpai433bhnbd3ps5m2rv3masctda7b6mmxe" + ) { + name + } + }`, + Results: map[string]any{ + "Users": []map[string]any{ + { + "name": "John", + }, + }, + }, + }, + }, } + testUtils.ExecuteTestCase(t, test) +} + +func TestQuerySimpleWithCid_MultipleDocs(t *testing.T) { test := testUtils.TestCase{ - SupportedClientTypes: immutable.Some( - []testUtils.ClientType{ - // The CLI/Http clients don't panic in this context - testUtils.GoClientType, - }, - ), Actions: []any{ testUtils.SchemaUpdate{ Schema: ` @@ -71,6 +92,11 @@ func TestQuerySimpleWithCid(t *testing.T) { "name": "John" }`, }, + testUtils.CreateDoc{ + Doc: `{ + "name": "Fred" + }`, + }, testUtils.Request{ Request: `query { Users ( @@ -90,7 +116,5 @@ func TestQuerySimpleWithCid(t *testing.T) { }, } - require.Panics(t, func() { - testUtils.ExecuteTestCase(t, test) - }) + testUtils.ExecuteTestCase(t, test) } diff --git a/tests/integration/schema/migrations/query/with_doc_id_test.go b/tests/integration/schema/migrations/query/with_doc_id_test.go index bb28b90ac8..73258cf932 100644 --- a/tests/integration/schema/migrations/query/with_doc_id_test.go +++ b/tests/integration/schema/migrations/query/with_doc_id_test.go @@ -20,7 +20,7 @@ import ( "github.com/sourcenetwork/defradb/tests/lenses" ) -// This test asserts that spans are being passed correctly through the new Lens fetcher. +// This test asserts that prefixes are being passed correctly through the new Lens fetcher. func TestSchemaMigrationQueryByDocID(t *testing.T) { test := testUtils.TestCase{ Description: "Test schema migration, query by docID", diff --git a/tests/integration/state.go b/tests/integration/state.go index e7130f2ebd..a1085b94b9 100644 --- a/tests/integration/state.go +++ b/tests/integration/state.go @@ -42,15 +42,21 @@ type p2pState struct { // The map key is the node id of the subscriber. peerCollections map[int]struct{} - // actualDocHeads contains all document heads that exist on a node. + // actualDAGHeads contains all DAG heads that exist on a node. // // The map key is the doc id. The map value is the doc head. - actualDocHeads map[string]docHeadState + // + // This tracks composite commits for documents, and collection commits for + // branchable collections + actualDAGHeads map[string]docHeadState - // expectedDocHeads contains all document heads that are expected to exist on a node. + // expectedDAGHeads contains all DAG heads that are expected to exist on a node. // - // The map key is the doc id. The map value is the doc head. - expectedDocHeads map[string]cid.Cid + // The map key is the doc id. The map value is the DAG head. + // + // This tracks composite commits for documents, and collection commits for + // branchable collections + expectedDAGHeads map[string]cid.Cid } // docHeadState contains the state of a document head. @@ -68,8 +74,8 @@ func newP2PState() *p2pState { connections: make(map[int]struct{}), replicators: make(map[int]struct{}), peerCollections: make(map[int]struct{}), - actualDocHeads: make(map[string]docHeadState), - expectedDocHeads: make(map[string]cid.Cid), + actualDAGHeads: make(map[string]docHeadState), + expectedDAGHeads: make(map[string]cid.Cid), } } @@ -114,6 +120,30 @@ func newEventState(bus *event.Bus) (*eventState, error) { }, nil } +// nodeState contains all testing state for a node. +type nodeState struct { + // The node's client active in this test. + clients.Client + // event contains all event node subscriptions. + event *eventState + // p2p contains p2p states for the node. + p2p *p2pState + // The network configurations for the nodes + netOpts []net.NodeOpt + // The path to any file-based databases active in this test. + dbPath string + // Collections by index present in the test. + // Indexes matches that of collectionNames. + collections []client.Collection + // Indexes, by index, by collection index. + indexes [][]client.IndexDescription + // indicates if the node is closed. + closed bool + // peerInfo contains the peer information for the node. + peerInfo peer.AddrInfo +} + +// state contains all testing state. type state struct { // The test context. ctx context.Context @@ -124,6 +154,7 @@ type state struct { // The TestCase currently being executed. testCase TestCase + // The type of KMS currently being tested. kms KMSType // The type of database currently being tested. @@ -142,7 +173,7 @@ type state struct { // types. See [identRef]. // The map value is the identity holder that contains the identity itself and token // generated for different target nodes. See [identityHolder]. - identities map[identityRef]*identityHolder + identities map[identity]*identityHolder // The seed for the next identity generation. We want identities to be deterministic. nextIdentityGenSeed int @@ -153,30 +184,11 @@ type state struct { // These channels will receive a function which asserts results of any subscription requests. subscriptionResultsChans []chan func() - // nodeEvents contains all event node subscriptions. - nodeEvents []*eventState - - // The addresses of any nodes configured. - nodeAddresses []peer.AddrInfo - - // The configurations for any nodes - nodeConfigs [][]net.NodeOpt - // The nodes active in this test. - nodes []clients.Client + nodes []*nodeState - // closedNodes contains the indexes of nodes that have been closed. - closedNodes map[int]struct{} - - // nodeP2P contains p2p states for all nodes - nodeP2P []*p2pState - - // The paths to any file-based databases active in this test. - dbPaths []string - - // Collections by index, by nodeID present in the test. - // Indexes matches that of collectionNames. - collections [][]client.Collection + // The ACP options to share between each node. + acpOptions []node.ACPOpt // The names of the collections active in this test. // Indexes matches that of initial collections. @@ -196,17 +208,14 @@ type state struct { // Valid Cid string values by [UniqueCid] ID. cids map[any]string - // Indexes, by index, by collection index, by node index. - indexes [][][]client.IndexDescription - // isBench indicates wether the test is currently being benchmarked. isBench bool // The SourceHub address used to pay for SourceHub transactions. sourcehubAddress string - // The ACP options to share between each node. - acpOptions []node.ACPOpt + // isNetworkEnabled indicates whether the network is enabled. + isNetworkEnabled bool } // newState returns a new fresh state for the given testCase. @@ -228,21 +237,12 @@ func newState( clientType: clientType, txns: []datastore.Txn{}, allActionsDone: make(chan struct{}), - identities: map[identityRef]*identityHolder{}, + identities: map[identity]*identityHolder{}, subscriptionResultsChans: []chan func(){}, - nodeEvents: []*eventState{}, - nodeAddresses: []peer.AddrInfo{}, - nodeConfigs: [][]net.NodeOpt{}, - nodeP2P: []*p2pState{}, - nodes: []clients.Client{}, - closedNodes: map[int]struct{}{}, - dbPaths: []string{}, - collections: [][]client.Collection{}, collectionNames: collectionNames, collectionIndexesByRoot: map[uint32]int{}, docIDs: [][]client.DocID{}, cids: map[any]string{}, - indexes: [][][]client.IndexDescription{}, isBench: false, } } diff --git a/tests/integration/test_case.go b/tests/integration/test_case.go index a1ab291257..2e7eaaa5ea 100644 --- a/tests/integration/test_case.go +++ b/tests/integration/test_case.go @@ -297,7 +297,7 @@ type CreateDoc struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // Specifies whether the document should be encrypted. IsDocEncrypted bool @@ -369,7 +369,7 @@ type DeleteDoc struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // The collection in which this document should be deleted. CollectionID int @@ -402,7 +402,7 @@ type UpdateDoc struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // The collection in which this document exists. CollectionID int @@ -445,7 +445,7 @@ type UpdateWithFilter struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // The collection in which this document exists. CollectionID int @@ -602,7 +602,7 @@ type Request struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - Identity immutable.Option[identityRef] + Identity immutable.Option[identity] // Used to identify the transaction for this to run against. Optional. TransactionID immutable.Option[int] @@ -805,7 +805,7 @@ type GetNodeIdentity struct { // // Use `UserIdentity` to create a user identity and `NodeIdentity` to create a node identity. // Default value is `NoIdentity()`. - ExpectedIdentity immutable.Option[identityRef] + ExpectedIdentity immutable.Option[identity] } // Wait is an action that will wait for the given duration. diff --git a/tests/integration/utils.go b/tests/integration/utils.go index f827ac0130..bf3daffff3 100644 --- a/tests/integration/utils.go +++ b/tests/integration/utils.go @@ -41,7 +41,6 @@ import ( "github.com/sourcenetwork/defradb/net" "github.com/sourcenetwork/defradb/node" changeDetector "github.com/sourcenetwork/defradb/tests/change_detector" - "github.com/sourcenetwork/defradb/tests/clients" "github.com/sourcenetwork/defradb/tests/gen" "github.com/sourcenetwork/defradb/tests/predefined" ) @@ -115,7 +114,6 @@ func init() { // mutation type. mutationType = CollectionSaveMutationType } - mutationType = GQLRequestMutationType if value, ok := os.LookupEnv(viewTypeEnvName); ok { viewType = ViewType(value) @@ -442,7 +440,7 @@ func createGenerateDocs(s *state, docs []gen.GeneratedDoc, nodeID immutable.Opti func generateDocs(s *state, action GenerateDocs) { nodeIDs, _ := getNodesWithIDs(action.NodeID, s.nodes) firstNodesID := nodeIDs[0] - collections := s.collections[firstNodesID] + collections := s.nodes[firstNodesID].collections defs := make([]client.CollectionDefinition, 0, len(collections)) for _, collection := range collections { if len(action.ForCollections) == 0 || slices.Contains(action.ForCollections, collection.Name().Value()) { @@ -459,7 +457,7 @@ func generateDocs(s *state, action GenerateDocs) { func generatePredefinedDocs(s *state, action CreatePredefinedDocs) { nodeIDs, _ := getNodesWithIDs(action.NodeID, s.nodes) firstNodesID := nodeIDs[0] - collections := s.collections[firstNodesID] + collections := s.nodes[firstNodesID].collections defs := make([]client.CollectionDefinition, 0, len(collections)) for _, col := range collections { defs = append(defs, col.Definition()) @@ -577,10 +575,10 @@ func closeNodes( s *state, action Close, ) { - nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) - for i, node := range nodes { + _, nodes := getNodesWithIDs(action.NodeID, s.nodes) + for _, node := range nodes { node.Close() - s.closedNodes[nodeIDs[i]] = struct{}{} + node.closed = true } } @@ -594,7 +592,7 @@ func closeNodes( // greater than 0. For example if requesting a node with nodeID=2 then the resulting output will contain only // one element (at index 0) caller might accidentally assume that this node belongs to node 0. Therefore, the // caller should always use the returned IDs, instead of guessing the IDs based on node indexes. -func getNodesWithIDs(nodeID immutable.Option[int], nodes []clients.Client) ([]int, []clients.Client) { +func getNodesWithIDs(nodeID immutable.Option[int], nodes []*nodeState) ([]int, []*nodeState) { if !nodeID.HasValue() { indexes := make([]int, len(nodes)) for i := range nodes { @@ -603,7 +601,7 @@ func getNodesWithIDs(nodeID immutable.Option[int], nodes []clients.Client) ([]in return indexes, nodes } - return []int{nodeID.Value()}, []clients.Client{nodes[nodeID.Value()]} + return []int{nodeID.Value()}, []*nodeState{nodes[nodeID.Value()]} } func calculateLenForFlattenedActions(testCase *TestCase) int { @@ -711,83 +709,44 @@ ActionLoop: func setStartingNodes( s *state, ) { - hasExplicitNode := false for _, action := range s.testCase.Actions { switch action.(type) { case ConfigureNode: - hasExplicitNode = true + s.isNetworkEnabled = true } } // If nodes have not been explicitly configured via actions, setup a default one. - if !hasExplicitNode { - node, path, err := setupNode(s) + if !s.isNetworkEnabled { + st, err := setupNode(s) require.Nil(s.t, err) - - c, err := setupClient(s, node) - require.Nil(s.t, err) - - eventState, err := newEventState(c.Events()) - require.NoError(s.t, err) - - s.nodes = append(s.nodes, c) - s.nodeEvents = append(s.nodeEvents, eventState) - s.nodeP2P = append(s.nodeP2P, newP2PState()) - s.dbPaths = append(s.dbPaths, path) + s.nodes = append(s.nodes, st) } } func startNodes(s *state, action Start) { - _, nodes := getNodesWithIDs(action.NodeID, s.nodes) + nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) // We need to restart the nodes in reverse order, to avoid dial backoff issues. for i := len(nodes) - 1; i >= 0; i-- { - nodeIndex := i - if action.NodeID.HasValue() { - nodeIndex = action.NodeID.Value() - } + nodeIndex := nodeIDs[i] originalPath := databaseDir - databaseDir = s.dbPaths[nodeIndex] - node, _, err := setupNode(s, db.WithNodeIdentity(getIdentity(s, NodeIdentity(nodeIndex)))) - require.NoError(s.t, err) - databaseDir = originalPath - - if len(s.nodeConfigs) == 0 { - // If there are no explicit node configuration actions the node will be - // basic (i.e. no P2P stuff) and can be yielded now. - c, err := setupClient(s, node) - require.NoError(s.t, err) - s.nodes[nodeIndex] = c - - eventState, err := newEventState(c.Events()) - require.NoError(s.t, err) - s.nodeEvents[nodeIndex] = eventState - continue + databaseDir = s.nodes[nodeIndex].dbPath + opts := []node.Option{db.WithNodeIdentity(getIdentity(s, NodeIdentity(nodeIndex)))} + for _, opt := range s.nodes[nodeIndex].netOpts { + opts = append(opts, opt) } - - // We need to make sure the node is configured with its old address, otherwise - // a new one may be selected and reconnection to it will fail. var addresses []string - for _, addr := range s.nodeAddresses[nodeIndex].Addrs { + for _, addr := range s.nodes[nodeIndex].peerInfo.Addrs { addresses = append(addresses, addr.String()) } - - nodeOpts := s.nodeConfigs[nodeIndex] - nodeOpts = append(nodeOpts, net.WithListenAddresses(addresses...)) - - node.Peer, err = net.NewPeer(s.ctx, node.DB.Blockstore(), node.DB.Encstore(), node.DB.Events(), nodeOpts...) - require.NoError(s.t, err) - - c, err := setupClient(s, node) + opts = append(opts, net.WithListenAddresses(addresses...)) + node, err := setupNode(s, opts...) require.NoError(s.t, err) - s.nodes[nodeIndex] = c - - eventState, err := newEventState(c.Events()) - require.NoError(s.t, err) - s.nodeEvents[nodeIndex] = eventState - - delete(s.closedNodes, nodeIndex) + databaseDir = originalPath + node.p2p = s.nodes[nodeIndex].p2p + s.nodes[nodeIndex] = node - waitForNetworkSetupEvents(s, i) + waitForNetworkSetupEvents(s, nodeIndex) } // If the db was restarted we need to refresh the collection definitions as the old instances @@ -814,10 +773,8 @@ func restartNodes( func refreshCollections( s *state, ) { - s.collections = make([][]client.Collection, len(s.nodes)) - - for nodeID, node := range s.nodes { - s.collections[nodeID] = make([]client.Collection, len(s.collectionNames)) + for _, node := range s.nodes { + node.collections = make([]client.Collection, len(s.collectionNames)) allCollections, err := node.GetCollections(s.ctx, client.CollectionFetchOptions{}) require.Nil(s.t, err) @@ -838,7 +795,7 @@ func refreshCollections( for _, collection := range allCollections { if index, ok := s.collectionIndexesByRoot[collection.Description().RootID]; ok { - s.collections[nodeID][index] = collection + node.collections[index] = collection } } } @@ -864,35 +821,23 @@ func configureNode( netNodeOpts := action() netNodeOpts = append(netNodeOpts, net.WithPrivateKey(privateKey)) - nodeOpts := []node.Option{node.WithDisableP2P(false), db.WithRetryInterval([]time.Duration{time.Millisecond * 1})} + nodeOpts := []node.Option{db.WithRetryInterval([]time.Duration{time.Millisecond * 1})} for _, opt := range netNodeOpts { nodeOpts = append(nodeOpts, opt) } nodeOpts = append(nodeOpts, db.WithNodeIdentity(getIdentity(s, NodeIdentity(len(s.nodes))))) - node, path, err := setupNode(s, nodeOpts...) //disable change detector, or allow it? - require.NoError(s.t, err) - - s.nodeAddresses = append(s.nodeAddresses, node.Peer.PeerInfo()) - s.nodeConfigs = append(s.nodeConfigs, netNodeOpts) - - c, err := setupClient(s, node) - require.NoError(s.t, err) - - eventState, err := newEventState(c.Events()) + node, err := setupNode(s, nodeOpts...) //disable change detector, or allow it? require.NoError(s.t, err) - s.nodes = append(s.nodes, c) - s.nodeEvents = append(s.nodeEvents, eventState) - s.nodeP2P = append(s.nodeP2P, newP2PState()) - s.dbPaths = append(s.dbPaths, path) + s.nodes = append(s.nodes, node) } func refreshDocuments( s *state, startActionIndex int, ) { - if len(s.collections) == 0 { + if len(s.nodes) == 0 { // This should only be possible at the moment for P2P testing, for which the // change detector is currently disabled. We'll likely need some fancier logic // here if/when we wish to enable it. @@ -902,9 +847,9 @@ func refreshDocuments( // For now just do the initial setup using the collections on the first node, // this may need to become more involved at a later date depending on testing // requirements. - s.docIDs = make([][]client.DocID, len(s.collections[0])) + s.docIDs = make([][]client.DocID, len(s.nodes[0].collections)) - for i := range s.collections[0] { + for i := range s.nodes[0].collections { s.docIDs[i] = []client.DocID{} } @@ -917,7 +862,7 @@ func refreshDocuments( // Just use the collection from the first relevant node, as all will be the same for this // purpose. firstNodesID := nodeIDs[0] - collection := s.collections[firstNodesID][action.CollectionID] + collection := s.nodes[firstNodesID].collections[action.CollectionID] if action.DocMap != nil { substituteRelations(s, action) @@ -939,16 +884,10 @@ func refreshDocuments( func refreshIndexes( s *state, ) { - if len(s.collections) == 0 { - return - } - - s.indexes = make([][][]client.IndexDescription, len(s.collections)) + for _, node := range s.nodes { + node.indexes = make([][]client.IndexDescription, len(node.collections)) - for i, nodeCols := range s.collections { - s.indexes[i] = make([][]client.IndexDescription, len(nodeCols)) - - for j, col := range nodeCols { + for i, col := range node.collections { if col == nil { continue } @@ -957,7 +896,7 @@ func refreshIndexes( continue } - s.indexes[i][j] = colIndexes + node.indexes[i] = colIndexes } } } @@ -966,7 +905,7 @@ func getIndexes( s *state, action GetIndexes, ) { - if len(s.collections) == 0 { + if len(s.nodes) == 0 { return } @@ -974,7 +913,7 @@ func getIndexes( nodeIDs, _ := getNodesWithIDs(action.NodeID, s.nodes) for _, nodeID := range nodeIDs { - collections := s.collections[nodeID] + collections := s.nodes[nodeID].collections err := withRetryOnNode( s.nodes[nodeID], func() error { @@ -1259,7 +1198,7 @@ func createDoc( nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] err := withRetryOnNode( node, func() error { @@ -1286,7 +1225,7 @@ func createDoc( s.docIDs[action.CollectionID] = append(s.docIDs[action.CollectionID], docIDs...) if action.ExpectedError == "" { - waitForUpdateEvents(s, action.NodeID, getEventsForCreateDoc(s, action)) + waitForUpdateEvents(s, action.NodeID, action.CollectionID, getEventsForCreateDoc(s, action)) } } @@ -1449,7 +1388,7 @@ func deleteDoc( nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] ctx := getContextWithIdentity(s.ctx, s, action.Identity, nodeID) err := withRetryOnNode( node, @@ -1464,10 +1403,11 @@ func deleteDoc( assertExpectedErrorRaised(s.t, s.testCase.Description, action.ExpectedError, expectedErrorRaised) if action.ExpectedError == "" { - docIDs := map[string]struct{}{ + expect := map[string]struct{}{ docID.String(): {}, } - waitForUpdateEvents(s, action.NodeID, docIDs) + + waitForUpdateEvents(s, action.NodeID, action.CollectionID, expect) } } @@ -1493,7 +1433,7 @@ func updateDoc( nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] err := withRetryOnNode( node, func() error { @@ -1512,7 +1452,7 @@ func updateDoc( assertExpectedErrorRaised(s.t, s.testCase.Description, action.ExpectedError, expectedErrorRaised) if action.ExpectedError == "" && !action.SkipLocalUpdateEvent { - waitForUpdateEvents(s, action.NodeID, getEventsForUpdateDoc(s, action)) + waitForUpdateEvents(s, action.NodeID, action.CollectionID, getEventsForUpdateDoc(s, action)) } } @@ -1596,7 +1536,7 @@ func updateWithFilter(s *state, action UpdateWithFilter) { nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] ctx := getContextWithIdentity(s.ctx, s, action.Identity, nodeID) err := withRetryOnNode( node, @@ -1612,7 +1552,7 @@ func updateWithFilter(s *state, action UpdateWithFilter) { assertExpectedErrorRaised(s.t, s.testCase.Description, action.ExpectedError, expectedErrorRaised) if action.ExpectedError == "" && !action.SkipLocalUpdateEvent { - waitForUpdateEvents(s, action.NodeID, getEventsForUpdateWithFilter(s, action, res)) + waitForUpdateEvents(s, action.NodeID, action.CollectionID, getEventsForUpdateWithFilter(s, action, res)) } } @@ -1621,18 +1561,10 @@ func createIndex( s *state, action CreateIndex, ) { - if action.CollectionID >= len(s.indexes) { - // Expand the slice if required, so that the index can be accessed by collection index - s.indexes = append( - s.indexes, - make([][][]client.IndexDescription, action.CollectionID-len(s.indexes)+1)..., - ) - } - nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] indexDesc := client.IndexDescription{ Name: action.IndexName, } @@ -1659,8 +1591,8 @@ func createIndex( if err != nil { return err } - s.indexes[nodeID][action.CollectionID] = append( - s.indexes[nodeID][action.CollectionID], + s.nodes[nodeID].indexes[action.CollectionID] = append( + s.nodes[nodeID].indexes[action.CollectionID], desc, ) return nil @@ -1684,10 +1616,10 @@ func dropIndex( nodeIDs, nodes := getNodesWithIDs(action.NodeID, s.nodes) for index, node := range nodes { nodeID := nodeIDs[index] - collection := s.collections[nodeID][action.CollectionID] + collection := s.nodes[nodeID].collections[action.CollectionID] indexName := action.IndexName if indexName == "" { - indexName = s.indexes[nodeID][action.CollectionID][action.IndexID].Name + indexName = s.nodes[nodeID].indexes[action.CollectionID][action.IndexID].Name } err := withRetryOnNode( @@ -1764,7 +1696,7 @@ func backupImport( // about this in our tests so we just retry a few times until it works (or the // retry limit is breached - important incase this is a different error) func withRetryOnNode( - node clients.Client, + node client.DB, action func() error, ) error { for i := 0; i < node.MaxTxnRetries(); i++ { @@ -2054,7 +1986,7 @@ func assertRequestResultDocs( ) bool { // compare results require.Equal(s.t, len(expectedResults), len(actualResults), - s.testCase.Description+" \n(number of results don't match)") + s.testCase.Description+" \n(number of results don't match for %s)", stack) for actualDocIndex, actualDoc := range actualResults { stack.pushArray(actualDocIndex) @@ -2065,9 +1997,9 @@ func assertRequestResultDocs( len(expectedDoc), len(actualDoc), fmt.Sprintf( - "%s \n(number of properties for item at index %v don't match)", + "%s \n(number of properties don't match for %s)", s.testCase.Description, - actualDocIndex, + stack, ), ) @@ -2319,7 +2251,7 @@ func skipIfClientTypeUnsupported( } if len(filteredClients) == 0 { - t.Skipf("test does not support any given client type. Type: %v", supportedClientTypes) + t.Skipf("test does not support any given client type. Supported Type: %v", supportedClientTypes.Value()) } return filteredClients @@ -2360,7 +2292,7 @@ func skipIfDatabaseTypeUnsupported( } if len(filteredDatabases) == 0 { - t.Skipf("test does not support any given database type. Type: %v", filteredDatabases) + t.Skipf("test does not support any given database type. Supported Type: %v", supportedDatabaseTypes.Value()) } return filteredDatabases