@dxos/echo 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/Annotation.mjs +3 -0
- package/dist/lib/Blob.mjs +160 -0
- package/dist/lib/Blob.mjs.map +1 -0
- package/dist/lib/Database.mjs +2 -0
- package/dist/lib/Entity.mjs +231 -0
- package/dist/lib/Entity.mjs.map +1 -0
- package/dist/lib/Err.mjs +105 -0
- package/dist/lib/Err.mjs.map +1 -0
- package/dist/lib/Feed.mjs +338 -0
- package/dist/lib/Feed.mjs.map +1 -0
- package/dist/lib/Filter.mjs +380 -0
- package/dist/lib/Filter.mjs.map +1 -0
- package/dist/lib/Format.mjs +47 -0
- package/dist/lib/Format.mjs.map +1 -0
- package/dist/lib/JsonSchema.mjs +21 -0
- package/dist/lib/JsonSchema.mjs.map +1 -0
- package/dist/lib/Key.mjs +15 -0
- package/dist/lib/Key.mjs.map +1 -0
- package/dist/lib/Migration.mjs +38 -0
- package/dist/lib/Migration.mjs.map +1 -0
- package/dist/lib/Obj.mjs +660 -0
- package/dist/lib/Obj.mjs.map +1 -0
- package/dist/lib/Order.mjs +65 -0
- package/dist/lib/Order.mjs.map +1 -0
- package/dist/lib/Query.mjs +336 -0
- package/dist/lib/Query.mjs.map +1 -0
- package/dist/lib/QueryResult.mjs +7 -0
- package/dist/lib/QueryResult.mjs.map +1 -0
- package/dist/lib/Ref.mjs +44 -0
- package/dist/lib/Ref.mjs.map +1 -0
- package/dist/lib/Registry.mjs +35 -0
- package/dist/lib/Registry.mjs.map +1 -0
- package/dist/lib/Relation.mjs +397 -0
- package/dist/lib/Relation.mjs.map +1 -0
- package/dist/lib/Scope.mjs +51 -0
- package/dist/lib/Scope.mjs.map +1 -0
- package/dist/lib/Tag.mjs +70 -0
- package/dist/lib/Tag.mjs.map +1 -0
- package/dist/lib/Text.mjs +82 -0
- package/dist/lib/Text.mjs.map +1 -0
- package/dist/lib/Type.mjs +371 -0
- package/dist/lib/Type.mjs.map +1 -0
- package/dist/lib/chunk-Annotation.mjs +221 -0
- package/dist/lib/chunk-Annotation.mjs.map +1 -0
- package/dist/lib/chunk-Database.mjs +918 -0
- package/dist/lib/chunk-Database.mjs.map +1 -0
- package/dist/lib/chunk-atom-snapshot.mjs +249 -0
- package/dist/lib/chunk-atom-snapshot.mjs.map +1 -0
- package/dist/lib/chunk-internal.mjs +2775 -0
- package/dist/lib/chunk-internal.mjs.map +1 -0
- package/dist/lib/chunk-json-schema.mjs +660 -0
- package/dist/lib/chunk-json-schema.mjs.map +1 -0
- package/dist/lib/chunk-number.mjs +164 -0
- package/dist/lib/chunk-number.mjs.map +1 -0
- package/dist/lib/chunk-ref-array.mjs +31 -0
- package/dist/lib/chunk-ref-array.mjs.map +1 -0
- package/dist/lib/chunk-ref.mjs +590 -0
- package/dist/lib/chunk-ref.mjs.map +1 -0
- package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
- package/dist/lib/chunk-select.mjs +186 -0
- package/dist/lib/chunk-select.mjs.map +1 -0
- package/dist/lib/chunk-src.mjs +234 -0
- package/dist/lib/chunk-src.mjs.map +1 -0
- package/dist/lib/chunk-util.mjs +140 -0
- package/dist/lib/chunk-util.mjs.map +1 -0
- package/dist/lib/index.mjs +24 -0
- package/dist/lib/internal.mjs +10 -0
- package/dist/lib/testing.mjs +346 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/types/src/Aggregate.d.ts +86 -0
- package/dist/types/src/Aggregate.d.ts.map +1 -0
- package/dist/types/src/Blob.d.ts +153 -0
- package/dist/types/src/Blob.d.ts.map +1 -0
- package/dist/types/src/Blob.test.d.ts +2 -0
- package/dist/types/src/Blob.test.d.ts.map +1 -0
- package/dist/types/src/Database.d.ts +153 -4
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +116 -0
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Feed.d.ts +116 -28
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Feed.test.d.ts +2 -0
- package/dist/types/src/Feed.test.d.ts.map +1 -0
- package/dist/types/src/Filter.d.ts +14 -6
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +18 -0
- package/dist/types/src/Hypergraph.d.ts.map +1 -1
- package/dist/types/src/Json.d.ts.map +1 -1
- package/dist/types/src/Obj.d.ts +14 -1
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Order.d.ts +9 -3
- package/dist/types/src/Order.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +107 -26
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/Relation.d.ts +6 -0
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/api.d.ts +6 -0
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/model.d.ts +3 -2
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
- package/dist/types/src/internal/Filter/match.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts +34 -8
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/atoms.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/Query/pretty.d.ts.map +1 -1
- package/dist/types/src/internal/Query/query-result-effect.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/make-object.d.ts +13 -0
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/reactive.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/symbols.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts +12 -0
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/index.d.ts +1 -0
- package/dist/types/src/internal/common/types/index.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/model-symbols.d.ts +5 -0
- package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/projection.d.ts +32 -0
- package/dist/types/src/internal/common/types/projection.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -35
- package/src/Aggregate.ts +105 -0
- package/src/Blob.test.ts +45 -0
- package/src/Blob.ts +205 -0
- package/src/Database.ts +207 -17
- package/src/Err.ts +36 -0
- package/src/Feed.test.ts +188 -0
- package/src/Feed.ts +238 -62
- package/src/Filter.ts +28 -10
- package/src/Hypergraph.ts +18 -0
- package/src/Json.ts +1 -0
- package/src/Obj.test.ts +2 -2
- package/src/Obj.ts +21 -1
- package/src/Order.ts +16 -9
- package/src/Query.test.ts +319 -2
- package/src/Query.ts +165 -51
- package/src/Relation.ts +14 -0
- package/src/Type.ts +5 -6
- package/src/index.ts +2 -0
- package/src/internal/Entity/api.ts +11 -1
- package/src/internal/Entity/model.ts +3 -0
- package/src/internal/Filter/match.ts +30 -1
- package/src/internal/JsonSchema/json-schema-type.ts +14 -2
- package/src/internal/JsonSchema/json-schema.test.ts +28 -1
- package/src/internal/JsonSchema/json-schema.ts +33 -6
- package/src/internal/Obj/atoms.ts +4 -2
- package/src/internal/Obj/json-serializer.test.ts +162 -2
- package/src/internal/Obj/json-serializer.ts +6 -0
- package/src/internal/Query/pretty.ts +19 -1
- package/src/internal/Query/query-result-effect.ts +2 -4
- package/src/internal/Ref/atoms.ts +1 -1
- package/src/internal/common/proxy/change-context.ts +1 -1
- package/src/internal/common/proxy/make-object.ts +42 -3
- package/src/internal/common/proxy/reactive.ts +5 -0
- package/src/internal/common/proxy/symbols.ts +1 -0
- package/src/internal/common/proxy/typed-handler.ts +71 -29
- package/src/internal/common/types/index.ts +1 -0
- package/src/internal/common/types/model-symbols.ts +6 -0
- package/src/internal/common/types/projection.ts +45 -0
- package/src/testing/test-data.ts +14 -14
- package/dist/lib/neutral/Annotation.mjs +0 -90
- package/dist/lib/neutral/Annotation.mjs.map +0 -7
- package/dist/lib/neutral/Database.mjs +0 -42
- package/dist/lib/neutral/Database.mjs.map +0 -7
- package/dist/lib/neutral/Entity.mjs +0 -76
- package/dist/lib/neutral/Entity.mjs.map +0 -7
- package/dist/lib/neutral/Err.mjs +0 -16
- package/dist/lib/neutral/Err.mjs.map +0 -7
- package/dist/lib/neutral/Feed.mjs +0 -50
- package/dist/lib/neutral/Feed.mjs.map +0 -7
- package/dist/lib/neutral/Filter.mjs +0 -72
- package/dist/lib/neutral/Filter.mjs.map +0 -7
- package/dist/lib/neutral/Format.mjs +0 -82
- package/dist/lib/neutral/Format.mjs.map +0 -7
- package/dist/lib/neutral/JsonSchema.mjs +0 -18
- package/dist/lib/neutral/JsonSchema.mjs.map +0 -7
- package/dist/lib/neutral/Key.mjs +0 -16
- package/dist/lib/neutral/Key.mjs.map +0 -7
- package/dist/lib/neutral/Migration.mjs +0 -18
- package/dist/lib/neutral/Migration.mjs.map +0 -7
- package/dist/lib/neutral/Obj.mjs +0 -128
- package/dist/lib/neutral/Obj.mjs.map +0 -7
- package/dist/lib/neutral/Order.mjs +0 -16
- package/dist/lib/neutral/Order.mjs.map +0 -7
- package/dist/lib/neutral/Query.mjs +0 -38
- package/dist/lib/neutral/Query.mjs.map +0 -7
- package/dist/lib/neutral/QueryResult.mjs +0 -2
- package/dist/lib/neutral/QueryResult.mjs.map +0 -7
- package/dist/lib/neutral/Ref.mjs +0 -25
- package/dist/lib/neutral/Ref.mjs.map +0 -7
- package/dist/lib/neutral/Registry.mjs +0 -14
- package/dist/lib/neutral/Registry.mjs.map +0 -7
- package/dist/lib/neutral/Relation.mjs +0 -97
- package/dist/lib/neutral/Relation.mjs.map +0 -7
- package/dist/lib/neutral/Scope.mjs +0 -12
- package/dist/lib/neutral/Scope.mjs.map +0 -7
- package/dist/lib/neutral/Tag.mjs +0 -32
- package/dist/lib/neutral/Tag.mjs.map +0 -7
- package/dist/lib/neutral/Text.mjs +0 -25
- package/dist/lib/neutral/Text.mjs.map +0 -7
- package/dist/lib/neutral/Type.mjs +0 -65
- package/dist/lib/neutral/Type.mjs.map +0 -7
- package/dist/lib/neutral/chunk-2HKGAQM4.mjs +0 -1394
- package/dist/lib/neutral/chunk-2HKGAQM4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-2ZHECXUR.mjs +0 -95
- package/dist/lib/neutral/chunk-2ZHECXUR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-3KTE2Y7Q.mjs +0 -336
- package/dist/lib/neutral/chunk-3KTE2Y7Q.mjs.map +0 -7
- package/dist/lib/neutral/chunk-3TN2VMI4.mjs +0 -714
- package/dist/lib/neutral/chunk-3TN2VMI4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-42L4HJ3Z.mjs +0 -104
- package/dist/lib/neutral/chunk-42L4HJ3Z.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4A2NWKRJ.mjs +0 -747
- package/dist/lib/neutral/chunk-4A2NWKRJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7LOUAPYZ.mjs +0 -25
- package/dist/lib/neutral/chunk-7LOUAPYZ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ACFAOTKJ.mjs +0 -1531
- package/dist/lib/neutral/chunk-ACFAOTKJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BEFR7LEA.mjs +0 -170
- package/dist/lib/neutral/chunk-BEFR7LEA.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BXIKXT7Q.mjs +0 -89
- package/dist/lib/neutral/chunk-BXIKXT7Q.mjs.map +0 -7
- package/dist/lib/neutral/chunk-C57XMMBY.mjs +0 -206
- package/dist/lib/neutral/chunk-C57XMMBY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-C62JYFAD.mjs +0 -183
- package/dist/lib/neutral/chunk-C62JYFAD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-FSGX2R62.mjs +0 -48
- package/dist/lib/neutral/chunk-FSGX2R62.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HBXT3GSB.mjs +0 -459
- package/dist/lib/neutral/chunk-HBXT3GSB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-IQR45HAD.mjs +0 -31
- package/dist/lib/neutral/chunk-IQR45HAD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KCBW4BR6.mjs +0 -424
- package/dist/lib/neutral/chunk-KCBW4BR6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-L3E5IXAE.mjs +0 -575
- package/dist/lib/neutral/chunk-L3E5IXAE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PRC4FEKJ.mjs +0 -56
- package/dist/lib/neutral/chunk-PRC4FEKJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SCT6FFCR.mjs +0 -351
- package/dist/lib/neutral/chunk-SCT6FFCR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TOCVVFK2.mjs +0 -75
- package/dist/lib/neutral/chunk-TOCVVFK2.mjs.map +0 -7
- package/dist/lib/neutral/chunk-U53LSQQA.mjs +0 -41
- package/dist/lib/neutral/chunk-U53LSQQA.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UGFFV2FR.mjs +0 -27
- package/dist/lib/neutral/chunk-UGFFV2FR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UWLP4RFM.mjs +0 -7
- package/dist/lib/neutral/chunk-UWLP4RFM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UZHCQ6NI.mjs +0 -283
- package/dist/lib/neutral/chunk-UZHCQ6NI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WISOH2XH.mjs +0 -36
- package/dist/lib/neutral/chunk-WISOH2XH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WKIT2YY5.mjs +0 -34
- package/dist/lib/neutral/chunk-WKIT2YY5.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XB6ISRAO.mjs +0 -271
- package/dist/lib/neutral/chunk-XB6ISRAO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XXL42WCB.mjs +0 -84
- package/dist/lib/neutral/chunk-XXL42WCB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XXWK4J53.mjs +0 -117
- package/dist/lib/neutral/chunk-XXWK4J53.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -115
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/internal/index.mjs +0 -581
- package/dist/lib/neutral/internal/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/testing/index.mjs +0 -477
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Ref.mjs","names":[],"sources":["../../src/Ref.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Option from 'effect/Option';\nimport type * as Schema from 'effect/Schema';\nimport * as SchemaAST from 'effect/SchemaAST';\n\nimport { type URI } from '@dxos/keys';\n\nimport type * as Entity from './Entity';\nimport type * as internal from './internal';\nimport * as refInternal from './internal/Ref';\nimport type * as JsonSchema from './JsonSchema';\nimport type * as Obj from './Obj';\nimport type * as Relation from './Relation';\n// eslint-disable-next-line @dxos/rules/import-as-namespace\nimport type * as Type$ from './Type';\n\n/**\n * Instance type for a reference.\n *\n * Reference can point to any object or relation.\n * References are lazy loaded.\n *\n * `ref.dxn` is the DXN of the referenced object.\n *\n * @example\n * ```ts\n * const taskRef: Ref<Task> = Ref.make(task);\n *\n * await taskRef.load(); // Returns Promise<Task>\n * yield* Database.load(taskRef); // Effectful version.\n *\n * database.makeRef(dxn); // Create a ref from a DXN.\n * ```\n */\nexport type Ref<T> = refInternal.Ref<T>;\nexport type Unknown = refInternal.Ref<Obj.Unknown>;\n\n/**\n * Factory function to create a Ref schema for the given target schema.\n * Use this in schema definitions to declare reference fields.\n *\n * @example\n * ```ts\n * class Task extends Type.makeObject<Task>(DXN.make('com.example.type.task', '0.1.0'))(\n * Schema.Struct({\n * assignee: Ref.Ref(Person), // Creates a Ref schema\n * }),\n * ) {}\n * ```\n */\nexport const Ref: {\n <S extends Type$.AnyObj>(type: S): RefSchema<Type$.InstanceType<S> & Obj.Unknown>;\n\n // Relations are entities too and can be referenced. The instance type already\n // carries the relation kind brand, so intersect with `Relation.Unknown` (not\n // `Obj.Unknown`, whose object kind brand conflicts and collapses to `never`).\n <S extends Type$.AnyRelation>(type: S): RefSchema<Type$.InstanceType<S> & Relation.Unknown>;\n\n // `Type.Type` entities (the meta-schema kind) can be referenced too — e.g. a\n // trigger that points to a stored function/workflow definition.\n <T extends Type$.Type<any>>(type: T): RefSchema<Type$.InstanceType<T>>;\n\n // Schema-side overload for the well-known \"any object\" / \"any relation\" schemas.\n // Other raw `Schema.Schema` values are intentionally rejected — callers should\n // pass a `Type.Type` entity instead.\n <S extends internal.UnknownTypeSchema<any, any>>(schema: S): RefSchema<Schema.Schema.Type<S> & Obj.Unknown>;\n} = refInternal.Ref as any;\n\nexport const Array = refInternal.RefArray;\n\n/**\n * TypeScript type for a Ref schema.\n * This is the type of the SCHEMA itself, not the runtime ref instance.\n * For the instance type, use `Ref.Ref<T>` from the Ref module.\n *\n * @example\n * ```ts\n * // Schema type annotation (rarely needed, usually inferred):\n * const refSchema: Ref.RefSchema<typeof Task> = Ref.Ref(Task);\n *\n * // Instance type annotation (use Ref.Ref instead):\n * const refInstance: Ref.Ref<Task> = Ref.make(task);\n * ```\n */\n// TODO(dmaretskyi): Investigate if we can remove this type.\n// Post DX-836 it will become just `Schema.Schema<Ref.Ref<T>>`.\n// NOTE: This could be Type.Ref<T> instead, but since it going to be removed, it's better to keep it here, self-contained.\nexport interface RefSchema<T extends Entity.Unknown> extends refInternal.RefSchema<T> {}\n\n/**\n * Extract reference target.\n */\nexport type Target<R extends Unknown> = R extends refInternal.Ref<infer T> ? T : never;\n\n/**\n * Reference resolver.\n */\nexport type Resolver = refInternal.RefResolver;\n\nexport const isRef: (value: unknown) => value is Unknown = refInternal.Ref.isRef;\n\nexport const make = refInternal.Ref.make;\n\n// TODO(dmaretskyi): Consider just allowing `make` to accept URI.\nexport const fromURI = (uri: URI.URI): refInternal.Ref<any> => refInternal.Ref.fromURI(uri);\n\nexport const hasEntityId = refInternal.Ref.hasEntityId;\n\n// TODO(wittjosiah): Factor out?\nexport const isRefType = (ast: SchemaAST.AST): boolean => {\n return SchemaAST.getAnnotation<JsonSchema.JsonSchema>(ast, SchemaAST.JSONSchemaAnnotationId).pipe(\n Option.flatMap((jsonSchema) => ('$id' in jsonSchema ? Option.some(jsonSchema) : Option.none())),\n Option.flatMap((jsonSchema) => {\n const { typename } = refInternal.getSchemaReference(jsonSchema) ?? {};\n return typename ? Option.some(true) : Option.some(false);\n }),\n Option.getOrElse(() => false),\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,IAAa,MAgBT;AAEJ,IAAa,QAAQ;AA+BrB,IAAa,QAAA,MAA8D;AAE3E,IAAa,OAAA,MAAuB;AAGpC,IAAa,WAAW,QAAA,MAAuD,QAAQ,GAAG;AAE1F,IAAa,cAAA,MAA8B;AAG3C,IAAa,aAAa,QAAgC;CACxD,OAAO,UAAU,cAAqC,KAAK,UAAU,sBAAsB,CAAC,CAAC,KAC3F,OAAO,SAAS,eAAgB,SAAS,aAAa,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAE,GAC9F,OAAO,SAAS,eAAe;EAC7B,MAAM,EAAE,aAAa,mBAA+B,UAAU,KAAK,CAAC;EACpE,OAAO,WAAW,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK;CACzD,CAAC,GACD,OAAO,gBAAgB,KAAK,CAC9B;AACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Context from "effect/Context";
|
|
4
|
+
//#region src/Registry.ts
|
|
5
|
+
var Registry_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
Service: () => Service,
|
|
7
|
+
TypeId: () => TypeId,
|
|
8
|
+
isRegistry: () => isRegistry,
|
|
9
|
+
runQuery: () => runQuery
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Identifier denoting an ECHO Registry.
|
|
13
|
+
*/
|
|
14
|
+
var TypeId = Symbol.for("@dxos/echo/Registry");
|
|
15
|
+
/**
|
|
16
|
+
* Type guard for {@link Registry}.
|
|
17
|
+
*/
|
|
18
|
+
var isRegistry = (obj) => obj != null && typeof obj === "object" && TypeId in obj && obj[TypeId] === TypeId;
|
|
19
|
+
/**
|
|
20
|
+
* Effect Context tag for {@link Registry}.
|
|
21
|
+
* Use this to inject a registry into Effect-based code.
|
|
22
|
+
*/
|
|
23
|
+
var Service = class extends Context.Tag("@dxos/echo/Registry/Service")() {};
|
|
24
|
+
/**
|
|
25
|
+
* Executes a query against the registry and returns the results.
|
|
26
|
+
* Analogous to {@link Database.query} `.run` for the in-process registry.
|
|
27
|
+
*/
|
|
28
|
+
var runQuery = (queryOrFilter) => Effect.gen(function* () {
|
|
29
|
+
const registry = yield* Service;
|
|
30
|
+
return yield* Effect.promise(() => registry.query(queryOrFilter).run());
|
|
31
|
+
});
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Service, TypeId, isRegistry, runQuery, Registry_exports as t };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=Registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Registry.mjs","names":[],"sources":["../../src/Registry.ts"],"sourcesContent":["// Copyright 2026 DXOS.org\n\n// @import-as-namespace\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\n\nimport { type ReadOnlyEvent } from '@dxos/async';\n\nimport type * as Database from './Database';\nimport * as Entity from './Entity';\nimport type * as Filter from './Filter';\nimport type * as Query from './Query';\n\n/**\n * Identifier denoting an ECHO Registry.\n */\nexport const TypeId = Symbol.for('@dxos/echo/Registry');\nexport type TypeId = typeof TypeId;\n\n/**\n * Composable, in-memory registry of keyed ECHO entities.\n *\n * Entities are stored by id and queried via the standard ECHO Query API.\n * A registry may delegate to an optional upstream registry: results from the local\n * registry take precedence and upstream results fill in anything not found locally.\n *\n * Intended use cases include caches of schemas, operations, skills, routines, plugins,\n * etc., sourced from 3rd-party plugins, local code, or local space objects.\n *\n * Types (schema-definition entities produced by `Type.makeObject` / `Type.makeRelation`) are\n * stored the same way as any other entity — via `add()`. Use `list().filter(Type.isType)` to\n * retrieve them.\n *\n * Scope: a Registry is independent of any ECHO space or Hypergraph — it is a process-local,\n * in-memory cache. Wire one per space (e.g. as a Layer scoped to the space's Effect runtime)\n * or share a single instance across spaces depending on the use case.\n *\n * The concrete implementation (and the `makeRegistry` / `registryLayer` factories) lives in\n * `@dxos/echo-client`; this module declares only the interface so that the `@dxos/echo` API surface\n * stays free of query-matching dependencies.\n */\nexport interface Registry {\n readonly [TypeId]: TypeId;\n\n /**\n * Stable per-instance identifier. Used to key process-local resources (e.g. memoized\n * reactive atoms) to a specific registry instance, analogous to {@link Database.spaceId}.\n */\n readonly id: string;\n\n /**\n * Fires whenever local registry contents change (add, remove, or clear).\n */\n readonly changed: ReadOnlyEvent<void>;\n\n /**\n * All locally-stored entities.\n * Does not include upstream entities — use {@link list} for that.\n */\n readonly local: readonly Entity.Unknown[];\n\n /**\n * Add or replace one or more entities in the local registry.\n * Existing entries with the same id are replaced.\n * Also indexes type entities by DXN for fast lookup.\n */\n add(entities: readonly Entity.Unknown[]): void;\n\n /**\n * Remove an entity by id from the local registry.\n * @returns true if an entity was removed, false if it was not found.\n */\n remove(id: string): boolean;\n\n /**\n * Remove all locally-stored entities.\n * Does not affect the upstream registry.\n */\n clear(): void;\n\n /**\n * Get an entity by id.\n * Searches the local registry first, then falls back to the upstream registry.\n */\n get(id: string): Entity.Unknown | undefined;\n\n /**\n * Get an entity by one of its addressing URIs — a type entity by its typename DXN (or, when\n * persisted, its identifier EID), a keyed entity by its `dxn:<key>[:<version>]`. Accepts legacy\n * DXN forms (normalized internally). Searches the local registry first, then falls back to the\n * upstream registry. Narrow the result with `Type.isType` when a type entity is required.\n */\n getByURI(uri: string): Entity.Unknown | undefined;\n\n /**\n * List all entities.\n * Local entities take precedence over upstream entities with the same id.\n */\n list(): Entity.Unknown[];\n\n /**\n * Run an ECHO query against the registry's entities (implements {@link Database.Queryable}).\n *\n * Matching happens in-memory over {@link list}. Scope (`from`) clauses are unwrapped and\n * ignored — a direct registry query always targets the registry's own entities. The primary\n * way to query registry contents is still through the database (`db.query(...).from(Scope.registry())`),\n * which fans the database and registry together; this method is for querying a registry directly.\n *\n * Only locally-evaluable AST nodes are supported: `select`, `filter`, `limit`, `from`, `options`,\n * and boolean combinators. Server-side concerns (order, traversal, text/timestamp filters) throw.\n */\n query: Database.QueryFn;\n}\n\n/**\n * Type guard for {@link Registry}.\n */\nexport const isRegistry = (obj: unknown): obj is Registry =>\n obj != null && typeof obj === 'object' && TypeId in obj && (obj as { [TypeId]?: unknown })[TypeId] === TypeId;\n\n/**\n * Options for the registry factory (`makeRegistry` in `@dxos/echo-client`).\n */\nexport type Options = {\n /**\n * Optional upstream registry. Queries fall back to upstream when an entity\n * is not present in the local registry.\n */\n upstream?: Registry;\n\n /**\n * Initial set of entities to seed the local registry with.\n */\n initial?: readonly Entity.Unknown[];\n};\n\n/**\n * Effect Context tag for {@link Registry}.\n * Use this to inject a registry into Effect-based code.\n */\nexport class Service extends Context.Tag('@dxos/echo/Registry/Service')<Service, Registry>() {}\n\n/**\n * Executes a query against the registry and returns the results.\n * Analogous to {@link Database.query} `.run` for the in-process registry.\n */\nexport const runQuery: {\n <Q extends Query.Any>(query: Q): Effect.Effect<Query.Type<Q>[], never, Service>;\n <F extends Filter.Any>(filter: F): Effect.Effect<Filter.Type<F>[], never, Service>;\n} = (queryOrFilter: Query.Any | Filter.Any) =>\n Effect.gen(function* () {\n const registry = yield* Service;\n return (yield* Effect.promise(() => registry.query(queryOrFilter as any).run())) as any;\n });\n"],"mappings":";;;;;;;;;;;;;AAiBA,IAAa,SAAS,OAAO,IAAI,qBAAqB;;;;AAqGtD,IAAa,cAAc,QACzB,OAAO,QAAQ,OAAO,QAAQ,YAAY,UAAU,OAAQ,IAA+B,YAAY;;;;;AAsBzG,IAAa,UAAb,cAA6B,QAAQ,IAAI,6BAA6B,CAAC,CAAoB,CAAC,CAAC,CAAC;;;;;AAM9F,IAAa,YAGR,kBACH,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO;CACxB,OAAQ,OAAO,OAAO,cAAc,SAAS,MAAM,aAAoB,CAAC,CAAC,IAAI,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { c as getKeys$1, l as getMetaChecked, o as addTag$1, s as deleteKeys$1, u as removeTag$1 } from "./chunk-atom-snapshot.mjs";
|
|
3
|
+
import { A as isVersion$1, Ct as sortByLabel$1, St as sort$1, T as objectToJSON, Tt as VersionTypeId$1, U as makeObject, d as makeRelation, h as isDeleted$1, j as version$1, m as setValue$1, p as getSnapshot$1, wt as sortByTypename$1 } from "./chunk-internal.mjs";
|
|
4
|
+
import { a as ANY_OBJECT_VERSION, i as ANY_OBJECT_TYPENAME, o as EntityKind } from "./chunk-util.mjs";
|
|
5
|
+
import { $t as RelationTargetId, Ct as getTypename$1, Dt as setLabel$1, E as getObjectEchoUri, Gt as MetaId, Lt as getType$1, Mt as ParentId, Qt as RelationTargetDXNId, S as isInstanceOf, St as getTypeURI$1, T as getUri, Tt as setDescription$1, Xt as RelationSourceDXNId, Zt as RelationSourceId, bt as getTypeAnnotation, ct as getDescription$1, pt as getLabel$1, rt as TypeAnnotationId, w as getDatabase$1 } from "./chunk-Database.mjs";
|
|
6
|
+
import { g as subscribe$1, h as change } from "./chunk-ref.mjs";
|
|
7
|
+
import { getSchema } from "./Type.mjs";
|
|
8
|
+
import { Kind, KindId, SnapshotKindId } from "./Entity.mjs";
|
|
9
|
+
import { isObject } from "./Obj.mjs";
|
|
10
|
+
import { DXN, EID } from "@dxos/keys";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
import { assertArgument, invariant } from "@dxos/invariant";
|
|
13
|
+
import { SchemaEx } from "@dxos/effect";
|
|
14
|
+
import { assumeType } from "@dxos/util";
|
|
15
|
+
import { raise } from "@dxos/debug";
|
|
16
|
+
//#region src/Relation.ts
|
|
17
|
+
var Relation_exports = /* @__PURE__ */ __exportAll({
|
|
18
|
+
Meta: () => Meta,
|
|
19
|
+
Source: () => Source,
|
|
20
|
+
Target: () => Target,
|
|
21
|
+
Unknown: () => Unknown,
|
|
22
|
+
VersionTypeId: () => VersionTypeId,
|
|
23
|
+
addTag: () => addTag,
|
|
24
|
+
atom: () => atom,
|
|
25
|
+
deleteKeys: () => deleteKeys,
|
|
26
|
+
getDatabase: () => getDatabase,
|
|
27
|
+
getDescription: () => getDescription,
|
|
28
|
+
getKeys: () => getKeys,
|
|
29
|
+
getLabel: () => getLabel,
|
|
30
|
+
getMeta: () => getMeta,
|
|
31
|
+
getSnapshot: () => getSnapshot,
|
|
32
|
+
getSource: () => getSource,
|
|
33
|
+
getSourceURI: () => getSourceURI,
|
|
34
|
+
getTarget: () => getTarget,
|
|
35
|
+
getTargetURI: () => getTargetURI,
|
|
36
|
+
getType: () => getType,
|
|
37
|
+
getTypeURI: () => getTypeURI,
|
|
38
|
+
getTypename: () => getTypename,
|
|
39
|
+
getURI: () => getURI,
|
|
40
|
+
getValue: () => getValue,
|
|
41
|
+
instanceOf: () => instanceOf,
|
|
42
|
+
isDeleted: () => isDeleted,
|
|
43
|
+
isRelation: () => isRelation,
|
|
44
|
+
isSnapshot: () => isSnapshot,
|
|
45
|
+
isVersion: () => isVersion,
|
|
46
|
+
make: () => make,
|
|
47
|
+
removeTag: () => removeTag,
|
|
48
|
+
setDescription: () => setDescription,
|
|
49
|
+
setLabel: () => setLabel,
|
|
50
|
+
setParent: () => setParent,
|
|
51
|
+
setValue: () => setValue,
|
|
52
|
+
sort: () => sort,
|
|
53
|
+
sortByLabel: () => sortByLabel,
|
|
54
|
+
sortByTypename: () => sortByTypename,
|
|
55
|
+
subscribe: () => subscribe,
|
|
56
|
+
toJSON: () => toJSON,
|
|
57
|
+
update: () => update,
|
|
58
|
+
version: () => version
|
|
59
|
+
});
|
|
60
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo/src/Relation.ts";
|
|
61
|
+
/**
|
|
62
|
+
* Runtime Effect schema for any ECHO relation.
|
|
63
|
+
* Use for validation, parsing, or as a reference target for collections.
|
|
64
|
+
* A relation has `id`, source, and target fields plus any additional properties.
|
|
65
|
+
*
|
|
66
|
+
* NOTE: `Schema.is(Type.Relation)` does STRUCTURAL validation only (checks for `id` field).
|
|
67
|
+
* Use `Relation.isRelation()` for proper ECHO instance type guards that check the KindId brand.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* // Structural type guard (accepts any object with id field)
|
|
72
|
+
* if (Schema.is(Type.Relation)(unknownValue)) { ... }
|
|
73
|
+
*
|
|
74
|
+
* // ECHO instance type guard (checks KindId brand)
|
|
75
|
+
* if (Relation.isRelation(unknownValue)) { ... }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
var Unknown = Schema.Struct({ id: Schema.String }).pipe(Schema.extend(Schema.Record({
|
|
79
|
+
key: Schema.String,
|
|
80
|
+
value: Schema.Unknown
|
|
81
|
+
})), Schema.annotations({ [TypeAnnotationId]: {
|
|
82
|
+
kind: Kind.Relation,
|
|
83
|
+
typename: "org.dxos.schema.anyRelation",
|
|
84
|
+
version: "0.0.0",
|
|
85
|
+
sourceSchema: DXN.make(ANY_OBJECT_TYPENAME, ANY_OBJECT_VERSION),
|
|
86
|
+
targetSchema: DXN.make(ANY_OBJECT_TYPENAME, ANY_OBJECT_VERSION)
|
|
87
|
+
} }));
|
|
88
|
+
var Source = RelationSourceId;
|
|
89
|
+
var Target = RelationTargetId;
|
|
90
|
+
/**
|
|
91
|
+
* Creates new relation.
|
|
92
|
+
* @param schema - Relation schema.
|
|
93
|
+
* @param props - Relation properties. Endpoints are passed as [Relation.Source] and [Relation.Target] keys.
|
|
94
|
+
* @param meta - Relation metadata. (deprecated; use [Obj.Meta] instead)
|
|
95
|
+
* @returns
|
|
96
|
+
*/
|
|
97
|
+
var make = (type, props) => {
|
|
98
|
+
const schema = getSchema(type);
|
|
99
|
+
assertArgument(getTypeAnnotation(schema)?.kind === EntityKind.Relation, "schema", "Expected a relation schema");
|
|
100
|
+
assertArgument(props[ParentId] === void 0, "props", "Parent is not allowed for relations");
|
|
101
|
+
let meta = void 0;
|
|
102
|
+
if (props[MetaId] != null) {
|
|
103
|
+
meta = props[MetaId];
|
|
104
|
+
delete props[MetaId];
|
|
105
|
+
}
|
|
106
|
+
const sourceDXN = getObjectEchoUri(props[Source]) ?? raise(/* @__PURE__ */ new Error("Unresolved relation source"));
|
|
107
|
+
const targetDXN = getObjectEchoUri(props[Target]) ?? raise(/* @__PURE__ */ new Error("Unresolved relation target"));
|
|
108
|
+
props[RelationSourceDXNId] = sourceDXN;
|
|
109
|
+
props[RelationTargetDXNId] = targetDXN;
|
|
110
|
+
return makeObject(schema, props, meta, type);
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Test if a value is an instance of a given relation type.
|
|
114
|
+
*
|
|
115
|
+
* Mirrors `Obj.instanceOf` but only accepts `Type.AnyRelation` — use
|
|
116
|
+
* `Obj.instanceOf` for objects and `Type.isType` for `Type.Type` entities.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* const isEmployedBy = Relation.instanceOf(EmployedBy);
|
|
121
|
+
* if (isEmployedBy(relation)) {
|
|
122
|
+
* // relation is EmployedBy
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
var instanceOf = ((...args) => {
|
|
127
|
+
if (args.length === 1) return (entity) => isInstanceOf(args[0], entity);
|
|
128
|
+
return isInstanceOf(args[0], args[1]);
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Type guard for relations.
|
|
132
|
+
* Returns true for both reactive relations and relation snapshots.
|
|
133
|
+
*/
|
|
134
|
+
var isRelation = (value) => {
|
|
135
|
+
if (typeof value !== "object" || value === null) return false;
|
|
136
|
+
if ("@relationSource" in value || "@relationTarget" in value) return true;
|
|
137
|
+
return (value[KindId] ?? value[SnapshotKindId]) === EntityKind.Relation;
|
|
138
|
+
};
|
|
139
|
+
var isSnapshot = (value) => {
|
|
140
|
+
if (typeof value !== "object" || value === null) return false;
|
|
141
|
+
return value[SnapshotKindId] === EntityKind.Relation;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Sets a relation as the parent of an object: the object cascade-deletes with the relation and is
|
|
145
|
+
* persisted transitively when the relation is added. The delete-cascade resolves the parent by id
|
|
146
|
+
* regardless of kind. The object-parent counterpart is {@link Obj.setParent}.
|
|
147
|
+
*/
|
|
148
|
+
var setParent = (entity, parent) => {
|
|
149
|
+
assertArgument(isObject(entity), "Expected an object");
|
|
150
|
+
assertArgument(isRelation(parent), "Expected a relation");
|
|
151
|
+
assumeType(entity);
|
|
152
|
+
assumeType(parent);
|
|
153
|
+
entity[ParentId] = parent;
|
|
154
|
+
return entity;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* @returns Relation source URI.
|
|
158
|
+
* Accepts both reactive relations and snapshots.
|
|
159
|
+
* @throws If the object is not a relation.
|
|
160
|
+
*/
|
|
161
|
+
var getSourceURI = (value) => {
|
|
162
|
+
assertArgument(isRelation(value), "Expected a relation");
|
|
163
|
+
assumeType(value);
|
|
164
|
+
const uri = value[RelationSourceDXNId];
|
|
165
|
+
invariant(EID.isEID(uri), void 0, {
|
|
166
|
+
"~LogMeta": "~LogMeta",
|
|
167
|
+
F: __dxlog_file,
|
|
168
|
+
L: 256,
|
|
169
|
+
S: void 0,
|
|
170
|
+
A: ["EID.isEID(uri)", ""]
|
|
171
|
+
});
|
|
172
|
+
return uri;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* @returns Relation target URI.
|
|
176
|
+
* Accepts both reactive relations and snapshots.
|
|
177
|
+
* @throws If the object is not a relation.
|
|
178
|
+
*/
|
|
179
|
+
var getTargetURI = (value) => {
|
|
180
|
+
assertArgument(isRelation(value), "Expected a relation");
|
|
181
|
+
assumeType(value);
|
|
182
|
+
const uri = value[RelationTargetDXNId];
|
|
183
|
+
invariant(EID.isEID(uri), void 0, {
|
|
184
|
+
"~LogMeta": "~LogMeta",
|
|
185
|
+
F: __dxlog_file,
|
|
186
|
+
L: 269,
|
|
187
|
+
S: void 0,
|
|
188
|
+
A: ["EID.isEID(uri)", ""]
|
|
189
|
+
});
|
|
190
|
+
return uri;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* @returns Relation source.
|
|
194
|
+
* Accepts both reactive relations and snapshots.
|
|
195
|
+
* @throws If the object is not a relation.
|
|
196
|
+
*/
|
|
197
|
+
var getSource = (relation) => {
|
|
198
|
+
assertArgument(isRelation(relation), "Expected a relation");
|
|
199
|
+
assumeType(relation);
|
|
200
|
+
const obj = relation[RelationSourceId];
|
|
201
|
+
if (obj === void 0) throw new Error(`Relation source could not be resolved.`);
|
|
202
|
+
return obj;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* @returns Relation target.
|
|
206
|
+
* Accepts both reactive relations and snapshots.
|
|
207
|
+
* @throws If the object is not a relation.
|
|
208
|
+
*/
|
|
209
|
+
var getTarget = (relation) => {
|
|
210
|
+
assertArgument(isRelation(relation), "Expected a relation");
|
|
211
|
+
assumeType(relation);
|
|
212
|
+
const obj = relation[RelationTargetId];
|
|
213
|
+
if (obj === void 0) throw new Error(`Relation target could not be resolved.`);
|
|
214
|
+
return obj;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Perform mutations on an echo relation within a controlled context.
|
|
218
|
+
*
|
|
219
|
+
* All mutations within the callback are batched and trigger a single notification
|
|
220
|
+
* when the callback completes. Direct mutations outside of `Relation.update` will throw
|
|
221
|
+
* an error for echo relations.
|
|
222
|
+
*
|
|
223
|
+
* @param relation - The echo relation to mutate. Use `Obj.update` for objects.
|
|
224
|
+
* @param callback - The callback that performs mutations on the relation.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* const worksFor = Relation.make(EmployedBy, {
|
|
229
|
+
* [Relation.Source]: person,
|
|
230
|
+
* [Relation.Target]: company,
|
|
231
|
+
* role: 'Engineer',
|
|
232
|
+
* });
|
|
233
|
+
*
|
|
234
|
+
* // Mutate within Relation.update
|
|
235
|
+
* Relation.update(worksFor, (obj) => {
|
|
236
|
+
* obj.role = 'Senior Engineer';
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* Note: Only accepts relations. Use `Obj.update` for objects.
|
|
241
|
+
*/
|
|
242
|
+
var update = (relation, callback) => {
|
|
243
|
+
change(relation, callback);
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Returns an immutable snapshot of a relation.
|
|
247
|
+
* The snapshot is branded with SnapshotKindId instead of KindId,
|
|
248
|
+
* making it distinguishable from the reactive relation at the type level.
|
|
249
|
+
*/
|
|
250
|
+
var getSnapshot = getSnapshot$1;
|
|
251
|
+
/**
|
|
252
|
+
* Subscribe to relation updates.
|
|
253
|
+
* The callback is called synchronously when the relation is modified.
|
|
254
|
+
* Only accepts reactive relations (not snapshots).
|
|
255
|
+
* @returns Unsubscribe function.
|
|
256
|
+
*/
|
|
257
|
+
var subscribe = (rel, callback) => {
|
|
258
|
+
return subscribe$1(rel, callback);
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* Get a deeply nested property from a relation.
|
|
262
|
+
* Accepts both reactive relations and snapshots.
|
|
263
|
+
*/
|
|
264
|
+
var getValue = (rel, path) => {
|
|
265
|
+
return SchemaEx.getValue(rel, SchemaEx.createJsonPath(path));
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Set a deeply nested property on a relation.
|
|
269
|
+
* Must be called within a `Relation.update` callback.
|
|
270
|
+
*
|
|
271
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
272
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
273
|
+
*/
|
|
274
|
+
var setValue = setValue$1;
|
|
275
|
+
/**
|
|
276
|
+
* Get the canonical URI of the relation. Returns `URI.URI` — today always an EID,
|
|
277
|
+
* but future entity kinds may surface other URI schemes; narrow with `EID.parse(uri)`
|
|
278
|
+
* or `DXN.tryMake(uri)` at the point of use. Accepts both reactive relations and snapshots.
|
|
279
|
+
*
|
|
280
|
+
* @param options.prefer - Controls the URI form (see {@link internal.GetURIOptions}).
|
|
281
|
+
*/
|
|
282
|
+
var getURI = (entity, options) => getUri(entity, options);
|
|
283
|
+
/**
|
|
284
|
+
* @returns The DXN of the relation's type.
|
|
285
|
+
*/
|
|
286
|
+
var getTypeURI = getTypeURI$1;
|
|
287
|
+
/**
|
|
288
|
+
* Get the type entity (`Type.AnyRelation`) the relation was created from.
|
|
289
|
+
*
|
|
290
|
+
* Returns `undefined` when the relation's type isn't registered in this
|
|
291
|
+
* runtime (e.g. a freshly deserialized snapshot whose type entity hasn't been
|
|
292
|
+
* wired up yet, or a relation loaded from storage before its schema is known).
|
|
293
|
+
* To get the Effect Schema from the returned entity, use `Type.getSchema(...)`.
|
|
294
|
+
*/
|
|
295
|
+
var getType = (relation) => getType$1(relation);
|
|
296
|
+
/**
|
|
297
|
+
* @returns The typename of the relation's type.
|
|
298
|
+
* Accepts both reactive relations and snapshots.
|
|
299
|
+
*/
|
|
300
|
+
var getTypename = (entity) => getTypename$1(entity);
|
|
301
|
+
/**
|
|
302
|
+
* Get the database the relation belongs to.
|
|
303
|
+
* Accepts both reactive relations and snapshots.
|
|
304
|
+
*/
|
|
305
|
+
var getDatabase = (entity) => getDatabase$1(entity);
|
|
306
|
+
/**
|
|
307
|
+
* Property that accesses metadata for an entity.
|
|
308
|
+
*
|
|
309
|
+
* Alias for `Entity.Meta`.
|
|
310
|
+
*/
|
|
311
|
+
var Meta = MetaId;
|
|
312
|
+
function getMeta(entity) {
|
|
313
|
+
return getMetaChecked(entity);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* @returns Foreign keys for the relation from the specified source.
|
|
317
|
+
* Accepts both reactive relations and snapshots.
|
|
318
|
+
*/
|
|
319
|
+
var getKeys = (entity, source) => getKeys$1(entity, source);
|
|
320
|
+
/**
|
|
321
|
+
* Delete all keys from the relation for the specified source.
|
|
322
|
+
* Must be called within a `Relation.update` callback.
|
|
323
|
+
*
|
|
324
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
325
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
326
|
+
*/
|
|
327
|
+
var deleteKeys = (entity, source) => deleteKeys$1(entity, source);
|
|
328
|
+
/**
|
|
329
|
+
* Add a tag to the relation.
|
|
330
|
+
* Must be called within a `Relation.update` callback.
|
|
331
|
+
*
|
|
332
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
333
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
334
|
+
*/
|
|
335
|
+
var addTag = (entity, tag) => addTag$1(entity, tag);
|
|
336
|
+
/**
|
|
337
|
+
* Remove a tag from the relation.
|
|
338
|
+
* Must be called within a `Relation.update` callback.
|
|
339
|
+
*
|
|
340
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
341
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
342
|
+
*/
|
|
343
|
+
var removeTag = (entity, tag) => removeTag$1(entity, tag);
|
|
344
|
+
/**
|
|
345
|
+
* Check if the relation is deleted.
|
|
346
|
+
* Accepts both reactive relations and snapshots.
|
|
347
|
+
*/
|
|
348
|
+
var isDeleted = (entity) => isDeleted$1(entity);
|
|
349
|
+
/**
|
|
350
|
+
* Get the label of the relation.
|
|
351
|
+
* Accepts both reactive relations and snapshots.
|
|
352
|
+
*
|
|
353
|
+
* @param options.fallback `'typename'` returns the relation's typename when no
|
|
354
|
+
* label is set (e.g. `org.dxos.type.table`).
|
|
355
|
+
*/
|
|
356
|
+
var getLabel = (entity, options) => getLabel$1(entity, options);
|
|
357
|
+
/**
|
|
358
|
+
* Set the label of the relation.
|
|
359
|
+
* Must be called within a `Relation.update` callback.
|
|
360
|
+
*
|
|
361
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
362
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
363
|
+
*/
|
|
364
|
+
var setLabel = (entity, label) => setLabel$1(entity, label);
|
|
365
|
+
/**
|
|
366
|
+
* Get the description of the relation.
|
|
367
|
+
* Accepts both reactive relations and snapshots.
|
|
368
|
+
*/
|
|
369
|
+
var getDescription = (entity) => getDescription$1(entity);
|
|
370
|
+
/**
|
|
371
|
+
* Set the description of the relation.
|
|
372
|
+
* Must be called within a `Relation.update` callback.
|
|
373
|
+
*
|
|
374
|
+
* NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`
|
|
375
|
+
* parameters, so there is no compile-time error. Enforcement is runtime-only.
|
|
376
|
+
*/
|
|
377
|
+
var setDescription = (entity, description) => setDescription$1(entity, description);
|
|
378
|
+
/**
|
|
379
|
+
* Converts relation to its JSON representation.
|
|
380
|
+
* Accepts both reactive relations and snapshots.
|
|
381
|
+
*/
|
|
382
|
+
var toJSON = (entity) => objectToJSON(entity);
|
|
383
|
+
var sortByLabel = sortByLabel$1;
|
|
384
|
+
var sortByTypename = sortByTypename$1;
|
|
385
|
+
var sort = (...comparators) => sort$1(...comparators);
|
|
386
|
+
var VersionTypeId = VersionTypeId$1;
|
|
387
|
+
var isVersion = isVersion$1;
|
|
388
|
+
/**
|
|
389
|
+
* Returns the version of the relation.
|
|
390
|
+
* Accepts both reactive relations and snapshots.
|
|
391
|
+
*/
|
|
392
|
+
var version = (entity) => version$1(entity);
|
|
393
|
+
var atom = makeRelation;
|
|
394
|
+
//#endregion
|
|
395
|
+
export { Meta, Source, Target, Unknown, VersionTypeId, addTag, atom, deleteKeys, getDatabase, getDescription, getKeys, getLabel, getMeta, getSnapshot, getSource, getSourceURI, getTarget, getTargetURI, getType, getTypeURI, getTypename, getURI, getValue, instanceOf, isDeleted, isRelation, isSnapshot, isVersion, make, removeTag, setDescription, setLabel, setParent, setValue, sort, sortByLabel, sortByTypename, subscribe, Relation_exports as t, toJSON, update, version };
|
|
396
|
+
|
|
397
|
+
//# sourceMappingURL=Relation.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Relation.mjs","names":[],"sources":["../../src/Relation.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { raise } from '@dxos/debug';\nimport type { ForeignKey } from '@dxos/echo-protocol';\nimport { SchemaEx } from '@dxos/effect';\nimport { assertArgument, invariant } from '@dxos/invariant';\nimport { DXN, EID, type EntityId, type URI } from '@dxos/keys';\nimport { assumeType } from '@dxos/util';\n\nimport type * as Database from './Database';\nimport * as Entity from './Entity';\nimport * as internal from './internal';\nimport * as entityInternal from './internal/Entity';\nimport * as objInternal from './internal/Obj';\nimport * as Obj from './Obj';\nimport type * as Ref from './Ref';\nimport type * as Tag from './Tag';\nimport * as Type from './Type';\n\nexport type Endpoints<Source, Target> = {\n [Source]: Source;\n [Target]: Target;\n};\n\n/**\n * Base type for all ECHO relations.\n * @private\n */\ninterface BaseRelation<Source, Target>\n extends internal.AnyEntity, Endpoints<Source, Target>, Entity.OfKind<internal.EntityKind.Relation> {}\n\n/**\n * Relation with no known properties beyond id, kind, source, and target.\n * Use this when the relation's schema/properties are not known.\n *\n * NOTE: This is a TypeScript type only, not a schema.\n * To validate that a value is an ECHO relation, use `Relation.isRelation`.\n */\nexport interface Unknown extends BaseRelation<Obj.Unknown, Obj.Unknown> {}\n\n/**\n * Runtime Effect schema for any ECHO relation.\n * Use for validation, parsing, or as a reference target for collections.\n * A relation has `id`, source, and target fields plus any additional properties.\n *\n * NOTE: `Schema.is(Type.Relation)` does STRUCTURAL validation only (checks for `id` field).\n * Use `Relation.isRelation()` for proper ECHO instance type guards that check the KindId brand.\n *\n * @example\n * ```ts\n * // Structural type guard (accepts any object with id field)\n * if (Schema.is(Type.Relation)(unknownValue)) { ... }\n *\n * // ECHO instance type guard (checks KindId brand)\n * if (Relation.isRelation(unknownValue)) { ... }\n * ```\n */\n// TODO(dmaretskyi): Change ObjModule.Any to ObjModule.Unknown to have stricter types.\nexport const Unknown: internal.UnknownTypeSchema<Unknown, typeof Entity.Kind.Relation> = Schema.Struct({\n id: Schema.String,\n}).pipe(\n Schema.extend(Schema.Record({ key: Schema.String, value: Schema.Unknown })),\n Schema.annotations({\n [internal.TypeAnnotationId]: {\n kind: Entity.Kind.Relation,\n typename: 'org.dxos.schema.anyRelation',\n version: '0.0.0',\n sourceSchema: DXN.make(internal.ANY_OBJECT_TYPENAME, internal.ANY_OBJECT_VERSION),\n targetSchema: DXN.make(internal.ANY_OBJECT_TYPENAME, internal.ANY_OBJECT_VERSION),\n },\n }),\n) as unknown as internal.UnknownTypeSchema<Unknown, typeof Entity.Kind.Relation>;\n\n/**\n * Relation type with specific source and target types.\n */\nexport type OfShape<Source extends Obj.Unknown, Target extends Obj.Unknown, Props> = BaseRelation<Source, Target> &\n Props;\n\n/**\n * Base type for snapshot relations (has SnapshotKindId instead of KindId).\n */\ninterface BaseRelationSnapshot<Source, Target> extends internal.AnyEntity, Endpoints<Source, Target> {\n readonly [Entity.SnapshotKindId]: internal.EntityKind.Relation;\n readonly id: EntityId;\n}\n\n/**\n * JSON-encoded properties for relations.\n */\nexport interface BaseRelationJson {\n id: string;\n [internal.ATTR_RELATION_SOURCE]: string;\n [internal.ATTR_RELATION_TARGET]: string;\n}\n\n/**\n * Immutable snapshot of an ECHO relation.\n * Branded with SnapshotKindId (not KindId).\n * Property values are frozen at the time the snapshot was created.\n * Returned by getSnapshot() and hooks.\n */\nexport type Snapshot<T extends Unknown = Unknown> = Omit<T, Entity.KindId> &\n BaseRelationSnapshot<Obj.Unknown, Obj.Unknown>;\n\nexport const Source: unique symbol = entityInternal.RelationSourceId as any;\nexport type Source = typeof Source;\n\nexport const Target: unique symbol = entityInternal.RelationTargetId as any;\nexport type Target = typeof Target;\n\n/**\n * Get relation source type.\n */\nexport type SourceOf<A> = A extends Endpoints<infer S, infer _T> ? S : never;\n\n/**\n * Get relation target type.\n */\nexport type TargetOf<A> = A extends Endpoints<infer _S, infer T> ? T : never;\n\n/**\n * Internal props type for relation instance creation.\n */\ntype MakePropsInternal<T extends Endpoints<any, any>> = {\n id?: EntityId;\n [Meta]?: Partial<internal.EntityMeta>;\n [Source]: T[Source];\n [Target]: T[Target];\n} & Entity.Properties<T>;\n\n/**\n * Props type for relation creation with a given schema. Accepts a `Type.AnyRelation`\n * entity (created with `Type.makeRelation`) and derives the props shape via\n * `Type.InstanceType`. Object-kind entities are rejected at the type level —\n * use `Obj.MakeProps` for those.\n */\nexport type MakeProps<S extends Type.AnyRelation> = MakePropsInternal<Type.InstanceType<S>>;\n\n/**\n * Creates new relation.\n * @param schema - Relation schema.\n * @param props - Relation properties. Endpoints are passed as [Relation.Source] and [Relation.Target] keys.\n * @param meta - Relation metadata. (deprecated; use [Obj.Meta] instead)\n * @returns\n */\n// NOTE: Writing the definition this way (with generic over schema) makes typescript perfer to infer the type from the first param (this schema) rather than the second param (the props).\n// TODO(dmaretskyi): Move meta into props.\nexport const make = <T extends Type.AnyRelation>(\n type: T,\n props: NoInfer<MakeProps<T>>,\n): Type.InstanceType<T> & Entity.OfKind<typeof Entity.Kind.Relation> => {\n const schema = Type.getSchema(type);\n assertArgument(\n internal.getTypeAnnotation(schema)?.kind === internal.EntityKind.Relation,\n 'schema',\n 'Expected a relation schema',\n );\n assertArgument(props[internal.ParentId] === undefined, 'props', 'Parent is not allowed for relations');\n\n let meta: internal.EntityMeta | undefined = undefined;\n\n if (props[internal.MetaId] != null) {\n meta = props[internal.MetaId] as any;\n delete props[internal.MetaId];\n }\n\n const sourceDXN = internal.getObjectEchoUri(props[Source]) ?? raise(new Error('Unresolved relation source'));\n const targetDXN = internal.getObjectEchoUri(props[Target]) ?? raise(new Error('Unresolved relation target'));\n\n (props as any)[internal.RelationSourceDXNId] = sourceDXN;\n (props as any)[internal.RelationTargetDXNId] = targetDXN;\n\n // Pass the type entity through as `typeSource` so the resulting instance\n // carries a back-reference resolvable via `Relation.getType` / `Entity.getType`.\n return internal.makeObject(schema as any, props as any, meta, type as any) as any;\n};\n\n/**\n * Test if a value is an instance of a given relation type.\n *\n * Mirrors `Obj.instanceOf` but only accepts `Type.AnyRelation` — use\n * `Obj.instanceOf` for objects and `Type.isType` for `Type.Type` entities.\n *\n * @example\n * ```ts\n * const isEmployedBy = Relation.instanceOf(EmployedBy);\n * if (isEmployedBy(relation)) {\n * // relation is EmployedBy\n * }\n * ```\n */\nexport const instanceOf: {\n <S extends Type.AnyRelation>(schema: S): (value: unknown) => value is Type.InstanceType<S>;\n <S extends Type.AnyRelation>(schema: S, value: unknown): value is Type.InstanceType<S>;\n} = ((...args: [schema: Type.AnyRelation, value?: unknown]) => {\n if (args.length === 1) {\n return (entity: unknown) => internal.isInstanceOf(args[0], entity);\n }\n return internal.isInstanceOf(args[0], args[1]);\n}) as any;\n\n/**\n * Type guard for relations.\n * Returns true for both reactive relations and relation snapshots.\n */\nexport const isRelation = (value: unknown): value is Unknown => {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n if (internal.ATTR_RELATION_SOURCE in value || internal.ATTR_RELATION_TARGET in value) {\n return true;\n }\n\n // Check for reactive relation (KindId) or snapshot (SnapshotKindId).\n const kind = (value as any)[Entity.KindId] ?? (value as any)[Entity.SnapshotKindId];\n return kind === internal.EntityKind.Relation;\n};\n\nexport const isSnapshot = (value: unknown): value is Snapshot => {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n return (value as any)[Entity.SnapshotKindId] === internal.EntityKind.Relation;\n};\n\n/**\n * Sets a relation as the parent of an object: the object cascade-deletes with the relation and is\n * persisted transitively when the relation is added. The delete-cascade resolves the parent by id\n * regardless of kind. The object-parent counterpart is {@link Obj.setParent}.\n */\nexport const setParent = (entity: Obj.Unknown, parent: Unknown): Obj.Unknown => {\n assertArgument(Obj.isObject(entity), 'Expected an object');\n assertArgument(isRelation(parent), 'Expected a relation');\n assumeType<internal.InternalObjectProps>(entity);\n assumeType<internal.InternalObjectProps>(parent);\n entity[internal.ParentId] = parent;\n return entity;\n};\n\n/**\n * @returns Relation source URI.\n * Accepts both reactive relations and snapshots.\n * @throws If the object is not a relation.\n */\nexport const getSourceURI = (value: Unknown | Snapshot): EID.EID => {\n assertArgument(isRelation(value), 'Expected a relation');\n assumeType<internal.InternalObjectProps>(value);\n const uri = (value as internal.InternalObjectProps)[internal.RelationSourceDXNId];\n invariant(EID.isEID(uri));\n return uri;\n};\n\n/**\n * @returns Relation target URI.\n * Accepts both reactive relations and snapshots.\n * @throws If the object is not a relation.\n */\nexport const getTargetURI = (value: Unknown | Snapshot): EID.EID => {\n assertArgument(isRelation(value), 'Expected a relation');\n assumeType<internal.InternalObjectProps>(value);\n const uri = (value as internal.InternalObjectProps)[internal.RelationTargetDXNId];\n invariant(EID.isEID(uri));\n return uri;\n};\n\n/**\n * @returns Relation source.\n * Accepts both reactive relations and snapshots.\n * @throws If the object is not a relation.\n */\nexport const getSource = <T extends Unknown | Snapshot>(relation: T): SourceOf<T> => {\n assertArgument(isRelation(relation), 'Expected a relation');\n assumeType<internal.InternalObjectProps>(relation);\n const obj = (relation as internal.InternalObjectProps)[internal.RelationSourceId];\n if (obj === undefined) {\n throw new Error(`Relation source could not be resolved.`);\n }\n return obj as SourceOf<T>;\n};\n\n/**\n * @returns Relation target.\n * Accepts both reactive relations and snapshots.\n * @throws If the object is not a relation.\n */\nexport const getTarget = <T extends Unknown | Snapshot>(relation: T): TargetOf<T> => {\n assertArgument(isRelation(relation), 'Expected a relation');\n assumeType<internal.InternalObjectProps>(relation);\n const obj = (relation as internal.InternalObjectProps)[internal.RelationTargetId];\n if (obj === undefined) {\n throw new Error(`Relation target could not be resolved.`);\n }\n return obj as TargetOf<T>;\n};\n\n//\n// Change\n//\n\n/**\n * Makes all properties mutable recursively.\n * Used to provide a mutable view of a relation within `Relation.update`.\n */\nexport type Mutable<T> = internal.Mutable<T>;\n\n/**\n * Perform mutations on an echo relation within a controlled context.\n *\n * All mutations within the callback are batched and trigger a single notification\n * when the callback completes. Direct mutations outside of `Relation.update` will throw\n * an error for echo relations.\n *\n * @param relation - The echo relation to mutate. Use `Obj.update` for objects.\n * @param callback - The callback that performs mutations on the relation.\n *\n * @example\n * ```ts\n * const worksFor = Relation.make(EmployedBy, {\n * [Relation.Source]: person,\n * [Relation.Target]: company,\n * role: 'Engineer',\n * });\n *\n * // Mutate within Relation.update\n * Relation.update(worksFor, (obj) => {\n * obj.role = 'Senior Engineer';\n * });\n * ```\n *\n * Note: Only accepts relations. Use `Obj.update` for objects.\n */\nexport const update = <T extends Unknown>(relation: T, callback: internal.ChangeCallback<T>): void => {\n internal.change(relation, callback);\n};\n\n//\n// Snapshot\n//\n\n/**\n * Returns an immutable snapshot of a relation.\n * The snapshot is branded with SnapshotKindId instead of KindId,\n * making it distinguishable from the reactive relation at the type level.\n */\nexport const getSnapshot: <T extends Unknown>(rel: T) => Snapshot<T> = internal.getSnapshot as any;\n\n//\n// Subscribe\n//\n\n/**\n * Subscribe to relation updates.\n * The callback is called synchronously when the relation is modified.\n * Only accepts reactive relations (not snapshots).\n * @returns Unsubscribe function.\n */\nexport const subscribe = (rel: Unknown, callback: () => void): (() => void) => {\n return internal.subscribe(rel, callback);\n};\n\n//\n// Property Access\n//\n\n/**\n * Get a deeply nested property from a relation.\n * Accepts both reactive relations and snapshots.\n */\nexport const getValue = (rel: Unknown | Snapshot, path: readonly (string | number)[]): any => {\n return SchemaEx.getValue(rel, SchemaEx.createJsonPath(path));\n};\n\n/**\n * Set a deeply nested property on a relation.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const setValue: (rel: Mutable<Unknown>, path: readonly (string | number)[], value: any) => void =\n internal.setValue as any;\n\n//\n// Type\n//\n\n/**\n * Get the canonical URI of the relation. Returns `URI.URI` — today always an EID,\n * but future entity kinds may surface other URI schemes; narrow with `EID.parse(uri)`\n * or `DXN.tryMake(uri)` at the point of use. Accepts both reactive relations and snapshots.\n *\n * @param options.prefer - Controls the URI form (see {@link internal.GetURIOptions}).\n */\nexport const getURI = (entity: Unknown | Snapshot, options?: internal.GetURIOptions): URI.URI =>\n internal.getUri(entity, options);\n\n/**\n * @returns The DXN of the relation's type.\n */\nexport const getTypeURI: (obj: internal.AnyProperties) => URI.URI | undefined = internal.getTypeURI;\n\n/**\n * Get the type entity (`Type.AnyRelation`) the relation was created from.\n *\n * Returns `undefined` when the relation's type isn't registered in this\n * runtime (e.g. a freshly deserialized snapshot whose type entity hasn't been\n * wired up yet, or a relation loaded from storage before its schema is known).\n * To get the Effect Schema from the returned entity, use `Type.getSchema(...)`.\n */\nexport const getType = (relation: Unknown | Snapshot): Type.AnyRelation | undefined =>\n internal.getType(relation) as Type.AnyRelation | undefined;\n\n/**\n * @returns The typename of the relation's type.\n * Accepts both reactive relations and snapshots.\n */\nexport const getTypename = (entity: Unknown | Snapshot): string | undefined => internal.getTypename(entity);\n\n//\n// Database\n//\n\n/**\n * Get the database the relation belongs to.\n * Accepts both reactive relations and snapshots.\n */\nexport const getDatabase = (entity: Unknown | Snapshot): Database.Database | undefined => internal.getDatabase(entity);\n\n//\n// Meta\n//\n\n/**\n * Property that accesses metadata for an entity.\n *\n * Alias for `Entity.Meta`.\n */\nexport const Meta = internal.MetaId;\n\n/**\n * Deeply read-only version of EntityMeta.\n */\nexport type ReadonlyMeta = internal.ReadonlyMeta;\n\n/**\n * Mutable meta type returned by `Relation.getMeta` inside a `Relation.update` callback.\n */\nexport type Meta = internal.Meta;\n\n/**\n * Get the metadata for a relation.\n * Returns mutable meta when passed a mutable relation (inside `Relation.update` callback).\n * Returns read-only meta when passed a regular relation or snapshot.\n */\n// TODO(wittjosiah): When passed a Snapshot, should return a snapshot of meta, not the live meta proxy.\nexport function getMeta(entity: Mutable<Unknown>): Meta;\nexport function getMeta(entity: Unknown | Snapshot): ReadonlyMeta;\nexport function getMeta(entity: Unknown | Snapshot | Mutable<Unknown>): Meta | ReadonlyMeta {\n return internal.getMetaChecked(entity);\n}\n\n/**\n * @returns Foreign keys for the relation from the specified source.\n * Accepts both reactive relations and snapshots.\n */\nexport const getKeys = (entity: Unknown | Snapshot, source: string): ForeignKey[] => internal.getKeys(entity, source);\n\n/**\n * Delete all keys from the relation for the specified source.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const deleteKeys = (entity: Mutable<Unknown>, source: string): void => internal.deleteKeys(entity, source);\n\n/**\n * Add a tag to the relation.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const addTag = (entity: Mutable<Unknown>, tag: Ref.Ref<Tag.Tag>): void => internal.addTag(entity, tag);\n\n/**\n * Remove a tag from the relation.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const removeTag = (entity: Mutable<Unknown>, tag: Ref.Ref<Tag.Tag>): void => internal.removeTag(entity, tag);\n\n/**\n * Check if the relation is deleted.\n * Accepts both reactive relations and snapshots.\n */\nexport const isDeleted = (entity: Unknown | Snapshot): boolean => internal.isDeleted(entity);\n\n//\n// Annotations\n//\n\n/**\n * Get the label of the relation.\n * Accepts both reactive relations and snapshots.\n *\n * @param options.fallback `'typename'` returns the relation's typename when no\n * label is set (e.g. `org.dxos.type.table`).\n */\nexport const getLabel = (entity: Unknown | Snapshot, options?: internal.GetLabelOptions): string | undefined =>\n internal.getLabel(entity, options);\n\n/**\n * Set the label of the relation.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const setLabel = (entity: Mutable<Unknown>, label: string): void => internal.setLabel(entity, label);\n\n/**\n * Get the description of the relation.\n * Accepts both reactive relations and snapshots.\n */\nexport const getDescription = (entity: Unknown | Snapshot): string | undefined => internal.getDescription(entity);\n\n/**\n * Set the description of the relation.\n * Must be called within a `Relation.update` callback.\n *\n * NOTE: TypeScript's structural typing allows readonly objects to be passed to `Mutable<T>`\n * parameters, so there is no compile-time error. Enforcement is runtime-only.\n */\nexport const setDescription = (entity: Mutable<Unknown>, description: string): void =>\n internal.setDescription(entity, description);\n\n//\n// JSON\n//\n\n/**\n * JSON representation of a relation.\n */\nexport type JSON = internal.ObjectJSON;\n\n/**\n * Converts relation to its JSON representation.\n * Accepts both reactive relations and snapshots.\n */\nexport const toJSON = (entity: Unknown | Snapshot): JSON => internal.objectToJSON(entity);\n\n//\n// Sorting\n//\n\n/**\n * Comparator function type for sorting relations.\n * Accepts both reactive relations and snapshots.\n */\nexport type Comparator = internal.Comparator<Unknown | Snapshot>;\n\nexport const sortByLabel: Comparator = internal.sortByLabel as Comparator;\nexport const sortByTypename: Comparator = internal.sortByTypename as Comparator;\nexport const sort = (...comparators: Comparator[]): Comparator => internal.sort(...comparators) as Comparator;\n\n//\n// Version\n//\n\nexport const VersionTypeId = internal.VersionTypeId;\nexport const isVersion = internal.isVersion;\n\n/**\n * Represent relation version.\n */\nexport type Version = internal.EntityVersion;\n\n/**\n * Returns the version of the relation.\n * Accepts both reactive relations and snapshots.\n */\nexport const version = (entity: Unknown | Snapshot): Version => internal.version(entity);\n\n//\n// Atoms\n//\n\nexport const atom = objInternal.makeRelation;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
//#region src/Scope.ts
|
|
3
|
+
var Scope_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
+
feed: () => feed,
|
|
5
|
+
registry: () => registry,
|
|
6
|
+
space: () => space
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Scope targeting a space's automerge documents.
|
|
10
|
+
*
|
|
11
|
+
* With no `spaceId`, targets the owning space — i.e. the space of whichever database
|
|
12
|
+
* executes the query — so callers can reference "this space" without looking up its id.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* db.query(Filter.type(Person).from(Scope.space())); // owning space
|
|
17
|
+
* db.query(Filter.type(Person).from(Scope.space({ id: otherSpaceId }))); // a specific space
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
var space = (options) => ({
|
|
21
|
+
_tag: "space",
|
|
22
|
+
...options?.id !== void 0 ? { spaceId: options.id } : {},
|
|
23
|
+
...options?.includeAllFeeds ? { includeAllFeeds: true } : {}
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Scope targeting a code-shipped object/type registry.
|
|
27
|
+
*
|
|
28
|
+
* - `'local'` — the in-process registry attached to the hypergraph (default).
|
|
29
|
+
* - `'remote'` — a remote registry service (not yet implemented).
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* // Discover all types — persisted in the space and code-shipped in the registry.
|
|
34
|
+
* db.query(Filter.type(Type.Type).from(Scope.space(), Scope.registry()));
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
var registry = (location = "local") => ({
|
|
38
|
+
_tag: "registry",
|
|
39
|
+
location
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Scope targeting a specific feed (by its underlying queue EID).
|
|
43
|
+
*/
|
|
44
|
+
var feed = (feedUri) => ({
|
|
45
|
+
_tag: "feed",
|
|
46
|
+
feedUri
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
49
|
+
export { feed, registry, space, Scope_exports as t };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=Scope.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scope.mjs","names":[],"sources":["../../src/Scope.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { type QueryAST } from '@dxos/echo-protocol';\n\n/**\n * Scope targeting a space's automerge documents.\n *\n * With no `spaceId`, targets the owning space — i.e. the space of whichever database\n * executes the query — so callers can reference \"this space\" without looking up its id.\n *\n * @example\n * ```ts\n * db.query(Filter.type(Person).from(Scope.space())); // owning space\n * db.query(Filter.type(Person).from(Scope.space({ id: otherSpaceId }))); // a specific space\n * ```\n */\nexport const space = (options?: { id?: string; includeAllFeeds?: boolean }): QueryAST.SpaceScope => ({\n _tag: 'space',\n ...(options?.id !== undefined ? { spaceId: options.id } : {}),\n ...(options?.includeAllFeeds ? { includeAllFeeds: true } : {}),\n});\n\n/**\n * Scope targeting a code-shipped object/type registry.\n *\n * - `'local'` — the in-process registry attached to the hypergraph (default).\n * - `'remote'` — a remote registry service (not yet implemented).\n *\n * @example\n * ```ts\n * // Discover all types — persisted in the space and code-shipped in the registry.\n * db.query(Filter.type(Type.Type).from(Scope.space(), Scope.registry()));\n * ```\n */\nexport const registry = (location: 'local' | 'remote' = 'local'): QueryAST.RegistryScope => ({\n _tag: 'registry',\n location,\n});\n\n/**\n * Scope targeting a specific feed (by its underlying queue EID).\n */\nexport const feed = (feedUri: string): QueryAST.FeedScope => ({\n _tag: 'feed',\n feedUri,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoBA,IAAa,SAAS,aAA+E;CACnG,MAAM;CACN,GAAI,SAAS,OAAO,KAAA,IAAY,EAAE,SAAS,QAAQ,GAAG,IAAI,CAAC;CAC3D,GAAI,SAAS,kBAAkB,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAC9D;;;;;;;;;;;;;AAcA,IAAa,YAAY,WAA+B,aAAqC;CAC3F,MAAM;CACN;AACF;;;;AAKA,IAAa,QAAQ,aAAyC;CAC5D,MAAM;CACN;AACF"}
|
package/dist/lib/Tag.mjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { _ as TagTypeDXN } from "./chunk-atom-snapshot.mjs";
|
|
3
|
+
import { G as HiddenAnnotation, Y as LabelAnnotation } from "./chunk-Database.mjs";
|
|
4
|
+
import { makeObject } from "./Type.mjs";
|
|
5
|
+
import { Meta, getMeta, make as make$1, update } from "./Obj.mjs";
|
|
6
|
+
import { foreignKeys, type } from "./Filter.mjs";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
//#region src/Tag.ts
|
|
9
|
+
var Tag_exports = /* @__PURE__ */ __exportAll({
|
|
10
|
+
Tag: () => Tag,
|
|
11
|
+
createTagList: () => createTagList,
|
|
12
|
+
findOrCreate: () => findOrCreate,
|
|
13
|
+
findTagByLabel: () => findTagByLabel,
|
|
14
|
+
make: () => make,
|
|
15
|
+
sortTags: () => sortTags
|
|
16
|
+
});
|
|
17
|
+
var Tag = class extends makeObject(TagTypeDXN)(Schema.Struct({
|
|
18
|
+
label: Schema.String,
|
|
19
|
+
hue: Schema.optional(Schema.String)
|
|
20
|
+
}).pipe(LabelAnnotation.set(["label"]), HiddenAnnotation.set(true))) {};
|
|
21
|
+
var make = (props) => make$1(Tag, props);
|
|
22
|
+
var sortTags = ({ label: a }, { label: b }) => a.localeCompare(b);
|
|
23
|
+
var createTagList = (tags) => Object.entries(tags).map(([id, tag]) => ({
|
|
24
|
+
...tag,
|
|
25
|
+
id
|
|
26
|
+
})).sort(sortTags);
|
|
27
|
+
var findTagByLabel = (tags, name) => {
|
|
28
|
+
const entry = Object.entries(tags ?? {}).find(([_, tag]) => tag.label.toLowerCase() === name.toLowerCase());
|
|
29
|
+
return entry ? {
|
|
30
|
+
...entry[1],
|
|
31
|
+
id: entry[0]
|
|
32
|
+
} : void 0;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Finds or creates a {@link Tag} object in the database.
|
|
36
|
+
*
|
|
37
|
+
* - With a foreign `key` (system/provider tags): matched by that key; the label is kept current on
|
|
38
|
+
* re-sync. Use a stable key (e.g. `{ source: 'google.com/gmail/label', id }`) for tags whose
|
|
39
|
+
* identity is external or well-known.
|
|
40
|
+
* - Without a key (user tags): matched by case-insensitive label among tags that carry **no**
|
|
41
|
+
* foreign key, so it never collides with a keyed system/provider tag of the same label.
|
|
42
|
+
*/
|
|
43
|
+
var findOrCreate = async (db, options) => {
|
|
44
|
+
const { label, hue, key } = options;
|
|
45
|
+
const withHue = hue ? { hue } : {};
|
|
46
|
+
if (key) {
|
|
47
|
+
const [existing] = await db.query(foreignKeys(Tag, [key])).run();
|
|
48
|
+
if (existing) {
|
|
49
|
+
if (existing.label !== label || hue !== void 0 && existing.hue !== hue) update(existing, (existing) => {
|
|
50
|
+
existing.label = label;
|
|
51
|
+
if (hue !== void 0) existing.hue = hue;
|
|
52
|
+
});
|
|
53
|
+
return existing;
|
|
54
|
+
}
|
|
55
|
+
return db.add(make$1(Tag, {
|
|
56
|
+
[Meta]: { keys: [key] },
|
|
57
|
+
label,
|
|
58
|
+
...withHue
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
const lowered = label.toLowerCase();
|
|
62
|
+
return (await db.query(type(Tag)).run()).find((tag) => tag.label.toLowerCase() === lowered && (getMeta(tag).keys ?? []).length === 0) ?? db.add(make({
|
|
63
|
+
label,
|
|
64
|
+
...withHue
|
|
65
|
+
}));
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
68
|
+
export { Tag, createTagList, findOrCreate, findTagByLabel, make, sortTags, Tag_exports as t };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=Tag.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tag.mjs","names":[],"sources":["../../src/Tag.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport type { ForeignKey } from '@dxos/echo-protocol';\n\nimport type * as Database from './Database';\nimport * as Filter from './Filter';\nimport * as internal from './internal';\nimport * as Obj from './Obj';\nimport * as Type from './Type';\n\nexport class Tag extends Type.makeObject<Tag>(internal.TagTypeDXN)(\n Schema.Struct({\n label: Schema.String,\n hue: Schema.optional(Schema.String), // TODO(burdon): Color name?\n }).pipe(internal.LabelAnnotation.set(['label']), internal.HiddenAnnotation.set(true)),\n) {}\n\nexport const make = (props: Obj.MakeProps<typeof Tag>) => Obj.make(Tag, props);\n\nexport type Map = Record<string, Type.InstanceType<typeof Tag>>;\n\nexport const sortTags = ({ label: a }: Type.InstanceType<typeof Tag>, { label: b }: Type.InstanceType<typeof Tag>) =>\n a.localeCompare(b);\n\nexport const createTagList = (tags: Map): Type.InstanceType<typeof Tag>[] =>\n Object.entries(tags)\n .map(([id, tag]) => ({ ...tag, id }))\n .sort(sortTags);\n\nexport const findTagByLabel = (tags: Map | undefined, name: string): Type.InstanceType<typeof Tag> | undefined => {\n const entry = Object.entries(tags ?? {}).find(([_, tag]) => tag.label.toLowerCase() === name.toLowerCase());\n return entry ? { ...entry[1], id: entry[0] } : undefined;\n};\n\n/**\n * Finds or creates a {@link Tag} object in the database.\n *\n * - With a foreign `key` (system/provider tags): matched by that key; the label is kept current on\n * re-sync. Use a stable key (e.g. `{ source: 'google.com/gmail/label', id }`) for tags whose\n * identity is external or well-known.\n * - Without a key (user tags): matched by case-insensitive label among tags that carry **no**\n * foreign key, so it never collides with a keyed system/provider tag of the same label.\n */\nexport const findOrCreate = async (\n db: Pick<Database.Database, 'query' | 'add'>,\n options: { label: string; hue?: string; key?: ForeignKey },\n): Promise<Type.InstanceType<typeof Tag>> => {\n const { label, hue, key } = options;\n const withHue = hue ? { hue } : {};\n if (key) {\n const [existing] = await db.query(Filter.foreignKeys(Tag, [key])).run();\n if (existing) {\n // Keep label (and hue, when provided) current on re-sync. `hue` is only touched when supplied,\n // so a label-only re-sync (e.g. Gmail) doesn't wipe a user-set colour.\n if (existing.label !== label || (hue !== undefined && existing.hue !== hue)) {\n Obj.update(existing, (existing) => {\n existing.label = label;\n if (hue !== undefined) {\n existing.hue = hue;\n }\n });\n }\n return existing;\n }\n\n return db.add(Obj.make(Tag, { [Obj.Meta]: { keys: [key] }, label, ...withHue }));\n }\n\n const lowered = label.toLowerCase();\n const candidates = await db.query(Filter.type(Tag)).run();\n const existing = candidates.find(\n (tag) => tag.label.toLowerCase() === lowered && (Obj.getMeta(tag).keys ?? []).length === 0,\n );\n return existing ?? db.add(make({ label, ...withHue }));\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,IAAa,MAAb,cAAyB,WAAqB,UAAmB,CAAC,CAChE,OAAO,OAAO;CACZ,OAAO,OAAO;CACd,KAAK,OAAO,SAAS,OAAO,MAAM;AACpC,CAAC,CAAC,CAAC,KAAA,gBAA8B,IAAI,CAAC,OAAO,CAAC,GAAA,iBAA6B,IAAI,IAAI,CAAC,CACtF,CAAC,CAAC,CAAC;AAEH,IAAa,QAAQ,UAAqC,OAAS,KAAK,KAAK;AAI7E,IAAa,YAAY,EAAE,OAAO,KAAoC,EAAE,OAAO,QAC7E,EAAE,cAAc,CAAC;AAEnB,IAAa,iBAAiB,SAC5B,OAAO,QAAQ,IAAI,CAAA,CAChB,KAAK,CAAC,IAAI,UAAU;CAAE,GAAG;CAAK;AAAG,EAAE,CAAA,CACnC,KAAK,QAAQ;AAElB,IAAa,kBAAkB,MAAuB,SAA4D;CAChH,MAAM,QAAQ,OAAO,QAAQ,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,MAAM,YAAY,MAAM,KAAK,YAAY,CAAC;CAC1G,OAAO,QAAQ;EAAE,GAAG,MAAM;EAAI,IAAI,MAAM;CAAG,IAAI,KAAA;AACjD;;;;;;;;;;AAWA,IAAa,eAAe,OAC1B,IACA,YAC2C;CAC3C,MAAM,EAAE,OAAO,KAAK,QAAQ;CAC5B,MAAM,UAAU,MAAM,EAAE,IAAI,IAAI,CAAC;CACjC,IAAI,KAAK;EACP,MAAM,CAAC,YAAY,MAAM,GAAG,MAAM,YAAmB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;EACtE,IAAI,UAAU;GAGZ,IAAI,SAAS,UAAU,SAAU,QAAQ,KAAA,KAAa,SAAS,QAAQ,KACrE,OAAW,WAAW,aAAa;IACjC,SAAS,QAAQ;IACjB,IAAI,QAAQ,KAAA,GACV,SAAS,MAAM;GAEnB,CAAC;GAEH,OAAO;EACT;EAEA,OAAO,GAAG,IAAI,OAAS,KAAK;IAAG,OAAW,EAAE,MAAM,CAAC,GAAG,EAAE;GAAG;GAAO,GAAG;EAAQ,CAAC,CAAC;CACjF;CAEA,MAAM,UAAU,MAAM,YAAY;CAKlC,QAHiB,MADQ,GAAG,MAAM,KAAY,GAAG,CAAC,CAAC,CAAC,IAAI,EAAA,CAC5B,MACzB,QAAQ,IAAI,MAAM,YAAY,MAAM,YAAY,QAAY,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAA,CAAG,WAAW,CAEpF,KAAY,GAAG,IAAI,KAAK;EAAE;EAAO,GAAG;CAAQ,CAAC,CAAC;AACvD"}
|