@dxos/echo 0.8.4-staging.ac66bdf99f → 0.9.0
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/LICENSE +102 -5
- package/README.md +7 -7
- package/dist/lib/neutral/Annotation.mjs +37 -6
- package/dist/lib/neutral/Database.mjs +6 -17
- package/dist/lib/neutral/Entity.mjs +31 -20
- package/dist/lib/neutral/Err.mjs +3 -3
- package/dist/lib/neutral/Feed.mjs +23 -19
- package/dist/lib/neutral/Filter.mjs +13 -15
- 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 +29 -20
- package/dist/lib/neutral/Order.mjs +7 -3
- package/dist/lib/neutral/Query.mjs +17 -17
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +10 -9
- package/dist/lib/neutral/Registry.mjs +14 -0
- package/dist/lib/neutral/Relation.mjs +28 -25
- package/dist/lib/neutral/Scope.mjs +12 -0
- package/dist/lib/neutral/Tag.mjs +17 -14
- package/dist/lib/neutral/Type.mjs +54 -26
- package/dist/lib/neutral/{chunk-OMUPQMLR.mjs → chunk-35INCYOE.mjs} +1 -1
- package/dist/lib/neutral/chunk-35INCYOE.mjs.map +7 -0
- package/dist/lib/neutral/chunk-3PBP4V4O.mjs +101 -0
- package/dist/lib/neutral/chunk-3PBP4V4O.mjs.map +7 -0
- package/dist/lib/neutral/chunk-4ZUHOTCG.mjs +184 -0
- package/dist/lib/neutral/chunk-4ZUHOTCG.mjs.map +7 -0
- package/dist/lib/neutral/chunk-5SMDBFVB.mjs +108 -0
- package/dist/lib/neutral/chunk-5SMDBFVB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-OS35K56T.mjs → chunk-5SUJPHAE.mjs} +3 -3
- package/dist/lib/neutral/{chunk-OS35K56T.mjs.map → chunk-5SUJPHAE.mjs.map} +2 -2
- package/dist/lib/neutral/{chunk-GZQTCRJB.mjs → chunk-6M2Z6WBH.mjs} +22 -2
- package/dist/lib/neutral/chunk-6M2Z6WBH.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-V36VO5SS.mjs → chunk-6YDI3J37.mjs} +32 -40
- package/dist/lib/neutral/chunk-6YDI3J37.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-MOR5ERFM.mjs → chunk-7FPIAJIV.mjs} +701 -1256
- package/dist/lib/neutral/chunk-7FPIAJIV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ANHVGJI4.mjs → chunk-7LOUAPYZ.mjs} +9 -5
- package/dist/lib/neutral/chunk-7LOUAPYZ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-JUXPFOEI.mjs → chunk-7PI7C4EF.mjs} +48 -88
- package/dist/lib/neutral/chunk-7PI7C4EF.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-UBEZSGXY.mjs → chunk-BBFJWWAV.mjs} +6 -6
- package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-UI6MWK5W.mjs → chunk-EVK6XBXO.mjs} +16 -2
- package/dist/lib/neutral/chunk-EVK6XBXO.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7RO7CPBZ.mjs → chunk-IGK6FN65.mjs} +2 -2
- package/dist/lib/neutral/{chunk-HBUZJNZO.mjs → chunk-LWXVKPPW.mjs} +94 -99
- package/dist/lib/neutral/chunk-LWXVKPPW.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BVOFLCVF.mjs → chunk-MZ7K3MLL.mjs} +9 -6
- package/dist/lib/neutral/chunk-MZ7K3MLL.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TBKX6JQO.mjs → chunk-O6BH7EPN.mjs} +30 -3
- package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-EAMSSLZC.mjs → chunk-QQIYS74I.mjs} +83 -46
- package/dist/lib/neutral/chunk-QQIYS74I.mjs.map +7 -0
- package/dist/lib/neutral/chunk-R5W6DXR4.mjs +678 -0
- package/dist/lib/neutral/chunk-R5W6DXR4.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-WAK4DMFV.mjs → chunk-RIVWNMSF.mjs} +12 -7
- package/dist/lib/neutral/chunk-RIVWNMSF.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-T6W2LEZU.mjs → chunk-SBVFRTST.mjs} +73 -38
- package/dist/lib/neutral/chunk-SBVFRTST.mjs.map +7 -0
- package/dist/lib/neutral/chunk-T6E37YIP.mjs +251 -0
- package/dist/lib/neutral/chunk-T6E37YIP.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-DQYLD2RB.mjs → chunk-TFEWTY5A.mjs} +155 -129
- package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-B4BASU6W.mjs → chunk-TYGKCRMK.mjs} +85 -76
- package/dist/lib/neutral/chunk-TYGKCRMK.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-4OIBYSXE.mjs → chunk-UUP46KUQ.mjs} +78 -32
- package/dist/lib/neutral/chunk-UUP46KUQ.mjs.map +7 -0
- package/dist/lib/neutral/chunk-WISOH2XH.mjs +36 -0
- package/dist/lib/neutral/chunk-WISOH2XH.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-G3IQMKF7.mjs → chunk-WTQJHC75.mjs} +111 -112
- package/dist/lib/neutral/chunk-WTQJHC75.mjs.map +7 -0
- package/dist/lib/neutral/chunk-WU3GIANS.mjs +31 -0
- package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TU3GW67D.mjs → chunk-ZGNNFYHS.mjs} +40 -40
- package/dist/lib/neutral/chunk-ZGNNFYHS.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +47 -41
- package/dist/lib/neutral/internal/index.mjs +137 -72
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +261 -178
- package/dist/lib/neutral/testing/index.mjs.map +4 -4
- 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 +56 -49
- 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 +101 -28
- package/dist/types/src/Entity.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +27 -27
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Feed.d.ts +66 -19
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Filter.d.ts +38 -12
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Format.d.ts +0 -2
- package/dist/types/src/Format.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +14 -9
- package/dist/types/src/Hypergraph.d.ts.map +1 -1
- package/dist/types/src/Json.d.ts +33 -0
- package/dist/types/src/Json.d.ts.map +1 -0
- package/dist/types/src/Json.test.d.ts +2 -0
- package/dist/types/src/Json.test.d.ts.map +1 -0
- package/dist/types/src/JsonSchema.d.ts +2 -2
- 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 +26 -11
- package/dist/types/src/Migration.d.ts.map +1 -1
- package/dist/types/src/Obj.d.ts +104 -61
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Order.d.ts +10 -0
- package/dist/types/src/Order.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +34 -12
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/QueryResult.d.ts +21 -0
- package/dist/types/src/QueryResult.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +15 -7
- 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 +73 -41
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Scope.d.ts +35 -0
- package/dist/types/src/Scope.d.ts.map +1 -0
- package/dist/types/src/Tag.d.ts +21 -5
- package/dist/types/src/Tag.d.ts.map +1 -1
- package/dist/types/src/Type.d.ts +362 -95
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +9 -12
- package/dist/types/src/View.d.ts.map +1 -1
- package/dist/types/src/exemplars.test.d.ts +2 -0
- package/dist/types/src/exemplars.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +4 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/annotations.d.ts +79 -38
- 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/sorting.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/util.d.ts +14 -5
- package/dist/types/src/internal/Annotation/util.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/api.d.ts +17 -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 +21 -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 +24 -0
- package/dist/types/src/internal/Entity/type-uri.d.ts.map +1 -0
- package/dist/types/src/internal/Entity/version.d.ts.map +1 -1
- 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/number.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/Format/types.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema-normalize.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts +34 -34
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts +3 -2
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/atoms.d.ts +38 -0
- package/dist/types/src/internal/Obj/atoms.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/common.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/create-object.d.ts +12 -12
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/deleted.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/index.d.ts +1 -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/set-value.d.ts +1 -1
- package/dist/types/src/internal/Obj/set-value.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/index.d.ts +2 -0
- package/dist/types/src/internal/Query/index.d.ts.map +1 -0
- package/dist/types/src/internal/{Query.d.ts → Query/pretty.d.ts} +1 -1
- package/dist/types/src/internal/Query/pretty.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/atoms.d.ts +10 -0
- package/dist/types/src/internal/Ref/atoms.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/ref-array.d.ts +2 -2
- package/dist/types/src/internal/Ref/ref.d.ts +50 -19
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/utils.d.ts +8 -0
- package/dist/types/src/internal/Ref/utils.d.ts.map +1 -0
- package/dist/types/src/internal/Type/compose.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 +14 -11
- package/dist/types/src/internal/common/api/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/event-batch.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/ownership.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/reactive-array.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/reactive.test.d.ts +2 -0
- package/dist/types/src/internal/common/proxy/reactive.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/schema-validator.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/base.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/entity.d.ts +62 -5
- 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 +33 -12
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/model-symbols.d.ts +15 -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/version.d.ts +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 +2 -2
- package/dist/types/src/internal/index.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/registry.d.ts +9 -0
- package/dist/types/src/testing/registry.d.ts.map +1 -0
- package/dist/types/src/testing/test-data.d.ts +8 -8
- package/dist/types/src/testing/test-data.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +83 -89
- 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 +26 -24
- package/src/Annotation.test.ts +439 -0
- package/src/Annotation.ts +158 -4
- package/src/Collection.ts +5 -9
- package/src/Database.ts +93 -100
- package/src/Dataset.ts +10 -2
- package/src/Entity.test.ts +116 -6
- package/src/Entity.ts +134 -32
- package/src/Err.ts +4 -4
- package/src/Feed.ts +92 -44
- package/src/Filter.ts +70 -40
- package/src/Format.ts +0 -4
- package/src/Hypergraph.ts +14 -9
- package/src/Json.test.ts +175 -0
- package/src/Json.ts +103 -0
- package/src/Key.ts +1 -1
- package/src/Migration.ts +39 -19
- package/src/Obj.test.ts +122 -20
- package/src/Obj.ts +168 -91
- package/src/Order.ts +22 -0
- package/src/Query.test.ts +183 -154
- package/src/Query.ts +172 -85
- package/src/QueryResult.ts +26 -0
- package/src/Ref.ts +22 -4
- package/src/Registry.ts +155 -0
- package/src/Relation.test.ts +10 -10
- package/src/Relation.ts +116 -69
- package/src/Scope.ts +50 -0
- package/src/Tag.md +88 -0
- package/src/Tag.ts +49 -6
- package/src/Type.test.ts +223 -18
- package/src/Type.ts +609 -131
- package/src/View.ts +14 -23
- package/src/exemplars.test.ts +21 -0
- package/src/index.ts +4 -4
- package/src/internal/Annotation/annotations.test.ts +31 -11
- package/src/internal/Annotation/annotations.ts +143 -111
- package/src/internal/Annotation/dictionary.ts +47 -0
- package/src/internal/Annotation/entity-dictionary.ts +74 -0
- package/src/internal/Annotation/index.ts +4 -2
- package/src/internal/Annotation/util.ts +17 -8
- package/src/internal/Entity/api.ts +54 -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 +38 -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 +92 -0
- package/src/internal/Entity/util.ts +9 -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-type.ts +4 -4
- package/src/internal/JsonSchema/json-schema.test.ts +71 -145
- package/src/internal/JsonSchema/json-schema.ts +49 -35
- package/src/internal/Obj/atoms.ts +244 -0
- 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 +68 -22
- package/src/internal/Obj/index.ts +1 -1
- package/src/internal/Obj/inspect.ts +5 -3
- package/src/internal/Obj/json-serializer.test.ts +101 -22
- package/src/internal/Obj/json-serializer.ts +89 -33
- package/src/internal/Obj/set-value.test.ts +22 -45
- package/src/internal/Obj/set-value.ts +12 -19
- package/src/internal/Obj/snapshot.ts +13 -4
- package/src/internal/Obj/typed-object.test.ts +9 -11
- package/src/internal/Obj/typed-object.ts +1 -1
- package/src/internal/Query/index.ts +5 -0
- package/src/internal/{Query.ts → Query/pretty.ts} +40 -12
- package/src/internal/Ref/atoms.ts +20 -0
- package/src/internal/Ref/ref-array.ts +3 -3
- package/src/internal/Ref/ref.test.ts +18 -27
- package/src/internal/Ref/ref.ts +137 -59
- package/src/internal/Ref/utils.ts +45 -0
- 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 +2 -2
- package/src/internal/common/api/meta.ts +19 -17
- package/src/internal/common/proxy/change-context.ts +1 -1
- package/src/internal/common/proxy/change.test.ts +91 -83
- package/src/internal/common/proxy/errors.ts +2 -2
- package/src/internal/common/proxy/handler.test.ts +1 -1
- package/src/internal/common/proxy/json-serializer.ts +27 -16
- package/src/internal/common/proxy/make-object.ts +44 -20
- package/src/internal/common/proxy/ownership.ts +2 -2
- package/src/internal/common/proxy/reactive-array.ts +1 -1
- package/src/internal/common/proxy/reactive.test.ts +54 -0
- package/src/internal/common/proxy/reactive.ts +11 -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 +78 -16
- package/src/internal/common/proxy/typed-object.test.ts +16 -28
- 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 +62 -20
- package/src/internal/common/types/model-symbols.ts +24 -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 +6 -4
- package/src/testing/api.test.ts +15 -9
- package/src/testing/index.ts +1 -0
- package/src/testing/registry.ts +44 -0
- package/src/testing/test-data.ts +159 -99
- 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-2KHZ36F5.mjs +0 -361
- package/dist/lib/neutral/chunk-2KHZ36F5.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4OIBYSXE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4P3IXBLT.mjs +0 -45
- package/dist/lib/neutral/chunk-4P3IXBLT.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ANHVGJI4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-B4BASU6W.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BNCCGLJN.mjs +0 -7
- package/dist/lib/neutral/chunk-BNCCGLJN.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BVOFLCVF.mjs.map +0 -7
- package/dist/lib/neutral/chunk-DQYLD2RB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EAMSSLZC.mjs.map +0 -7
- package/dist/lib/neutral/chunk-G3IQMKF7.mjs.map +0 -7
- package/dist/lib/neutral/chunk-GZQTCRJB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HBUZJNZO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JUXPFOEI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MOR5ERFM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-OMUPQMLR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-PHU22NLC.mjs +0 -136
- package/dist/lib/neutral/chunk-PHU22NLC.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ROG4RXXL.mjs +0 -97
- package/dist/lib/neutral/chunk-ROG4RXXL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-T6W2LEZU.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TBKX6JQO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TU3GW67D.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UBEZSGXY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UI6MWK5W.mjs.map +0 -7
- package/dist/lib/neutral/chunk-V36VO5SS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WAK4DMFV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YAHXAYOW.mjs +0 -56
- package/dist/lib/neutral/chunk-YAHXAYOW.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YS6Q3XAD.mjs +0 -50
- package/dist/lib/neutral/chunk-YS6Q3XAD.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/Query.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-7RO7CPBZ.mjs.map → chunk-IGK6FN65.mjs.map} +0 -0
|
@@ -6,8 +6,10 @@ 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 } from '../common/types/meta';
|
|
12
|
+
import { MetaId } from '../common/types/model-symbols';
|
|
11
13
|
|
|
12
14
|
/*
|
|
13
15
|
* @internal
|
|
@@ -37,7 +39,7 @@ const typedObjectInspectFunction: CustomInspectFunction<AnyEntity> = function (
|
|
|
37
39
|
return inspect(
|
|
38
40
|
{
|
|
39
41
|
id,
|
|
40
|
-
[ATTR_TYPE]:
|
|
42
|
+
[ATTR_TYPE]: getTypeURI(this),
|
|
41
43
|
...props,
|
|
42
44
|
[ATTR_META]: (this as any)[MetaId], // TODO(dmaretskyi): Couldn't use getMeta since that throw's if the object has no meta.
|
|
43
45
|
},
|
|
@@ -2,25 +2,28 @@
|
|
|
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/model-symbols';
|
|
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 =
|
|
23
|
-
Obj.
|
|
25
|
+
const contact = Obj.make(TestSchema.Person, { name: 'Alice' });
|
|
26
|
+
Obj.update(contact, (contact) => {
|
|
24
27
|
getMetaChecked(contact).keys.push({ id: '12345', source: 'example.com' });
|
|
25
28
|
});
|
|
26
29
|
|
|
@@ -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 bare 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 id strings.
|
|
107
|
+
json['@meta'] = { keys: [], tags: ['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(['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,40 @@
|
|
|
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, EntityMetaSchema } from '../common/types/meta';
|
|
28
|
+
import { MetaId } from '../common/types/model-symbols';
|
|
29
29
|
import {
|
|
30
30
|
ATTR_DELETED,
|
|
31
31
|
ATTR_RELATION_SOURCE,
|
|
32
32
|
ATTR_RELATION_TARGET,
|
|
33
|
-
|
|
33
|
+
ATTR_SELF_URI,
|
|
34
|
+
ATTR_SELF_URI_LEGACY,
|
|
34
35
|
ObjectDatabaseId,
|
|
35
36
|
type ObjectJSON,
|
|
36
37
|
RelationSourceDXNId,
|
|
37
38
|
RelationSourceId,
|
|
38
39
|
RelationTargetDXNId,
|
|
39
40
|
RelationTargetId,
|
|
40
|
-
|
|
41
|
+
SelfURIId,
|
|
41
42
|
assertObjectModel,
|
|
42
43
|
} from '../Entity';
|
|
43
44
|
import { Ref, type RefResolver, refFromEncodedReference, setRefResolver } from '../Ref';
|
|
@@ -62,7 +63,7 @@ type SerializedObject<T extends { id: string }> = {
|
|
|
62
63
|
* Converts object to it's JSON representation.
|
|
63
64
|
*/
|
|
64
65
|
export const objectToJSON = <T extends AnyEntity>(obj: T): SerializedObject<T> => {
|
|
65
|
-
const typename =
|
|
66
|
+
const typename = getTypeURI(obj);
|
|
66
67
|
invariant(typename && typeof typename === 'string');
|
|
67
68
|
return typedJsonSerializer.call(obj);
|
|
68
69
|
};
|
|
@@ -75,27 +76,27 @@ export const objectToJSON = <T extends AnyEntity>(obj: T): SerializedObject<T> =
|
|
|
75
76
|
*
|
|
76
77
|
* @param jsonData - JSON representation of the object.
|
|
77
78
|
* @param options.refResolver - Resolver for references.
|
|
78
|
-
* @param options.
|
|
79
|
+
* @param options.uri - Override object URI.
|
|
79
80
|
* @param options.database - Database to associate with the object.
|
|
80
81
|
*/
|
|
81
82
|
export const objectFromJSON = async (
|
|
82
83
|
jsonData: unknown,
|
|
83
84
|
{
|
|
84
85
|
refResolver,
|
|
85
|
-
|
|
86
|
+
uri,
|
|
86
87
|
database,
|
|
87
88
|
parent,
|
|
88
|
-
}: { refResolver?: RefResolver;
|
|
89
|
+
}: { refResolver?: RefResolver; uri?: URI.URI; database?: Database.Database; parent?: Obj.Unknown } = {},
|
|
89
90
|
): Promise<AnyEntity> => {
|
|
90
91
|
assumeType<ObjectJSON>(jsonData);
|
|
91
92
|
assertArgument(typeof jsonData === 'object' && jsonData !== null, 'jsonData', 'expect object');
|
|
92
93
|
assertArgument(typeof jsonData[ATTR_TYPE] === 'string', 'jsonData[ATTR_TYPE]', 'expected object to have a type');
|
|
93
94
|
assertArgument(typeof jsonData.id === 'string', 'jsonData.id', 'expected object to have an id');
|
|
94
95
|
|
|
95
|
-
const type =
|
|
96
|
+
const type = URI.make(jsonData[ATTR_TYPE]);
|
|
96
97
|
const schema = await refResolver?.resolveSchema(type);
|
|
97
98
|
invariant(schema === undefined || Schema.isSchema(schema));
|
|
98
|
-
const decodedInput = stripInternalJsonKeys(jsonData);
|
|
99
|
+
const decodedInput = restoreUint8Arrays(stripInternalJsonKeys(jsonData));
|
|
99
100
|
|
|
100
101
|
let obj: any;
|
|
101
102
|
if (schema != null) {
|
|
@@ -107,17 +108,26 @@ export const objectFromJSON = async (
|
|
|
107
108
|
obj = decodeGeneric(decodedInput, { refResolver });
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
invariant(
|
|
111
|
+
invariant(EntityId.isValid(obj.id), 'Invalid object id');
|
|
111
112
|
setTypename(obj, type);
|
|
112
113
|
if (schema) {
|
|
113
114
|
setSchema(obj, schema);
|
|
114
115
|
}
|
|
116
|
+
// Resolve and stamp the source type entity, if the resolver provides one.
|
|
117
|
+
// Lets `Obj.getType` / `Entity.getType` return a stable entity for objects
|
|
118
|
+
// loaded via `Obj.fromJSON` (serializer / queue paths).
|
|
119
|
+
if (refResolver?.resolveType) {
|
|
120
|
+
const typeEntity = await refResolver.resolveType(type);
|
|
121
|
+
if (typeEntity != null) {
|
|
122
|
+
setType(obj, typeEntity);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
115
125
|
|
|
116
126
|
const isRelation =
|
|
117
127
|
typeof jsonData[ATTR_RELATION_SOURCE] === 'string' || typeof jsonData[ATTR_RELATION_TARGET] === 'string';
|
|
118
128
|
if (isRelation) {
|
|
119
|
-
const sourceDxn
|
|
120
|
-
const targetDxn
|
|
129
|
+
const sourceDxn = jsonData[ATTR_RELATION_SOURCE] ?? raise(new TypeError('Missing relation source'));
|
|
130
|
+
const targetDxn = jsonData[ATTR_RELATION_TARGET] ?? raise(new TypeError('Missing relation target'));
|
|
121
131
|
|
|
122
132
|
const source = (await refResolver?.resolve(sourceDxn)) as AnyEntity | undefined;
|
|
123
133
|
const target = (await refResolver?.resolve(targetDxn)) as AnyEntity | undefined;
|
|
@@ -128,29 +138,37 @@ export const objectFromJSON = async (
|
|
|
128
138
|
defineHiddenProperty(obj, RelationSourceId, source);
|
|
129
139
|
defineHiddenProperty(obj, RelationTargetId, target);
|
|
130
140
|
} else {
|
|
131
|
-
|
|
141
|
+
// Honour the schema's TypeAnnotation kind — persisted `Type.Type` entities
|
|
142
|
+
// (e.g. dynamic schemas loaded from a snapshot import) must brand as
|
|
143
|
+
// `KindId = Type`, not Object, otherwise `Filter.type(Type.Type)` /
|
|
144
|
+
// `Type.isType` skip them and the schema registry never picks them up.
|
|
145
|
+
// Mirrors the kind resolution in `createObject` (the in-memory path).
|
|
146
|
+
const annotationKind = schema != null ? getTypeAnnotation(schema)?.kind : undefined;
|
|
147
|
+
defineHiddenProperty(obj, KindId, annotationKind === EntityKind.Type ? EntityKind.Type : EntityKind.Object);
|
|
132
148
|
}
|
|
133
149
|
|
|
134
150
|
if (typeof jsonData[ATTR_META] === 'object') {
|
|
135
|
-
const meta = await
|
|
151
|
+
const meta = await EntityMetaSchema.pipe(Schema.decodeUnknownPromise)(normalizeMeta(jsonData[ATTR_META]));
|
|
136
152
|
invariant(Array.isArray(meta.keys));
|
|
137
153
|
defineHiddenProperty(obj, MetaId, meta);
|
|
138
154
|
} else {
|
|
139
155
|
defineHiddenProperty(obj, MetaId, {
|
|
140
156
|
keys: [],
|
|
157
|
+
tags: [],
|
|
158
|
+
annotations: {},
|
|
141
159
|
});
|
|
142
160
|
}
|
|
143
161
|
|
|
144
162
|
if (jsonData[ATTR_PARENT]) {
|
|
145
|
-
const parentDxn =
|
|
163
|
+
const parentDxn = jsonData[ATTR_PARENT];
|
|
146
164
|
const resolvedParent = (await refResolver?.resolve(parentDxn)) as Obj.Unknown | undefined;
|
|
147
165
|
defineHiddenProperty(obj, ParentId, resolvedParent);
|
|
148
166
|
} else if (parent) {
|
|
149
167
|
defineHiddenProperty(obj, ParentId, parent);
|
|
150
168
|
}
|
|
151
169
|
|
|
152
|
-
if (
|
|
153
|
-
defineHiddenProperty(obj,
|
|
170
|
+
if (uri) {
|
|
171
|
+
defineHiddenProperty(obj, SelfURIId, uri);
|
|
154
172
|
}
|
|
155
173
|
|
|
156
174
|
if (database) {
|
|
@@ -161,12 +179,30 @@ export const objectFromJSON = async (
|
|
|
161
179
|
invariant((obj as any)[ATTR_TYPE] === undefined, 'Invalid object model');
|
|
162
180
|
invariant((obj as any)[ATTR_META] === undefined, 'Invalid object model');
|
|
163
181
|
invariant((obj as any)[ATTR_DELETED] === undefined, 'Invalid object model');
|
|
164
|
-
invariant((obj as any)[
|
|
182
|
+
invariant((obj as any)[ATTR_SELF_URI] === undefined, 'Invalid object model');
|
|
183
|
+
invariant((obj as any)[ATTR_SELF_URI_LEGACY] === undefined, 'Invalid object model');
|
|
165
184
|
invariant((obj as any)[ATTR_RELATION_SOURCE] === undefined, 'Invalid object model');
|
|
166
185
|
invariant((obj as any)[ATTR_RELATION_TARGET] === undefined, 'Invalid object model');
|
|
167
186
|
return obj;
|
|
168
187
|
};
|
|
169
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Backfills required meta fields and upgrades legacy `tags` (bare URI strings) to encoded references
|
|
191
|
+
* so serialized data produced before the tags-as-refs migration still decodes.
|
|
192
|
+
*/
|
|
193
|
+
const normalizeMeta = (meta: any): any => {
|
|
194
|
+
const tags = Array.isArray(meta?.tags)
|
|
195
|
+
? meta.tags.map((tag: unknown) => (typeof tag === 'string' ? { '/': URI.make(tag) } : tag))
|
|
196
|
+
: [];
|
|
197
|
+
// Coalesce required fields so explicit `undefined` in legacy input doesn't override the defaults.
|
|
198
|
+
return {
|
|
199
|
+
...meta,
|
|
200
|
+
keys: Array.isArray(meta?.keys) ? meta.keys : [],
|
|
201
|
+
tags,
|
|
202
|
+
annotations: meta?.annotations ?? {},
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
|
|
170
206
|
const decodeGeneric = (jsonData: unknown, options: { refResolver?: RefResolver }) => {
|
|
171
207
|
const props = stripInternalJsonKeys(jsonData);
|
|
172
208
|
|
|
@@ -174,17 +210,33 @@ const decodeGeneric = (jsonData: unknown, options: { refResolver?: RefResolver }
|
|
|
174
210
|
if (isEncodedReference(value)) {
|
|
175
211
|
return refFromEncodedReference(value, options.refResolver);
|
|
176
212
|
}
|
|
213
|
+
if (isEncodedUint8Array(value)) {
|
|
214
|
+
return decodeUint8ArrayFromJson(value);
|
|
215
|
+
}
|
|
177
216
|
|
|
178
217
|
return visitor(value);
|
|
179
218
|
});
|
|
180
219
|
};
|
|
181
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Recursively replaces encoded `Uint8Array` JSON markers with actual `Uint8Array` instances.
|
|
223
|
+
* Runs before schema decoding so `Schema.Uint8ArrayFromSelf` sees real bytes.
|
|
224
|
+
*/
|
|
225
|
+
const restoreUint8Arrays = (data: unknown): any =>
|
|
226
|
+
deepMapValues(data, (value, recurse) => {
|
|
227
|
+
if (isEncodedUint8Array(value)) {
|
|
228
|
+
return decodeUint8ArrayFromJson(value);
|
|
229
|
+
}
|
|
230
|
+
return recurse(value);
|
|
231
|
+
});
|
|
232
|
+
|
|
182
233
|
const stripInternalJsonKeys = (jsonData: unknown) => {
|
|
183
234
|
const {
|
|
184
235
|
[ATTR_TYPE]: _type,
|
|
185
236
|
[ATTR_META]: _meta,
|
|
186
237
|
[ATTR_DELETED]: _deleted,
|
|
187
|
-
[
|
|
238
|
+
[ATTR_SELF_URI]: _selfUri,
|
|
239
|
+
[ATTR_SELF_URI_LEGACY]: _legacySelfUri,
|
|
188
240
|
[ATTR_RELATION_SOURCE]: _relationSource,
|
|
189
241
|
[ATTR_RELATION_TARGET]: _relationTarget,
|
|
190
242
|
...props
|
|
@@ -206,17 +258,21 @@ export const setRefResolverOnData = (obj: AnyEntity, refResolver: RefResolver) =
|
|
|
206
258
|
};
|
|
207
259
|
|
|
208
260
|
/**
|
|
209
|
-
* Convert
|
|
210
|
-
* Different from {@link objectToJSON} as it takes the internal {@link
|
|
261
|
+
* Convert EntityStructure to JSON data for indexing.
|
|
262
|
+
* Different from {@link objectToJSON} as it takes the internal {@link EntityStructure} representation directly
|
|
211
263
|
*/
|
|
212
|
-
export const objectStructureToJson = (objectId:
|
|
264
|
+
export const objectStructureToJson = (objectId: EntityId, structure: EntityStructure): Obj.JSON => {
|
|
265
|
+
const typeRef = EntityStructure.getTypeReference(structure)?.['/'];
|
|
266
|
+
const parent = EntityStructure.getParent(structure)?.['/'];
|
|
267
|
+
const source = EntityStructure.getRelationSource(structure)?.['/'];
|
|
268
|
+
const target = EntityStructure.getRelationTarget(structure)?.['/'];
|
|
213
269
|
return {
|
|
214
270
|
...structure.data,
|
|
215
271
|
id: objectId,
|
|
216
|
-
[ATTR_TYPE]:
|
|
217
|
-
[ATTR_DELETED]:
|
|
218
|
-
[ATTR_PARENT]:
|
|
219
|
-
[ATTR_RELATION_SOURCE]:
|
|
220
|
-
[ATTR_RELATION_TARGET]:
|
|
272
|
+
[ATTR_TYPE]: typeRef ? URI.make(typeRef) : undefined,
|
|
273
|
+
[ATTR_DELETED]: EntityStructure.isDeleted(structure),
|
|
274
|
+
[ATTR_PARENT]: parent !== undefined ? EID.tryParse(parent) : undefined,
|
|
275
|
+
[ATTR_RELATION_SOURCE]: source !== undefined ? EID.tryParse(source) : undefined,
|
|
276
|
+
[ATTR_RELATION_TARGET]: target !== undefined ? EID.tryParse(target) : undefined,
|
|
221
277
|
};
|
|
222
278
|
};
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import * as Schema from 'effect/Schema';
|
|
6
6
|
import { describe, test } from 'vitest';
|
|
7
7
|
|
|
8
|
+
import { DXN } from '@dxos/keys';
|
|
9
|
+
|
|
8
10
|
import * as Obj from '../../Obj';
|
|
9
11
|
import { TestSchema } from '../../testing';
|
|
10
12
|
import * as Type from '../../Type';
|
|
@@ -17,7 +19,7 @@ describe('Obj.setValue', () => {
|
|
|
17
19
|
email: 'john@example.com',
|
|
18
20
|
});
|
|
19
21
|
|
|
20
|
-
Obj.
|
|
22
|
+
Obj.update(person, (person) => Obj.setValue(person, ['address', 'city'], 'NYC'));
|
|
21
23
|
|
|
22
24
|
expect(person.address).toBeDefined();
|
|
23
25
|
expect(person.address?.city).toBe('NYC');
|
|
@@ -30,7 +32,7 @@ describe('Obj.setValue', () => {
|
|
|
30
32
|
email: 'john@example.com',
|
|
31
33
|
});
|
|
32
34
|
|
|
33
|
-
Obj.
|
|
35
|
+
Obj.update(person, (person) => Obj.setValue(person, ['fields', 0, 'label'], 'Phone'));
|
|
34
36
|
|
|
35
37
|
expect(Array.isArray(person.fields)).toBe(true);
|
|
36
38
|
expect(person.fields?.[0].label).toBe('Phone');
|
|
@@ -45,7 +47,7 @@ describe('Obj.setValue', () => {
|
|
|
45
47
|
email: 'john@example.com',
|
|
46
48
|
});
|
|
47
49
|
|
|
48
|
-
Obj.
|
|
50
|
+
Obj.update(person, (person) => Obj.setValue(person, ['address', 'coordinates', 'lat'], 40.7128));
|
|
49
51
|
|
|
50
52
|
expect(person.address).toBeDefined();
|
|
51
53
|
expect(person.address?.coordinates).toBeDefined();
|
|
@@ -60,16 +62,11 @@ describe('Obj.setValue', () => {
|
|
|
60
62
|
const Container = Schema.Struct({
|
|
61
63
|
name: Schema.String,
|
|
62
64
|
items: Schema.optional(Schema.Array(Item)),
|
|
63
|
-
}).pipe(
|
|
64
|
-
Type.object({
|
|
65
|
-
typename: 'test.com/Container',
|
|
66
|
-
version: '0.1.0',
|
|
67
|
-
}),
|
|
68
|
-
);
|
|
65
|
+
}).pipe(Type.makeObject(DXN.make('com.test.type.container', '0.1.0')));
|
|
69
66
|
|
|
70
67
|
const container = Obj.make(Container, { name: 'box' });
|
|
71
68
|
|
|
72
|
-
Obj.
|
|
69
|
+
Obj.update(container, (container) => {
|
|
73
70
|
Obj.setValue(container, ['items', 0, 'value'], 10);
|
|
74
71
|
Obj.setValue(container, ['items', 1, 'value'], 20);
|
|
75
72
|
Obj.setValue(container, ['items', 2, 'value'], 30);
|
|
@@ -88,7 +85,7 @@ describe('Obj.setValue', () => {
|
|
|
88
85
|
email: 'john@example.com',
|
|
89
86
|
});
|
|
90
87
|
|
|
91
|
-
Obj.
|
|
88
|
+
Obj.update(person, (person) => Obj.setValue(person, ['age'], 25));
|
|
92
89
|
|
|
93
90
|
expect(person.age).toBe(25);
|
|
94
91
|
});
|
|
@@ -100,7 +97,7 @@ describe('Obj.setValue', () => {
|
|
|
100
97
|
email: 'john@example.com',
|
|
101
98
|
});
|
|
102
99
|
|
|
103
|
-
Obj.
|
|
100
|
+
Obj.update(person, (person) => Obj.setValue(person, ['address', 'city'], 'NYC'));
|
|
104
101
|
|
|
105
102
|
expect(person.address).toBeDefined();
|
|
106
103
|
expect(person.address?.city).toBe('NYC');
|
|
@@ -114,7 +111,7 @@ describe('Obj.setValue', () => {
|
|
|
114
111
|
});
|
|
115
112
|
|
|
116
113
|
let result: any;
|
|
117
|
-
Obj.
|
|
114
|
+
Obj.update(person, (person) => {
|
|
118
115
|
result = Obj.setValue(person, ['age'], 30);
|
|
119
116
|
});
|
|
120
117
|
|
|
@@ -129,7 +126,7 @@ describe('Obj.setValue', () => {
|
|
|
129
126
|
age: 25,
|
|
130
127
|
});
|
|
131
128
|
|
|
132
|
-
Obj.
|
|
129
|
+
Obj.update(person, (person) => Obj.setValue(person, ['age'], 30));
|
|
133
130
|
|
|
134
131
|
expect(person.age).toBe(30);
|
|
135
132
|
});
|
|
@@ -142,7 +139,7 @@ describe('Obj.setValue', () => {
|
|
|
142
139
|
address: { city: 'Boston', state: 'MA', coordinates: {} },
|
|
143
140
|
});
|
|
144
141
|
|
|
145
|
-
Obj.
|
|
142
|
+
Obj.update(person, (person) => Obj.setValue(person, ['address', 'city'], 'NYC'));
|
|
146
143
|
|
|
147
144
|
expect(person.address?.city).toBe('NYC');
|
|
148
145
|
expect(person.address?.state).toBe('MA');
|
|
@@ -151,16 +148,11 @@ describe('Obj.setValue', () => {
|
|
|
151
148
|
test('handles two-dimensional arrays', ({ expect }) => {
|
|
152
149
|
const Matrix = Schema.Struct({
|
|
153
150
|
values: Schema.optional(Schema.Array(Schema.Array(Schema.Number))),
|
|
154
|
-
}).pipe(
|
|
155
|
-
Type.object({
|
|
156
|
-
typename: 'test.com/Matrix',
|
|
157
|
-
version: '0.1.0',
|
|
158
|
-
}),
|
|
159
|
-
);
|
|
151
|
+
}).pipe(Type.makeObject(DXN.make('com.test.type.matrix', '0.1.0')));
|
|
160
152
|
|
|
161
153
|
const matrix = Obj.make(Matrix, {});
|
|
162
154
|
|
|
163
|
-
Obj.
|
|
155
|
+
Obj.update(matrix, (matrix) => {
|
|
164
156
|
Obj.setValue(matrix, ['values', 0, 0], 1);
|
|
165
157
|
Obj.setValue(matrix, ['values', 0, 1], 2);
|
|
166
158
|
Obj.setValue(matrix, ['values', 1, 0], 3);
|
|
@@ -180,7 +172,7 @@ describe('Obj.setValue', () => {
|
|
|
180
172
|
email: 'john@example.com',
|
|
181
173
|
});
|
|
182
174
|
|
|
183
|
-
Obj.
|
|
175
|
+
Obj.update(person, (person) => {
|
|
184
176
|
expect(() => Obj.setValue(person, [], 'value')).toThrow('Path must not be empty');
|
|
185
177
|
});
|
|
186
178
|
});
|
|
@@ -192,7 +184,7 @@ describe('Obj.setValue', () => {
|
|
|
192
184
|
email: 'john@example.com',
|
|
193
185
|
});
|
|
194
186
|
|
|
195
|
-
Obj.
|
|
187
|
+
Obj.update(person, (person) => Obj.setValue(person, ['age'], 30));
|
|
196
188
|
|
|
197
189
|
expect(person.age).toBe(30);
|
|
198
190
|
});
|
|
@@ -205,17 +197,12 @@ describe('Obj.setValue', () => {
|
|
|
205
197
|
const Container = Schema.Struct({
|
|
206
198
|
name: Schema.String,
|
|
207
199
|
items: Schema.optional(Schema.Array(Item)),
|
|
208
|
-
}).pipe(
|
|
209
|
-
Type.object({
|
|
210
|
-
typename: 'test.com/Container',
|
|
211
|
-
version: '0.1.0',
|
|
212
|
-
}),
|
|
213
|
-
);
|
|
200
|
+
}).pipe(Type.makeObject(DXN.make('com.test.type.container', '0.1.0')));
|
|
214
201
|
|
|
215
202
|
const container = Obj.make(Container, { name: 'box' });
|
|
216
203
|
|
|
217
204
|
// Using string '0' for array index.
|
|
218
|
-
Obj.
|
|
205
|
+
Obj.update(container, (container) => Obj.setValue(container, ['items', '0', 'value'], 42));
|
|
219
206
|
|
|
220
207
|
expect(container.items?.[0].value).toBe(42);
|
|
221
208
|
});
|
|
@@ -232,18 +219,13 @@ describe('Obj.setValue', () => {
|
|
|
232
219
|
const TodoList = Schema.Struct({
|
|
233
220
|
name: Schema.String,
|
|
234
221
|
tasks: Schema.optional(Schema.Array(Task)),
|
|
235
|
-
}).pipe(
|
|
236
|
-
Type.object({
|
|
237
|
-
typename: 'test.com/TodoList',
|
|
238
|
-
version: '0.1.0',
|
|
239
|
-
}),
|
|
240
|
-
);
|
|
222
|
+
}).pipe(Type.makeObject(DXN.make('com.test.type.todoList', '0.1.0')));
|
|
241
223
|
|
|
242
224
|
const todoList = Obj.make(TodoList, { name: 'My Tasks' });
|
|
243
225
|
|
|
244
226
|
// This should work: setting a nested property on an array element.
|
|
245
227
|
// The required 'id' field should be initialized with a default value.
|
|
246
|
-
Obj.
|
|
228
|
+
Obj.update(todoList, (todoList) => Obj.setValue(todoList, ['tasks', 0, 'title'], 'Buy groceries'));
|
|
247
229
|
|
|
248
230
|
expect(todoList.tasks?.[0].id).toBe(''); // Default value for required String
|
|
249
231
|
expect(todoList.tasks?.[0].title).toBe('Buy groceries');
|
|
@@ -261,16 +243,11 @@ describe('Obj.setValue', () => {
|
|
|
261
243
|
const Container = Schema.Struct({
|
|
262
244
|
name: Schema.String,
|
|
263
245
|
items: Schema.optional(Schema.Array(Item)),
|
|
264
|
-
}).pipe(
|
|
265
|
-
Type.object({
|
|
266
|
-
typename: 'test.com/Container',
|
|
267
|
-
version: '0.1.0',
|
|
268
|
-
}),
|
|
269
|
-
);
|
|
246
|
+
}).pipe(Type.makeObject(DXN.make('com.test.type.container', '0.1.0')));
|
|
270
247
|
|
|
271
248
|
const container = Obj.make(Container, { name: 'box' });
|
|
272
249
|
|
|
273
|
-
Obj.
|
|
250
|
+
Obj.update(container, (container) => Obj.setValue(container, ['items', 0, 'label'], 'First Item'));
|
|
274
251
|
|
|
275
252
|
// All required primitive fields should have default values.
|
|
276
253
|
expect(container.items?.[0].id).toBe('');
|