@dxos/echo 0.8.4-main.d05539e30a → 0.8.4-main.d9fc60f731
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/README.md +4 -4
- package/dist/lib/neutral/Annotation.mjs +27 -6
- package/dist/lib/neutral/Database.mjs +6 -11
- package/dist/lib/neutral/Entity.mjs +25 -16
- package/dist/lib/neutral/Err.mjs +3 -3
- package/dist/lib/neutral/Feed.mjs +19 -17
- package/dist/lib/neutral/Filter.mjs +13 -13
- package/dist/lib/neutral/Format.mjs +23 -3
- package/dist/lib/neutral/JsonSchema.mjs +7 -8
- package/dist/lib/neutral/Key.mjs +9 -5
- package/dist/lib/neutral/Migration.mjs +11 -10
- package/dist/lib/neutral/Obj.mjs +21 -18
- package/dist/lib/neutral/Query.mjs +17 -17
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +10 -11
- package/dist/lib/neutral/Registry.mjs +14 -0
- package/dist/lib/neutral/Relation.mjs +24 -23
- package/dist/lib/neutral/Scope.mjs +12 -0
- package/dist/lib/neutral/Tag.mjs +17 -14
- package/dist/lib/neutral/Type.mjs +52 -26
- package/dist/lib/neutral/chunk-3DKP2EIN.mjs +31 -0
- package/dist/lib/neutral/chunk-3DKP2EIN.mjs.map +7 -0
- package/dist/lib/neutral/chunk-4BB4MFCN.mjs +154 -0
- package/dist/lib/neutral/chunk-4BB4MFCN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-PT37DG2F.mjs → chunk-4SFPZJVA.mjs} +82 -74
- package/dist/lib/neutral/chunk-4SFPZJVA.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-APHSOTIX.mjs → chunk-4Z6GET2X.mjs} +3 -3
- package/dist/lib/neutral/{chunk-APHSOTIX.mjs.map → chunk-4Z6GET2X.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-7RVZT53K.mjs → chunk-7LOUAPYZ.mjs} +9 -5
- package/dist/lib/neutral/chunk-7LOUAPYZ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BMB7IHGB.mjs → chunk-7OAFN3OX.mjs} +70 -57
- package/dist/lib/neutral/chunk-7OAFN3OX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-MLS7U7AT.mjs → chunk-7PRCIDHH.mjs} +41 -28
- package/dist/lib/neutral/chunk-7PRCIDHH.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ZISMEVKD.mjs → chunk-BBFJWWAV.mjs} +6 -6
- package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ZFACXBY6.mjs → chunk-BDQGMDIX.mjs} +30 -34
- package/dist/lib/neutral/chunk-BDQGMDIX.mjs.map +7 -0
- package/dist/lib/neutral/chunk-CGTI5MXO.mjs +36 -0
- package/dist/lib/neutral/chunk-CGTI5MXO.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-V72DY6LU.mjs → chunk-DKLUHO4T.mjs} +1 -1
- package/dist/lib/neutral/chunk-DKLUHO4T.mjs.map +7 -0
- package/dist/lib/neutral/chunk-DMN2CKPX.mjs +93 -0
- package/dist/lib/neutral/chunk-DMN2CKPX.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-QRZ2I3ZM.mjs → chunk-G6CFWUYH.mjs} +2 -2
- package/dist/lib/neutral/chunk-H26LSXVJ.mjs +653 -0
- package/dist/lib/neutral/chunk-H26LSXVJ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-N7VOEPSV.mjs → chunk-J3MNM65T.mjs} +9 -9
- package/dist/lib/neutral/chunk-J3MNM65T.mjs.map +7 -0
- package/dist/lib/neutral/chunk-JE7AOSWF.mjs +247 -0
- package/dist/lib/neutral/chunk-JE7AOSWF.mjs.map +7 -0
- package/dist/lib/neutral/chunk-LAF3LSWI.mjs +379 -0
- package/dist/lib/neutral/chunk-LAF3LSWI.mjs.map +7 -0
- package/dist/lib/neutral/chunk-LMNRFOVB.mjs +108 -0
- package/dist/lib/neutral/chunk-LMNRFOVB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-N4B7FHQT.mjs → chunk-O6BH7EPN.mjs} +30 -3
- package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-Q7ZL2P5H.mjs → chunk-OIYW7R2G.mjs} +62 -46
- package/dist/lib/neutral/chunk-OIYW7R2G.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-G54OX4IX.mjs → chunk-OYUG4FHF.mjs} +527 -847
- package/dist/lib/neutral/chunk-OYUG4FHF.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-J54QMAKF.mjs → chunk-Q5FKCVBC.mjs} +64 -59
- package/dist/lib/neutral/chunk-Q5FKCVBC.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-FIWO2FZK.mjs → chunk-Q62IHV2N.mjs} +12 -7
- package/dist/lib/neutral/chunk-Q62IHV2N.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-SCPFDS2E.mjs → chunk-QVJDDG44.mjs} +65 -34
- package/dist/lib/neutral/chunk-QVJDDG44.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TRPZU2HV.mjs → chunk-TFEWTY5A.mjs} +155 -129
- package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-44HT3MEC.mjs → chunk-VKWOFXT2.mjs} +22 -2
- package/dist/lib/neutral/{chunk-44HT3MEC.mjs.map → chunk-VKWOFXT2.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-APJKDGFL.mjs → chunk-ZACMEAYV.mjs} +24 -24
- package/dist/lib/neutral/chunk-ZACMEAYV.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +50 -40
- package/dist/lib/neutral/internal/index.mjs +125 -64
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +88 -99
- package/dist/lib/neutral/testing/index.mjs.map +3 -3
- package/dist/types/src/Annotation.d.ts +108 -4
- package/dist/types/src/Annotation.d.ts.map +1 -1
- package/dist/types/src/Annotation.test.d.ts +2 -0
- package/dist/types/src/Annotation.test.d.ts.map +1 -0
- package/dist/types/src/Collection.d.ts +2 -3
- package/dist/types/src/Collection.d.ts.map +1 -1
- package/dist/types/src/Database.d.ts +50 -30
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Dataset.d.ts +16 -6
- package/dist/types/src/Dataset.d.ts.map +1 -1
- package/dist/types/src/Entity.d.ts +89 -19
- package/dist/types/src/Entity.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +9 -9
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Feed.d.ts +35 -12
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Filter.d.ts +21 -8
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +13 -8
- package/dist/types/src/Hypergraph.d.ts.map +1 -1
- package/dist/types/src/Json.d.ts.map +1 -1
- package/dist/types/src/JsonSchema.d.ts +1 -1
- package/dist/types/src/JsonSchema.d.ts.map +1 -1
- package/dist/types/src/Key.d.ts +1 -1
- package/dist/types/src/Key.d.ts.map +1 -1
- package/dist/types/src/Migration.d.ts +15 -12
- package/dist/types/src/Migration.d.ts.map +1 -1
- package/dist/types/src/Obj.d.ts +69 -40
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +24 -10
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/QueryResult.d.ts +9 -0
- package/dist/types/src/QueryResult.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +15 -8
- package/dist/types/src/Ref.d.ts.map +1 -1
- package/dist/types/src/Registry.d.ts +131 -0
- package/dist/types/src/Registry.d.ts.map +1 -0
- package/dist/types/src/Relation.d.ts +55 -26
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Scope.d.ts +34 -0
- package/dist/types/src/Scope.d.ts.map +1 -0
- package/dist/types/src/StateMap.d.ts +32 -0
- package/dist/types/src/StateMap.d.ts.map +1 -0
- package/dist/types/src/StateMap.test.d.ts +2 -0
- package/dist/types/src/StateMap.test.d.ts.map +1 -0
- package/dist/types/src/Tag.d.ts +19 -3
- package/dist/types/src/Tag.d.ts.map +1 -1
- package/dist/types/src/TagIndex.d.ts +36 -0
- package/dist/types/src/TagIndex.d.ts.map +1 -0
- package/dist/types/src/TagIndex.test.d.ts +2 -0
- package/dist/types/src/TagIndex.test.d.ts.map +1 -0
- package/dist/types/src/Tagging.d.ts +31 -0
- package/dist/types/src/Tagging.d.ts.map +1 -0
- package/dist/types/src/Type.d.ts +356 -95
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +1 -4
- package/dist/types/src/View.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +6 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/annotations.d.ts +68 -36
- package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/dictionary.d.ts +24 -0
- package/dist/types/src/internal/Annotation/dictionary.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/entity-dictionary.d.ts +14 -0
- package/dist/types/src/internal/Annotation/entity-dictionary.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/index.d.ts +4 -2
- package/dist/types/src/internal/Annotation/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/util.d.ts +13 -4
- package/dist/types/src/internal/Annotation/util.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/api.d.ts +3 -3
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/entity.d.ts +72 -8
- package/dist/types/src/internal/Entity/entity.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/guard.d.ts +10 -0
- package/dist/types/src/internal/Entity/guard.d.ts.map +1 -0
- package/dist/types/src/internal/Entity/index.d.ts +2 -0
- package/dist/types/src/internal/Entity/index.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/model.d.ts +18 -17
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/object.d.ts +3 -3
- package/dist/types/src/internal/Entity/object.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/relation.d.ts +30 -7
- package/dist/types/src/internal/Entity/relation.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/type-kind.d.ts +24 -0
- package/dist/types/src/internal/Entity/type-kind.d.ts.map +1 -0
- package/dist/types/src/internal/Entity/type-uri.d.ts +25 -0
- package/dist/types/src/internal/Entity/type-uri.d.ts.map +1 -0
- package/dist/types/src/internal/Format/date.d.ts.map +1 -1
- package/dist/types/src/internal/Format/format.d.ts +3 -2
- package/dist/types/src/internal/Format/format.d.ts.map +1 -1
- package/dist/types/src/internal/Format/index.d.ts +2 -2
- package/dist/types/src/internal/Format/index.d.ts.map +1 -1
- package/dist/types/src/internal/Format/object.d.ts +3 -1
- package/dist/types/src/internal/Format/object.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts +2 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/create-object.d.ts +11 -12
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/index.d.ts +0 -1
- package/dist/types/src/internal/Obj/index.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/json-serializer.d.ts +8 -8
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/snapshot.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/typed-object.d.ts +1 -1
- package/dist/types/src/internal/Query.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/ref-array.d.ts +2 -2
- package/dist/types/src/internal/Ref/ref.d.ts +29 -19
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
- package/dist/types/src/internal/Type/index.d.ts +1 -2
- package/dist/types/src/internal/Type/index.d.ts.map +1 -1
- package/dist/types/src/internal/Type/manipulation.d.ts +0 -1
- package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -1
- package/dist/types/src/internal/Type/type-schema.d.ts +52 -0
- package/dist/types/src/internal/Type/type-schema.d.ts.map +1 -0
- package/dist/types/src/internal/common/api/meta.d.ts +11 -8
- package/dist/types/src/internal/common/api/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/make-object.d.ts +11 -5
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts +18 -2
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/base.d.ts +4 -4
- package/dist/types/src/internal/common/types/entity.d.ts +59 -2
- package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/index.d.ts +1 -1
- package/dist/types/src/internal/common/types/index.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/meta.d.ts +13 -7
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/model-symbols.d.ts +8 -4
- package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/typename.d.ts +7 -0
- package/dist/types/src/internal/common/types/typename.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/well-known-types.d.ts +11 -0
- package/dist/types/src/internal/common/types/well-known-types.d.ts.map +1 -0
- package/dist/types/src/internal/index.d.ts +1 -0
- package/dist/types/src/internal/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +32 -38
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/dist/types/src/testing/util.d.ts +5 -3
- package/dist/types/src/testing/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +21 -23
- package/src/Annotation.test.ts +439 -0
- package/src/Annotation.ts +151 -4
- package/src/Collection.ts +5 -9
- package/src/Database.ts +86 -61
- package/src/Dataset.ts +10 -2
- package/src/Entity.test.ts +116 -6
- package/src/Entity.ts +116 -23
- package/src/Err.ts +4 -4
- package/src/Feed.ts +57 -40
- package/src/Filter.ts +49 -27
- package/src/Hypergraph.ts +13 -8
- package/src/Json.test.ts +4 -4
- package/src/Json.ts +7 -6
- package/src/Key.ts +1 -1
- package/src/Migration.ts +27 -19
- package/src/Obj.test.ts +19 -8
- package/src/Obj.ts +131 -70
- package/src/Query.test.ts +147 -151
- package/src/Query.ts +133 -75
- package/src/QueryResult.ts +11 -0
- package/src/Ref.ts +21 -5
- package/src/Registry.ts +155 -0
- package/src/Relation.test.ts +10 -10
- package/src/Relation.ts +89 -52
- package/src/Scope.ts +50 -0
- package/src/StateMap.test.ts +56 -0
- package/src/StateMap.ts +99 -0
- package/src/Tag.md +88 -0
- package/src/Tag.ts +49 -6
- package/src/TagIndex.test.ts +57 -0
- package/src/TagIndex.ts +110 -0
- package/src/Tagging.ts +83 -0
- package/src/Type.test.ts +223 -18
- package/src/Type.ts +601 -131
- package/src/View.ts +10 -19
- package/src/index.ts +6 -4
- package/src/internal/Annotation/annotations.test.ts +31 -11
- package/src/internal/Annotation/annotations.ts +122 -103
- package/src/internal/Annotation/dictionary.ts +47 -0
- package/src/internal/Annotation/entity-dictionary.ts +40 -0
- package/src/internal/Annotation/index.ts +4 -2
- package/src/internal/Annotation/util.ts +17 -8
- package/src/internal/Entity/api.ts +7 -7
- package/src/internal/Entity/entity.ts +196 -47
- package/src/internal/Entity/guard.ts +26 -0
- package/src/internal/Entity/index.ts +2 -0
- package/src/internal/Entity/model.ts +35 -28
- package/src/internal/Entity/object.ts +21 -5
- package/src/internal/Entity/relation.ts +68 -34
- package/src/internal/Entity/type-kind.ts +75 -0
- package/src/internal/Entity/type-uri.ts +87 -0
- package/src/internal/Entity/util.ts +10 -9
- package/src/internal/Format/date.ts +0 -4
- package/src/internal/Format/format.test.ts +21 -0
- package/src/internal/Format/index.ts +2 -3
- package/src/internal/Format/object.ts +21 -4
- package/src/internal/Format/types.ts +1 -1
- package/src/internal/JsonSchema/annotations.ts +1 -1
- package/src/internal/JsonSchema/json-schema.test.ts +54 -140
- package/src/internal/JsonSchema/json-schema.ts +44 -30
- package/src/internal/Obj/clone.ts +9 -4
- package/src/internal/Obj/create-object.test.ts +12 -10
- package/src/internal/Obj/create-object.ts +67 -22
- package/src/internal/Obj/index.ts +0 -1
- package/src/internal/Obj/inspect.ts +4 -3
- package/src/internal/Obj/json-serializer.test.ts +100 -21
- package/src/internal/Obj/json-serializer.ts +93 -38
- package/src/internal/Obj/set-value.test.ts +7 -30
- package/src/internal/Obj/snapshot.ts +11 -4
- package/src/internal/Obj/typed-object.test.ts +9 -11
- package/src/internal/Obj/typed-object.ts +1 -1
- package/src/internal/Query.ts +14 -11
- package/src/internal/Ref/ref-array.ts +3 -3
- package/src/internal/Ref/ref.test.ts +17 -26
- package/src/internal/Ref/ref.ts +107 -59
- package/src/internal/Type/compose.test.ts +3 -1
- package/src/internal/Type/index.ts +1 -2
- package/src/internal/Type/manipulation.ts +0 -25
- package/src/internal/Type/type-schema.ts +60 -0
- package/src/internal/common/README.md +1 -1
- package/src/internal/common/api/meta.ts +16 -14
- package/src/internal/common/proxy/change.test.ts +35 -27
- package/src/internal/common/proxy/handler.test.ts +1 -1
- package/src/internal/common/proxy/json-serializer.ts +26 -16
- package/src/internal/common/proxy/make-object.ts +43 -20
- package/src/internal/common/proxy/ownership.ts +2 -2
- package/src/internal/common/proxy/schema.test.ts +48 -86
- package/src/internal/common/proxy/typed-handler.test.ts +12 -11
- package/src/internal/common/proxy/typed-handler.ts +71 -9
- package/src/internal/common/proxy/typed-object.test.ts +15 -27
- package/src/internal/common/types/base.ts +4 -4
- package/src/internal/common/types/entity.ts +80 -1
- package/src/internal/common/types/index.ts +6 -1
- package/src/internal/common/types/meta.ts +37 -14
- package/src/internal/common/types/model-symbols.ts +16 -4
- package/src/internal/common/types/typename.ts +39 -3
- package/src/internal/common/types/well-known-types.ts +15 -0
- package/src/internal/index.ts +5 -0
- package/src/testing/api.test.ts +15 -9
- package/src/testing/test-data.ts +24 -24
- package/src/testing/test-schema.ts +22 -58
- package/src/testing/util.ts +14 -11
- package/dist/lib/neutral/Extension.mjs +0 -18
- package/dist/lib/neutral/SchemaRegistry.mjs +0 -2
- package/dist/lib/neutral/chunk-5SL5LDLD.mjs +0 -47
- package/dist/lib/neutral/chunk-5SL5LDLD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7RVZT53K.mjs.map +0 -7
- package/dist/lib/neutral/chunk-APJKDGFL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BICZKPQG.mjs +0 -7
- package/dist/lib/neutral/chunk-BICZKPQG.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BMB7IHGB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-FIWO2FZK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-G54OX4IX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GWFFC34K.mjs +0 -50
- package/dist/lib/neutral/chunk-GWFFC34K.mjs.map +0 -7
- package/dist/lib/neutral/chunk-I2DARWPX.mjs +0 -128
- package/dist/lib/neutral/chunk-I2DARWPX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J54QMAKF.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MGSQGHOD.mjs +0 -206
- package/dist/lib/neutral/chunk-MGSQGHOD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MLS7U7AT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-N4B7FHQT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-N7VOEPSV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PSZBLH53.mjs +0 -81
- package/dist/lib/neutral/chunk-PSZBLH53.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PT37DG2F.mjs.map +0 -7
- package/dist/lib/neutral/chunk-Q2KKKJSV.mjs +0 -56
- package/dist/lib/neutral/chunk-Q2KKKJSV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-Q7ZL2P5H.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SCPFDS2E.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TNBK56IN.mjs +0 -350
- package/dist/lib/neutral/chunk-TNBK56IN.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TRPZU2HV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-V72DY6LU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZFACXBY6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZISMEVKD.mjs.map +0 -7
- package/dist/types/src/Extension.d.ts +0 -80
- package/dist/types/src/Extension.d.ts.map +0 -1
- package/dist/types/src/Extension.test.d.ts +0 -2
- package/dist/types/src/Extension.test.d.ts.map +0 -1
- package/dist/types/src/SchemaRegistry.d.ts +0 -84
- package/dist/types/src/SchemaRegistry.d.ts.map +0 -1
- package/dist/types/src/internal/Obj/ids.d.ts +0 -6
- package/dist/types/src/internal/Obj/ids.d.ts.map +0 -1
- package/dist/types/src/internal/Type/echo-schema.d.ts +0 -181
- package/dist/types/src/internal/Type/echo-schema.d.ts.map +0 -1
- package/dist/types/src/internal/Type/persistent-schema.d.ts +0 -20
- package/dist/types/src/internal/Type/persistent-schema.d.ts.map +0 -1
- package/src/Extension.test.ts +0 -235
- package/src/Extension.ts +0 -122
- package/src/SchemaRegistry.ts +0 -106
- package/src/internal/Obj/ids.ts +0 -12
- package/src/internal/Type/echo-schema.ts +0 -423
- package/src/internal/Type/persistent-schema.ts +0 -33
- /package/dist/lib/neutral/{Extension.mjs.map → Registry.mjs.map} +0 -0
- /package/dist/lib/neutral/{SchemaRegistry.mjs.map → Scope.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-QRZ2I3ZM.mjs.map → chunk-G6CFWUYH.mjs.map} +0 -0
|
@@ -2,27 +2,44 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import type * as Schema from 'effect/Schema';
|
|
6
|
-
|
|
7
5
|
import { raise } from '@dxos/debug';
|
|
8
6
|
import { assertArgument, failedInvariant } from '@dxos/invariant';
|
|
9
|
-
import {
|
|
7
|
+
import { EntityId } from '@dxos/keys';
|
|
10
8
|
|
|
11
|
-
import
|
|
9
|
+
import type * as Type from '../../Type';
|
|
10
|
+
import { getSchemaURI, getTypeAnnotation, setTypename } from '../Annotation';
|
|
12
11
|
import { defineHiddenProperty } from '../common/proxy';
|
|
13
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
EntityKind,
|
|
14
|
+
KindId,
|
|
15
|
+
SchemaKindId,
|
|
16
|
+
StaticTypeSchemaSlot,
|
|
17
|
+
getStaticTypeSchema,
|
|
18
|
+
setSchema,
|
|
19
|
+
setType,
|
|
20
|
+
} from '../common/types';
|
|
21
|
+
import { MetaId, type EntityMeta } from '../common/types/meta';
|
|
14
22
|
import {
|
|
15
23
|
RelationSourceDXNId,
|
|
16
24
|
RelationSourceId,
|
|
17
25
|
RelationTargetDXNId,
|
|
18
26
|
RelationTargetId,
|
|
19
27
|
assertObjectModel,
|
|
20
|
-
|
|
28
|
+
getObjectEchoUri,
|
|
21
29
|
} from '../Entity';
|
|
22
30
|
import { attachedTypedObjectInspector } from './inspect';
|
|
23
31
|
import { attachTypedJsonSerializer } from './json-serializer';
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
// Omits the brand slots — those get stamped on the instance by the entity
|
|
34
|
+
// handler (KindId via setKind, SchemaKindId derived in the proxy `get` trap
|
|
35
|
+
// from kind + jsonSchema.entityKind, StaticTypeSchemaSlot lazily via the
|
|
36
|
+
// proxy), not supplied by the caller. Allows `[Obj.Meta]` (MetaId symbol) for
|
|
37
|
+
// seeding registry-provenance meta at construction (mirrors `Obj.make`).
|
|
38
|
+
export type CreateObjectProps<T> = (T extends { id: string }
|
|
39
|
+
? Omit<T, 'id' | KindId | SchemaKindId | StaticTypeSchemaSlot> & { id?: string }
|
|
40
|
+
: Omit<T, KindId | SchemaKindId | StaticTypeSchemaSlot>) & {
|
|
41
|
+
readonly [MetaId]?: Partial<EntityMeta>;
|
|
42
|
+
};
|
|
26
43
|
|
|
27
44
|
/**
|
|
28
45
|
* Creates a new object instance from a schema and data, without signal reactivity.
|
|
@@ -40,10 +57,7 @@ export type CreateObjectProps<T> = T extends { id: string } ? Omit<T, 'id' | Kin
|
|
|
40
57
|
* const Contact = Schema.Struct({
|
|
41
58
|
* name: Schema.String,
|
|
42
59
|
* email: Schema.String,
|
|
43
|
-
* }).pipe(Type.
|
|
44
|
-
* typename: 'com.example.type.person',
|
|
45
|
-
* version: '0.1.0',
|
|
46
|
-
* }))
|
|
60
|
+
* }).pipe(Type.makeObject(DXN.make('com.example.type.person', '0.1.0')))
|
|
47
61
|
*
|
|
48
62
|
* const contact = createObject(Contact, {
|
|
49
63
|
* name: "John",
|
|
@@ -52,10 +66,13 @@ export type CreateObjectProps<T> = T extends { id: string } ? Omit<T, 'id' | Kin
|
|
|
52
66
|
* ```
|
|
53
67
|
*/
|
|
54
68
|
// TODO(burdon): Make internal.
|
|
55
|
-
export const createObject
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
69
|
+
export const createObject: {
|
|
70
|
+
<T extends Type.AnyEntity>(input: T, props: NoInfer<CreateObjectProps<Type.InstanceType<T>>>): Type.InstanceType<T>;
|
|
71
|
+
} = (input: any, props: any): any => {
|
|
72
|
+
// `Type.Type` entities aren't `Schema.Schema` themselves; read the source
|
|
73
|
+
// schema off the hidden slot (persisted entities synthesize it lazily via
|
|
74
|
+
// the proxy `get` trap).
|
|
75
|
+
const schema = getStaticTypeSchema(input) ?? failedInvariant('Type entity is missing its source schema');
|
|
59
76
|
const annotation = getTypeAnnotation(schema);
|
|
60
77
|
if (!annotation) {
|
|
61
78
|
throw new Error('Schema is not an ECHO schema');
|
|
@@ -69,22 +86,50 @@ export const createObject = <S extends Schema.Schema.AnyNoContext>(
|
|
|
69
86
|
'Relation source and target must be provided together',
|
|
70
87
|
);
|
|
71
88
|
|
|
89
|
+
// Pull `[Obj.Meta]` (MetaId-symbol) off props before spreading so it doesn't
|
|
90
|
+
// leak into data. Callers use this to seed registry-provenance meta fields
|
|
91
|
+
// (`key`, `version`) and foreign keys / tags at construction time, mirroring
|
|
92
|
+
// `Obj.make`'s symbol-keyed meta convention.
|
|
93
|
+
const metaOverride = props[MetaId];
|
|
94
|
+
if (metaOverride !== undefined) {
|
|
95
|
+
delete props[MetaId];
|
|
96
|
+
}
|
|
97
|
+
|
|
72
98
|
// Raw object.
|
|
73
|
-
const obj = { ...props, id: props.id ??
|
|
99
|
+
const obj = { ...props, id: props.id ?? EntityId.random() };
|
|
74
100
|
|
|
75
|
-
// Metadata.
|
|
76
|
-
|
|
101
|
+
// Metadata. Instance-kind is read from the schema's TypeAnnotation (set by
|
|
102
|
+
// EchoObjectSchema / EchoRelationSchema / EchoTypeKindSchema): instances of
|
|
103
|
+
// a type-kind meta-schema are themselves type-kind entities, etc. The
|
|
104
|
+
// RelationSourceId-in-props check covers the legacy path where the schema
|
|
105
|
+
// annotation isn't authoritative.
|
|
106
|
+
const kind =
|
|
107
|
+
annotation.kind === EntityKind.Type
|
|
108
|
+
? EntityKind.Type
|
|
109
|
+
: annotation.kind === EntityKind.Relation || RelationSourceId in props
|
|
110
|
+
? EntityKind.Relation
|
|
111
|
+
: EntityKind.Object;
|
|
77
112
|
defineHiddenProperty(obj, KindId, kind);
|
|
78
|
-
defineHiddenProperty(obj, MetaId, {
|
|
113
|
+
defineHiddenProperty(obj, MetaId, {
|
|
114
|
+
...metaOverride,
|
|
115
|
+
keys: metaOverride?.keys ?? [],
|
|
116
|
+
tags: metaOverride?.tags ?? [],
|
|
117
|
+
annotations: metaOverride?.annotations ?? {},
|
|
118
|
+
});
|
|
79
119
|
setSchema(obj, schema);
|
|
80
|
-
|
|
120
|
+
// If the caller passed a type entity (recognised via the schema slot), keep
|
|
121
|
+
// a reference to it on the instance for `Obj.getType` / `Relation.getType`.
|
|
122
|
+
if (input !== schema) {
|
|
123
|
+
setType(obj, input);
|
|
124
|
+
}
|
|
125
|
+
setTypename(obj, getSchemaURI(schema) ?? failedInvariant('Missing schema URI'));
|
|
81
126
|
attachTypedJsonSerializer(obj);
|
|
82
127
|
attachedTypedObjectInspector(obj);
|
|
83
128
|
|
|
84
129
|
// Relation.
|
|
85
130
|
if (kind === EntityKind.Relation) {
|
|
86
|
-
const sourceDXN =
|
|
87
|
-
const targetDXN =
|
|
131
|
+
const sourceDXN = getObjectEchoUri(props[RelationSourceId]) ?? raise(new Error('Unresolved relation source'));
|
|
132
|
+
const targetDXN = getObjectEchoUri(props[RelationTargetId]) ?? raise(new Error('Unresolved relation target'));
|
|
88
133
|
defineHiddenProperty(obj, RelationSourceDXNId, sourceDXN);
|
|
89
134
|
defineHiddenProperty(obj, RelationTargetDXNId, targetDXN);
|
|
90
135
|
}
|
|
@@ -6,8 +6,9 @@ import type { InspectOptionsStylized, inspect as inspectFn } from 'node:util';
|
|
|
6
6
|
|
|
7
7
|
import { type CustomInspectFunction, inspectCustom } from '@dxos/debug';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { getTypeURI } from '../Annotation';
|
|
10
|
+
import { ATTR_TYPE, type AnyEntity } from '../common/types';
|
|
11
|
+
import { ATTR_META, MetaId } from '../common/types/meta';
|
|
11
12
|
|
|
12
13
|
/*
|
|
13
14
|
* @internal
|
|
@@ -37,7 +38,7 @@ const typedObjectInspectFunction: CustomInspectFunction<AnyEntity> = function (
|
|
|
37
38
|
return inspect(
|
|
38
39
|
{
|
|
39
40
|
id,
|
|
40
|
-
[ATTR_TYPE]:
|
|
41
|
+
[ATTR_TYPE]: getTypeURI(this),
|
|
41
42
|
...props,
|
|
42
43
|
[ATTR_META]: (this as any)[MetaId], // TODO(dmaretskyi): Couldn't use getMeta since that throw's if the object has no meta.
|
|
43
44
|
},
|
|
@@ -2,24 +2,27 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
5
6
|
import { describe, expect, test } from 'vitest';
|
|
6
7
|
|
|
7
|
-
import { DXN } from '@dxos/keys';
|
|
8
|
+
import { DXN, EID } from '@dxos/keys';
|
|
8
9
|
|
|
9
10
|
import * as Obj from '../../Obj';
|
|
10
11
|
import { TestSchema } from '../../testing';
|
|
11
|
-
import
|
|
12
|
+
import * as Type from '../../Type';
|
|
13
|
+
import { getTypeURI, getTypename } from '../Annotation';
|
|
12
14
|
import { getMetaChecked } from '../common/api';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { RelationSourceId, RelationTargetId,
|
|
15
|
+
import { ATTR_TYPE, EntityKind, KindId, TypeId, getSchema } from '../common/types';
|
|
16
|
+
import { MetaId } from '../common/types/meta';
|
|
17
|
+
import { RelationSourceId, RelationTargetId, getObjectEchoUri } from '../Entity';
|
|
18
|
+
import * as JsonSchema from '../JsonSchema';
|
|
16
19
|
import { Ref, StaticRefResolver } from '../Ref';
|
|
17
20
|
import { createObject } from './create-object';
|
|
18
21
|
import { objectFromJSON, objectToJSON } from './json-serializer';
|
|
19
22
|
|
|
20
23
|
describe('Object JSON serializer', () => {
|
|
21
24
|
test('should serialize and deserialize object', async () => {
|
|
22
|
-
const contact =
|
|
25
|
+
const contact = Obj.make(TestSchema.Person, { name: 'Alice' });
|
|
23
26
|
Obj.update(contact, (contact) => {
|
|
24
27
|
getMetaChecked(contact).keys.push({ id: '12345', source: 'example.com' });
|
|
25
28
|
});
|
|
@@ -33,13 +36,13 @@ describe('Object JSON serializer', () => {
|
|
|
33
36
|
const taskJson = objectToJSON(task);
|
|
34
37
|
|
|
35
38
|
expect(contactJson.id).toBe(contact.id);
|
|
36
|
-
expect(contactJson[ATTR_TYPE]).toEqual(
|
|
39
|
+
expect(contactJson[ATTR_TYPE]).toEqual(Type.getURI(TestSchema.Person).toString());
|
|
37
40
|
expect(contactJson.name).toEqual('Alice');
|
|
38
41
|
|
|
39
42
|
expect(taskJson.id).toBe(task.id);
|
|
40
|
-
expect(taskJson[ATTR_TYPE]).toEqual(
|
|
43
|
+
expect(taskJson[ATTR_TYPE]).toEqual(Type.getURI(TestSchema.Task).toString());
|
|
41
44
|
expect(taskJson.title).toEqual('Fix the tests');
|
|
42
|
-
expect(taskJson.assignee).toEqual({ '/':
|
|
45
|
+
expect(taskJson.assignee).toEqual({ '/': EID.make({ entityId: contact.id }) });
|
|
43
46
|
|
|
44
47
|
const refResolver = new StaticRefResolver()
|
|
45
48
|
.addSchema(TestSchema.Person)
|
|
@@ -52,7 +55,7 @@ describe('Object JSON serializer', () => {
|
|
|
52
55
|
|
|
53
56
|
expect(contactFromJson.id).toBe(contact.id);
|
|
54
57
|
expect(contactFromJson.name).toBe('Alice');
|
|
55
|
-
expect((contactFromJson as any)[TypeId]).toEqual(
|
|
58
|
+
expect((contactFromJson as any)[TypeId]).toEqual(Type.getURI(TestSchema.Person));
|
|
56
59
|
expect((contactFromJson as any)[KindId]).toBe(EntityKind.Object);
|
|
57
60
|
expect((contactFromJson as any)[RelationSourceId]).toBeUndefined();
|
|
58
61
|
expect((contactFromJson as any)[RelationTargetId]).toBeUndefined();
|
|
@@ -63,23 +66,25 @@ describe('Object JSON serializer', () => {
|
|
|
63
66
|
source: 'example.com',
|
|
64
67
|
},
|
|
65
68
|
],
|
|
69
|
+
tags: [],
|
|
70
|
+
annotations: {},
|
|
66
71
|
});
|
|
67
|
-
expect(
|
|
68
|
-
expect(getTypename(contactFromJson)).toBe(
|
|
69
|
-
expect(
|
|
70
|
-
expect(getSchema(contactFromJson)).toEqual(TestSchema.Person);
|
|
72
|
+
expect(getTypeURI(contactFromJson)?.toString()).toBe(Type.getURI(TestSchema.Person).toString());
|
|
73
|
+
expect(getTypename(contactFromJson)).toBe(Type.getTypename(TestSchema.Person));
|
|
74
|
+
expect(getObjectEchoUri(contactFromJson)?.toString()).toEqual(getObjectEchoUri(contact)?.toString());
|
|
75
|
+
expect(getSchema(contactFromJson)).toEqual(Type.getSchema(TestSchema.Person));
|
|
71
76
|
|
|
72
77
|
expect(taskFromJson.id).toBe(task.id);
|
|
73
78
|
expect(taskFromJson.title).toBe('Fix the tests');
|
|
74
|
-
expect(taskFromJson.assignee!.
|
|
79
|
+
expect(taskFromJson.assignee!.uri).toEqual(EID.make({ entityId: contact.id }));
|
|
75
80
|
expect(taskFromJson.assignee!.target).toEqual(contact);
|
|
76
81
|
expect(await taskFromJson.assignee!.load()).toEqual(contact);
|
|
77
|
-
expect((taskFromJson as any)[TypeId]).toEqual(
|
|
82
|
+
expect((taskFromJson as any)[TypeId]).toEqual(Type.getURI(TestSchema.Task));
|
|
78
83
|
expect((taskFromJson as any)[KindId]).toBe(EntityKind.Object);
|
|
79
84
|
expect((taskFromJson as any)[RelationSourceId]).toBeUndefined();
|
|
80
85
|
expect((taskFromJson as any)[RelationTargetId]).toBeUndefined();
|
|
81
|
-
expect((taskFromJson as any)[MetaId]).toEqual({ keys: [] });
|
|
82
|
-
expect(getSchema(taskFromJson)).toEqual(TestSchema.Task);
|
|
86
|
+
expect((taskFromJson as any)[MetaId]).toEqual({ keys: [], tags: [], annotations: {} });
|
|
87
|
+
expect(getSchema(taskFromJson)).toEqual(Type.getSchema(TestSchema.Task));
|
|
83
88
|
});
|
|
84
89
|
|
|
85
90
|
test('serialize with unresolved schema', async () => {
|
|
@@ -90,9 +95,20 @@ describe('Object JSON serializer', () => {
|
|
|
90
95
|
expect(contactFromJson.id).toBe(contact.id);
|
|
91
96
|
expect(contactFromJson.name).toBe('Alice');
|
|
92
97
|
expect(getSchema(contactFromJson)).toBeUndefined();
|
|
93
|
-
expect(getTypename(contactFromJson)).toEqual(
|
|
94
|
-
expect(
|
|
95
|
-
expect(
|
|
98
|
+
expect(getTypename(contactFromJson)).toEqual(Type.getTypename(TestSchema.Person));
|
|
99
|
+
expect(getObjectEchoUri(contactFromJson)).toEqual(getObjectEchoUri(contact));
|
|
100
|
+
expect(getTypeURI(contactFromJson)).toEqual(Type.getURI(TestSchema.Person));
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('upgrades legacy string tags to encoded references on deserialize', async () => {
|
|
104
|
+
const expando = Obj.make(TestSchema.Expando, { message: 'hi' });
|
|
105
|
+
const json = objectToJSON(expando) as any;
|
|
106
|
+
// Simulate data serialized before the tags-as-refs migration: bare DXN strings.
|
|
107
|
+
json['@meta'] = { keys: [], tags: ['dxn:echo:@:TAGLEGACY'] };
|
|
108
|
+
|
|
109
|
+
const fromJson = (await objectFromJSON(json)) as any;
|
|
110
|
+
// Decodes to a materialized `Ref` (the shared ref codec), not a raw encoded reference.
|
|
111
|
+
expect(fromJson[MetaId].tags.map((ref: any) => ref.uri)).toEqual(['dxn:echo:@:TAGLEGACY']);
|
|
96
112
|
});
|
|
97
113
|
|
|
98
114
|
test('deserializes expando without leaking internal json keys', async () => {
|
|
@@ -117,4 +133,67 @@ describe('Object JSON serializer', () => {
|
|
|
117
133
|
expect(expandoFromJson.message).toBe('local-only');
|
|
118
134
|
expect((expandoFromJson as any)[ATTR_TYPE]).toBeUndefined();
|
|
119
135
|
});
|
|
136
|
+
|
|
137
|
+
// `objectFromJSON` is the deserialization path for queue messages and devtools
|
|
138
|
+
// round-trips. For persisted `Type.Type` entities it must stamp `KindId = Type`
|
|
139
|
+
// (not Object), mirroring the kind resolution that `createObject` does for the
|
|
140
|
+
// in-memory path. Otherwise `Filter.type(Type.Type)` / `Type.isType` skip them.
|
|
141
|
+
describe('Type.Type round-trip', () => {
|
|
142
|
+
test('preserves KindId=Type for a persisted Type.Type entity', async ({ expect }) => {
|
|
143
|
+
const typeEntity = Type.makeObjectFromJsonSchema({
|
|
144
|
+
typename: 'com.example.type.regression',
|
|
145
|
+
version: '0.1.0',
|
|
146
|
+
jsonSchema: JsonSchema.toJsonSchema(Schema.Struct({ field: Schema.Number })),
|
|
147
|
+
name: 'Regression Type',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const typeJson = objectToJSON(typeEntity as any);
|
|
151
|
+
const refResolver = new StaticRefResolver().addSchema(Type.Type);
|
|
152
|
+
const reconstructed = (await objectFromJSON(typeJson, { refResolver })) as any;
|
|
153
|
+
|
|
154
|
+
expect(reconstructed[KindId]).toBe(EntityKind.Type);
|
|
155
|
+
expect(Type.isType(reconstructed)).toBe(true);
|
|
156
|
+
// `typename` lives in `EntityMeta.key` on persisted Type.Type entities
|
|
157
|
+
// — surfaced via `Type.getTypename`.
|
|
158
|
+
expect(Type.getTypename(reconstructed)).toBe('com.example.type.regression');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Uint8Array', () => {
|
|
163
|
+
const Blob = Schema.Struct({
|
|
164
|
+
name: Schema.String,
|
|
165
|
+
bytes: Schema.Uint8ArrayFromSelf,
|
|
166
|
+
}).pipe(Type.makeObject(DXN.make('com.example.type.blob', '0.1.0')));
|
|
167
|
+
type Blob = Type.InstanceType<typeof Blob>;
|
|
168
|
+
|
|
169
|
+
test('round-trips Uint8Array field through JSON with schema', async ({ expect }) => {
|
|
170
|
+
const bytes = new Uint8Array([0, 1, 2, 3, 250, 251, 252, 253, 254, 255]);
|
|
171
|
+
const blob = Obj.make(Blob, { name: 'blob', bytes });
|
|
172
|
+
|
|
173
|
+
const blobJson = objectToJSON(blob);
|
|
174
|
+
// JSON must round-trip through stringify/parse without loss.
|
|
175
|
+
const roundTripped = JSON.parse(JSON.stringify(blobJson));
|
|
176
|
+
|
|
177
|
+
const refResolver = new StaticRefResolver().addSchema(Blob);
|
|
178
|
+
const blobFromJson = (await objectFromJSON(roundTripped, { refResolver })) as Blob;
|
|
179
|
+
|
|
180
|
+
expect(blobFromJson.name).toBe('blob');
|
|
181
|
+
expect(blobFromJson.bytes).toBeInstanceOf(Uint8Array);
|
|
182
|
+
expect(Array.from(blobFromJson.bytes)).toEqual(Array.from(bytes));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('round-trips Uint8Array field through JSON without schema resolver', async ({ expect }) => {
|
|
186
|
+
const bytes = new Uint8Array([10, 20, 30, 40, 50]);
|
|
187
|
+
const blob = Obj.make(Blob, { name: 'blob', bytes });
|
|
188
|
+
|
|
189
|
+
const blobJson = objectToJSON(blob);
|
|
190
|
+
const roundTripped = JSON.parse(JSON.stringify(blobJson));
|
|
191
|
+
|
|
192
|
+
const blobFromJson = (await objectFromJSON(roundTripped)) as Blob;
|
|
193
|
+
|
|
194
|
+
expect(blobFromJson.name).toBe('blob');
|
|
195
|
+
expect(blobFromJson.bytes).toBeInstanceOf(Uint8Array);
|
|
196
|
+
expect(Array.from(blobFromJson.bytes)).toEqual(Array.from(bytes));
|
|
197
|
+
});
|
|
198
|
+
});
|
|
120
199
|
});
|
|
@@ -5,39 +5,39 @@
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
7
|
import { raise } from '@dxos/debug';
|
|
8
|
-
import { type EncodedReference,
|
|
8
|
+
import { type EncodedReference, EntityStructure, isEncodedReference } from '@dxos/echo-protocol';
|
|
9
9
|
import { assertArgument, invariant } from '@dxos/invariant';
|
|
10
|
-
import {
|
|
11
|
-
import { assumeType, deepMapValues, visitValues } from '@dxos/util';
|
|
10
|
+
import { EID, EntityId, URI } from '@dxos/keys';
|
|
11
|
+
import { assumeType, decodeUint8ArrayFromJson, deepMapValues, isEncodedUint8Array, visitValues } from '@dxos/util';
|
|
12
12
|
|
|
13
13
|
import type * as Database from '../../Database';
|
|
14
14
|
import type * as Obj from '../../Obj';
|
|
15
|
-
import {
|
|
15
|
+
import { getTypeAnnotation, getTypeURI, setTypename } from '../Annotation';
|
|
16
16
|
import { attachTypedJsonSerializer, defineHiddenProperty, typedJsonSerializer } from '../common/proxy';
|
|
17
17
|
import {
|
|
18
|
-
ATTR_META,
|
|
19
18
|
ATTR_PARENT,
|
|
20
19
|
ATTR_TYPE,
|
|
21
20
|
type AnyEntity,
|
|
22
21
|
EntityKind,
|
|
23
22
|
KindId,
|
|
24
|
-
MetaId,
|
|
25
|
-
ObjectMetaSchema,
|
|
26
23
|
ParentId,
|
|
27
24
|
setSchema,
|
|
25
|
+
setType,
|
|
28
26
|
} from '../common/types';
|
|
27
|
+
import { ATTR_META, MetaId, EntityMetaSchema } from '../common/types/meta';
|
|
29
28
|
import {
|
|
30
29
|
ATTR_DELETED,
|
|
31
30
|
ATTR_RELATION_SOURCE,
|
|
32
31
|
ATTR_RELATION_TARGET,
|
|
33
|
-
|
|
32
|
+
ATTR_SELF_URI,
|
|
33
|
+
ATTR_SELF_URI_LEGACY,
|
|
34
34
|
ObjectDatabaseId,
|
|
35
35
|
type ObjectJSON,
|
|
36
36
|
RelationSourceDXNId,
|
|
37
37
|
RelationSourceId,
|
|
38
38
|
RelationTargetDXNId,
|
|
39
39
|
RelationTargetId,
|
|
40
|
-
|
|
40
|
+
SelfURIId,
|
|
41
41
|
assertObjectModel,
|
|
42
42
|
} from '../Entity';
|
|
43
43
|
import { Ref, type RefResolver, refFromEncodedReference, setRefResolver } from '../Ref';
|
|
@@ -62,7 +62,7 @@ type SerializedObject<T extends { id: string }> = {
|
|
|
62
62
|
* Converts object to it's JSON representation.
|
|
63
63
|
*/
|
|
64
64
|
export const objectToJSON = <T extends AnyEntity>(obj: T): SerializedObject<T> => {
|
|
65
|
-
const typename =
|
|
65
|
+
const typename = getTypeURI(obj);
|
|
66
66
|
invariant(typename && typeof typename === 'string');
|
|
67
67
|
return typedJsonSerializer.call(obj);
|
|
68
68
|
};
|
|
@@ -75,27 +75,27 @@ export const objectToJSON = <T extends AnyEntity>(obj: T): SerializedObject<T> =
|
|
|
75
75
|
*
|
|
76
76
|
* @param jsonData - JSON representation of the object.
|
|
77
77
|
* @param options.refResolver - Resolver for references.
|
|
78
|
-
* @param options.
|
|
78
|
+
* @param options.uri - Override object URI.
|
|
79
79
|
* @param options.database - Database to associate with the object.
|
|
80
80
|
*/
|
|
81
81
|
export const objectFromJSON = async (
|
|
82
82
|
jsonData: unknown,
|
|
83
83
|
{
|
|
84
84
|
refResolver,
|
|
85
|
-
|
|
85
|
+
uri,
|
|
86
86
|
database,
|
|
87
87
|
parent,
|
|
88
|
-
}: { refResolver?: RefResolver;
|
|
88
|
+
}: { refResolver?: RefResolver; uri?: URI.URI; database?: Database.Database; parent?: Obj.Unknown } = {},
|
|
89
89
|
): Promise<AnyEntity> => {
|
|
90
90
|
assumeType<ObjectJSON>(jsonData);
|
|
91
91
|
assertArgument(typeof jsonData === 'object' && jsonData !== null, 'jsonData', 'expect object');
|
|
92
92
|
assertArgument(typeof jsonData[ATTR_TYPE] === 'string', 'jsonData[ATTR_TYPE]', 'expected object to have a type');
|
|
93
93
|
assertArgument(typeof jsonData.id === 'string', 'jsonData.id', 'expected object to have an id');
|
|
94
94
|
|
|
95
|
-
const type =
|
|
95
|
+
const type = URI.make(jsonData[ATTR_TYPE]);
|
|
96
96
|
const schema = await refResolver?.resolveSchema(type);
|
|
97
97
|
invariant(schema === undefined || Schema.isSchema(schema));
|
|
98
|
-
const decodedInput = stripInternalJsonKeys(jsonData);
|
|
98
|
+
const decodedInput = restoreUint8Arrays(stripInternalJsonKeys(jsonData));
|
|
99
99
|
|
|
100
100
|
let obj: any;
|
|
101
101
|
if (schema != null) {
|
|
@@ -107,50 +107,67 @@ export const objectFromJSON = async (
|
|
|
107
107
|
obj = decodeGeneric(decodedInput, { refResolver });
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
invariant(
|
|
110
|
+
invariant(EntityId.isValid(obj.id), 'Invalid object id');
|
|
111
111
|
setTypename(obj, type);
|
|
112
112
|
if (schema) {
|
|
113
113
|
setSchema(obj, schema);
|
|
114
114
|
}
|
|
115
|
+
// Resolve and stamp the source type entity, if the resolver provides one.
|
|
116
|
+
// Lets `Obj.getType` / `Entity.getType` return a stable entity for objects
|
|
117
|
+
// loaded via `Obj.fromJSON` (serializer / queue paths).
|
|
118
|
+
if (refResolver?.resolveType) {
|
|
119
|
+
const typeEntity = await refResolver.resolveType(type);
|
|
120
|
+
if (typeEntity != null) {
|
|
121
|
+
setType(obj, typeEntity);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
115
124
|
|
|
116
125
|
const isRelation =
|
|
117
126
|
typeof jsonData[ATTR_RELATION_SOURCE] === 'string' || typeof jsonData[ATTR_RELATION_TARGET] === 'string';
|
|
118
127
|
if (isRelation) {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
128
|
+
const sourceDxn = jsonData[ATTR_RELATION_SOURCE] ?? raise(new TypeError('Missing relation source'));
|
|
129
|
+
const targetDxn = jsonData[ATTR_RELATION_TARGET] ?? raise(new TypeError('Missing relation target'));
|
|
121
130
|
|
|
122
|
-
const source = (await refResolver?.resolve(
|
|
123
|
-
const target = (await refResolver?.resolve(
|
|
131
|
+
const source = (await refResolver?.resolve(sourceDxn)) as AnyEntity | undefined;
|
|
132
|
+
const target = (await refResolver?.resolve(targetDxn)) as AnyEntity | undefined;
|
|
124
133
|
|
|
125
134
|
defineHiddenProperty(obj, KindId, EntityKind.Relation);
|
|
126
|
-
defineHiddenProperty(obj, RelationSourceDXNId,
|
|
127
|
-
defineHiddenProperty(obj, RelationTargetDXNId,
|
|
135
|
+
defineHiddenProperty(obj, RelationSourceDXNId, sourceDxn);
|
|
136
|
+
defineHiddenProperty(obj, RelationTargetDXNId, targetDxn);
|
|
128
137
|
defineHiddenProperty(obj, RelationSourceId, source);
|
|
129
138
|
defineHiddenProperty(obj, RelationTargetId, target);
|
|
130
139
|
} else {
|
|
131
|
-
|
|
140
|
+
// Honour the schema's TypeAnnotation kind — persisted `Type.Type` entities
|
|
141
|
+
// (e.g. dynamic schemas loaded from a snapshot import) must brand as
|
|
142
|
+
// `KindId = Type`, not Object, otherwise `Filter.type(Type.Type)` /
|
|
143
|
+
// `Type.isType` skip them and the schema registry never picks them up.
|
|
144
|
+
// Mirrors the kind resolution in `createObject` (the in-memory path).
|
|
145
|
+
const annotationKind = schema != null ? getTypeAnnotation(schema)?.kind : undefined;
|
|
146
|
+
defineHiddenProperty(obj, KindId, annotationKind === EntityKind.Type ? EntityKind.Type : EntityKind.Object);
|
|
132
147
|
}
|
|
133
148
|
|
|
134
149
|
if (typeof jsonData[ATTR_META] === 'object') {
|
|
135
|
-
const meta = await
|
|
150
|
+
const meta = await EntityMetaSchema.pipe(Schema.decodeUnknownPromise)(normalizeMeta(jsonData[ATTR_META]));
|
|
136
151
|
invariant(Array.isArray(meta.keys));
|
|
137
152
|
defineHiddenProperty(obj, MetaId, meta);
|
|
138
153
|
} else {
|
|
139
154
|
defineHiddenProperty(obj, MetaId, {
|
|
140
155
|
keys: [],
|
|
156
|
+
tags: [],
|
|
157
|
+
annotations: {},
|
|
141
158
|
});
|
|
142
159
|
}
|
|
143
160
|
|
|
144
161
|
if (jsonData[ATTR_PARENT]) {
|
|
145
|
-
const
|
|
146
|
-
const resolvedParent = (await refResolver?.resolve(
|
|
162
|
+
const parentDxn = jsonData[ATTR_PARENT];
|
|
163
|
+
const resolvedParent = (await refResolver?.resolve(parentDxn)) as Obj.Unknown | undefined;
|
|
147
164
|
defineHiddenProperty(obj, ParentId, resolvedParent);
|
|
148
165
|
} else if (parent) {
|
|
149
166
|
defineHiddenProperty(obj, ParentId, parent);
|
|
150
167
|
}
|
|
151
168
|
|
|
152
|
-
if (
|
|
153
|
-
defineHiddenProperty(obj,
|
|
169
|
+
if (uri) {
|
|
170
|
+
defineHiddenProperty(obj, SelfURIId, uri);
|
|
154
171
|
}
|
|
155
172
|
|
|
156
173
|
if (database) {
|
|
@@ -161,12 +178,30 @@ export const objectFromJSON = async (
|
|
|
161
178
|
invariant((obj as any)[ATTR_TYPE] === undefined, 'Invalid object model');
|
|
162
179
|
invariant((obj as any)[ATTR_META] === undefined, 'Invalid object model');
|
|
163
180
|
invariant((obj as any)[ATTR_DELETED] === undefined, 'Invalid object model');
|
|
164
|
-
invariant((obj as any)[
|
|
181
|
+
invariant((obj as any)[ATTR_SELF_URI] === undefined, 'Invalid object model');
|
|
182
|
+
invariant((obj as any)[ATTR_SELF_URI_LEGACY] === undefined, 'Invalid object model');
|
|
165
183
|
invariant((obj as any)[ATTR_RELATION_SOURCE] === undefined, 'Invalid object model');
|
|
166
184
|
invariant((obj as any)[ATTR_RELATION_TARGET] === undefined, 'Invalid object model');
|
|
167
185
|
return obj;
|
|
168
186
|
};
|
|
169
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Backfills required meta fields and upgrades legacy `tags` (bare URI strings) to encoded references
|
|
190
|
+
* so serialized data produced before the tags-as-refs migration still decodes.
|
|
191
|
+
*/
|
|
192
|
+
const normalizeMeta = (meta: any): any => {
|
|
193
|
+
const tags = Array.isArray(meta?.tags)
|
|
194
|
+
? meta.tags.map((tag: unknown) => (typeof tag === 'string' ? { '/': URI.make(tag) } : tag))
|
|
195
|
+
: [];
|
|
196
|
+
// Coalesce required fields so explicit `undefined` in legacy input doesn't override the defaults.
|
|
197
|
+
return {
|
|
198
|
+
...meta,
|
|
199
|
+
keys: Array.isArray(meta?.keys) ? meta.keys : [],
|
|
200
|
+
tags,
|
|
201
|
+
annotations: meta?.annotations ?? {},
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
|
|
170
205
|
const decodeGeneric = (jsonData: unknown, options: { refResolver?: RefResolver }) => {
|
|
171
206
|
const props = stripInternalJsonKeys(jsonData);
|
|
172
207
|
|
|
@@ -174,17 +209,33 @@ const decodeGeneric = (jsonData: unknown, options: { refResolver?: RefResolver }
|
|
|
174
209
|
if (isEncodedReference(value)) {
|
|
175
210
|
return refFromEncodedReference(value, options.refResolver);
|
|
176
211
|
}
|
|
212
|
+
if (isEncodedUint8Array(value)) {
|
|
213
|
+
return decodeUint8ArrayFromJson(value);
|
|
214
|
+
}
|
|
177
215
|
|
|
178
216
|
return visitor(value);
|
|
179
217
|
});
|
|
180
218
|
};
|
|
181
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Recursively replaces encoded `Uint8Array` JSON markers with actual `Uint8Array` instances.
|
|
222
|
+
* Runs before schema decoding so `Schema.Uint8ArrayFromSelf` sees real bytes.
|
|
223
|
+
*/
|
|
224
|
+
const restoreUint8Arrays = (data: unknown): any =>
|
|
225
|
+
deepMapValues(data, (value, recurse) => {
|
|
226
|
+
if (isEncodedUint8Array(value)) {
|
|
227
|
+
return decodeUint8ArrayFromJson(value);
|
|
228
|
+
}
|
|
229
|
+
return recurse(value);
|
|
230
|
+
});
|
|
231
|
+
|
|
182
232
|
const stripInternalJsonKeys = (jsonData: unknown) => {
|
|
183
233
|
const {
|
|
184
234
|
[ATTR_TYPE]: _type,
|
|
185
235
|
[ATTR_META]: _meta,
|
|
186
236
|
[ATTR_DELETED]: _deleted,
|
|
187
|
-
[
|
|
237
|
+
[ATTR_SELF_URI]: _selfUri,
|
|
238
|
+
[ATTR_SELF_URI_LEGACY]: _legacySelfUri,
|
|
188
239
|
[ATTR_RELATION_SOURCE]: _relationSource,
|
|
189
240
|
[ATTR_RELATION_TARGET]: _relationTarget,
|
|
190
241
|
...props
|
|
@@ -206,17 +257,21 @@ export const setRefResolverOnData = (obj: AnyEntity, refResolver: RefResolver) =
|
|
|
206
257
|
};
|
|
207
258
|
|
|
208
259
|
/**
|
|
209
|
-
* Convert
|
|
210
|
-
* Different from {@link objectToJSON} as it takes the internal {@link
|
|
260
|
+
* Convert EntityStructure to JSON data for indexing.
|
|
261
|
+
* Different from {@link objectToJSON} as it takes the internal {@link EntityStructure} representation directly
|
|
211
262
|
*/
|
|
212
|
-
export const objectStructureToJson = (objectId:
|
|
263
|
+
export const objectStructureToJson = (objectId: EntityId, structure: EntityStructure): Obj.JSON => {
|
|
264
|
+
const typeRef = EntityStructure.getTypeReference(structure)?.['/'];
|
|
265
|
+
const parent = EntityStructure.getParent(structure)?.['/'];
|
|
266
|
+
const source = EntityStructure.getRelationSource(structure)?.['/'];
|
|
267
|
+
const target = EntityStructure.getRelationTarget(structure)?.['/'];
|
|
213
268
|
return {
|
|
214
269
|
...structure.data,
|
|
215
270
|
id: objectId,
|
|
216
|
-
[ATTR_TYPE]:
|
|
217
|
-
[ATTR_DELETED]:
|
|
218
|
-
[ATTR_PARENT]:
|
|
219
|
-
[ATTR_RELATION_SOURCE]:
|
|
220
|
-
[ATTR_RELATION_TARGET]:
|
|
271
|
+
[ATTR_TYPE]: typeRef ? URI.make(typeRef) : undefined,
|
|
272
|
+
[ATTR_DELETED]: EntityStructure.isDeleted(structure),
|
|
273
|
+
[ATTR_PARENT]: parent !== undefined ? EID.tryParse(parent) : undefined,
|
|
274
|
+
[ATTR_RELATION_SOURCE]: source !== undefined ? EID.tryParse(source) : undefined,
|
|
275
|
+
[ATTR_RELATION_TARGET]: target !== undefined ? EID.tryParse(target) : undefined,
|
|
221
276
|
};
|
|
222
277
|
};
|