@dxos/echo 0.8.4-main.3eb6e50203 → 0.8.4-main.3fbcb4aa9b
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 +7 -3
- package/dist/lib/neutral/Database.mjs +8 -4
- package/dist/lib/neutral/Entity.mjs +24 -14
- package/dist/lib/neutral/Err.mjs +1 -1
- package/dist/lib/neutral/Extension.mjs +18 -0
- package/dist/lib/neutral/Extension.mjs.map +7 -0
- package/dist/lib/neutral/Feed.mjs +50 -0
- package/dist/lib/neutral/Feed.mjs.map +7 -0
- package/dist/lib/neutral/Filter.mjs +21 -10
- package/dist/lib/neutral/Format.mjs +3 -3
- package/dist/lib/neutral/JsonSchema.mjs +9 -9
- package/dist/lib/neutral/Key.mjs +1 -1
- package/dist/lib/neutral/Migration.mjs +17 -0
- package/dist/lib/neutral/Migration.mjs.map +7 -0
- package/dist/lib/neutral/Obj.mjs +26 -17
- package/dist/lib/neutral/Order.mjs +1 -1
- package/dist/lib/neutral/Query.mjs +21 -9
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +9 -7
- package/dist/lib/neutral/Relation.mjs +23 -13
- package/dist/lib/neutral/SchemaRegistry.mjs +1 -1
- package/dist/lib/neutral/Tag.mjs +14 -10
- package/dist/lib/neutral/Type.mjs +13 -23
- package/dist/lib/neutral/{chunk-N2QNHMT5.mjs → chunk-44HT3MEC.mjs} +2 -2
- package/dist/lib/neutral/{chunk-N2QNHMT5.mjs.map → chunk-44HT3MEC.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-XAJMXQ4H.mjs → chunk-5SL5LDLD.mjs} +6 -2
- package/dist/lib/neutral/chunk-5SL5LDLD.mjs.map +7 -0
- package/dist/lib/neutral/chunk-6VIJV543.mjs +34 -0
- package/dist/lib/neutral/chunk-6VIJV543.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ANHVGJI4.mjs → chunk-7RVZT53K.mjs} +1 -1
- package/dist/lib/neutral/{chunk-4L6DOFXP.mjs → chunk-BICZKPQG.mjs} +1 -1
- package/dist/lib/neutral/{chunk-4L6DOFXP.mjs.map → chunk-BICZKPQG.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-B4FLOYG7.mjs → chunk-FHYIM4RD.mjs} +18 -20
- package/dist/lib/neutral/chunk-FHYIM4RD.mjs.map +7 -0
- package/dist/lib/neutral/chunk-FZHVQEHN.mjs +81 -0
- package/dist/lib/neutral/chunk-FZHVQEHN.mjs.map +7 -0
- package/dist/lib/neutral/chunk-GWFFC34K.mjs +50 -0
- package/dist/lib/neutral/chunk-GWFFC34K.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-EXAYCLIM.mjs → chunk-HPNQTEEQ.mjs} +5 -5
- package/dist/lib/neutral/chunk-HPNQTEEQ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-YPIP3WGI.mjs → chunk-LVGOVFDV.mjs} +40 -12
- package/dist/lib/neutral/chunk-LVGOVFDV.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MPAI2MHO.mjs +346 -0
- package/dist/lib/neutral/chunk-MPAI2MHO.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-KB7RIVLK.mjs → chunk-N4B7FHQT.mjs} +4 -4
- package/dist/lib/neutral/{chunk-KB7RIVLK.mjs.map → chunk-N4B7FHQT.mjs.map} +2 -2
- package/dist/lib/neutral/chunk-O5LRY6CO.mjs +734 -0
- package/dist/lib/neutral/chunk-O5LRY6CO.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-VYEWMV5U.mjs → chunk-QGMIH2SN.mjs} +8 -4
- package/dist/lib/neutral/chunk-QGMIH2SN.mjs.map +7 -0
- package/dist/lib/neutral/chunk-QXIANHKU.mjs +206 -0
- package/dist/lib/neutral/chunk-QXIANHKU.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-UMECVTXM.mjs → chunk-RF7ZBZ4A.mjs} +72 -5
- package/dist/lib/neutral/chunk-RF7ZBZ4A.mjs.map +7 -0
- package/dist/lib/neutral/chunk-S7IMFVTB.mjs +132 -0
- package/dist/lib/neutral/chunk-S7IMFVTB.mjs.map +7 -0
- package/dist/lib/neutral/chunk-SJKBWMJY.mjs +2436 -0
- package/dist/lib/neutral/chunk-SJKBWMJY.mjs.map +7 -0
- package/dist/lib/neutral/chunk-SUZMWP3Y.mjs +36 -0
- package/dist/lib/neutral/chunk-SUZMWP3Y.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-HQXQWXLH.mjs → chunk-SW5CUSBY.mjs} +183 -32
- package/dist/lib/neutral/chunk-SW5CUSBY.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-RIMHNJ3E.mjs → chunk-TNBK56IN.mjs} +98 -44
- package/dist/lib/neutral/chunk-TNBK56IN.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7WE7SBA2.mjs → chunk-TRPZU2HV.mjs} +13 -13
- package/dist/lib/neutral/chunk-TRPZU2HV.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-ROKO4RKJ.mjs → chunk-TTCSATUD.mjs} +2 -2
- package/dist/lib/neutral/chunk-TTCSATUD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-OMUPQMLR.mjs → chunk-V72DY6LU.mjs} +1 -1
- package/dist/lib/neutral/chunk-VGKLHHRT.mjs +318 -0
- package/dist/lib/neutral/chunk-VGKLHHRT.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TMLVKIMX.mjs → chunk-VYAGNFSJ.mjs} +8 -3
- package/dist/lib/neutral/chunk-VYAGNFSJ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7YWDDFPH.mjs → chunk-WRVRDZDA.mjs} +77 -58
- package/dist/lib/neutral/chunk-WRVRDZDA.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-MXQJZCPY.mjs → chunk-ZISMEVKD.mjs} +1 -1
- package/dist/lib/neutral/chunk-ZISMEVKD.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +51 -28
- package/dist/lib/neutral/internal/index.mjs +52 -38
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +199 -136
- package/dist/lib/neutral/testing/index.mjs.map +3 -3
- package/dist/types/src/Annotation.d.ts +3 -3
- package/dist/types/src/Annotation.d.ts.map +1 -1
- package/dist/types/src/Collection.d.ts +16 -0
- package/dist/types/src/Collection.d.ts.map +1 -0
- package/dist/types/src/Database.d.ts +20 -35
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Dataset.d.ts +19 -0
- package/dist/types/src/Dataset.d.ts.map +1 -0
- package/dist/types/src/Entity.d.ts +54 -22
- package/dist/types/src/Entity.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +18 -18
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Extension.d.ts +80 -0
- package/dist/types/src/Extension.d.ts.map +1 -0
- package/dist/types/src/Extension.test.d.ts +2 -0
- package/dist/types/src/Extension.test.d.ts.map +1 -0
- package/dist/types/src/Feed.d.ts +182 -0
- package/dist/types/src/Feed.d.ts.map +1 -0
- package/dist/types/src/Filter.d.ts +34 -5
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Filter.test.d.ts +2 -0
- package/dist/types/src/Filter.test.d.ts.map +1 -0
- package/dist/types/src/Format.d.ts +3 -3
- package/dist/types/src/Format.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +8 -3
- 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 +11 -4
- package/dist/types/src/JsonSchema.d.ts.map +1 -1
- package/dist/types/src/Migration.d.ts +57 -0
- package/dist/types/src/Migration.d.ts.map +1 -0
- package/dist/types/src/Obj.d.ts +109 -60
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Order.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +105 -17
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +58 -10
- package/dist/types/src/Ref.d.ts.map +1 -1
- package/dist/types/src/Relation.d.ts +86 -40
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/SchemaRegistry.d.ts +4 -4
- package/dist/types/src/SchemaRegistry.d.ts.map +1 -1
- package/dist/types/src/Tag.d.ts +2 -1
- package/dist/types/src/Tag.d.ts.map +1 -1
- package/dist/types/src/Type.d.ts +51 -180
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +68 -0
- package/dist/types/src/View.d.ts.map +1 -0
- 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 +7 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/{annotations → Annotation}/annotations.d.ts +65 -2
- package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/annotations.test.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/index.d.ts +4 -0
- package/dist/types/src/internal/Annotation/index.d.ts.map +1 -0
- package/dist/types/src/internal/{api → Annotation}/sorting.d.ts +1 -1
- package/dist/types/src/internal/Annotation/sorting.d.ts.map +1 -0
- package/dist/types/src/internal/{annotations → Annotation}/util.d.ts +2 -2
- package/dist/types/src/internal/Annotation/util.d.ts.map +1 -0
- package/dist/types/src/internal/{api/entity.d.ts → Entity/api.d.ts} +2 -2
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/entity.d.ts +3 -3
- package/dist/types/src/internal/Entity/entity.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/index.d.ts +2 -0
- package/dist/types/src/internal/Entity/index.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/model.d.ts +2 -26
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/object.d.ts +2 -2
- package/dist/types/src/internal/Entity/object.d.ts.map +1 -0
- package/dist/types/src/internal/{entities → Entity}/relation.d.ts +3 -30
- package/dist/types/src/internal/Entity/relation.d.ts.map +1 -0
- package/dist/types/src/internal/Entity/util.d.ts.map +1 -0
- package/dist/types/src/internal/{api → Entity}/version.d.ts +1 -1
- package/dist/types/src/internal/Entity/version.d.ts.map +1 -0
- package/dist/types/src/internal/Format/date.d.ts.map +1 -0
- package/dist/types/src/internal/Format/date.test.d.ts.map +1 -0
- package/dist/types/src/internal/Format/format.d.ts.map +1 -0
- package/dist/types/src/internal/Format/format.test.d.ts.map +1 -0
- package/dist/types/src/internal/Format/index.d.ts.map +1 -0
- package/dist/types/src/internal/Format/number.d.ts.map +1 -0
- package/dist/types/src/internal/Format/object.d.ts.map +1 -0
- package/dist/types/src/internal/Format/select.d.ts.map +1 -0
- package/dist/types/src/internal/Format/string.d.ts.map +1 -0
- package/dist/types/src/internal/{formats → Format}/types.d.ts +1 -1
- package/dist/types/src/internal/Format/types.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/annotations.d.ts +1 -1
- package/dist/types/src/internal/JsonSchema/annotations.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/effect-schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/index.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/json-schema-normalize.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema-type.d.ts +37 -37
- package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -0
- package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema.d.ts +1 -1
- package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -0
- package/dist/types/src/internal/JsonSchema/json-schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/common.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/create-object.d.ts +2 -2
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/create-object.test.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/deleted.d.ts +1 -1
- package/dist/types/src/internal/Obj/deleted.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/ids.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/index.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/inspect.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/json-serializer.d.ts +13 -5
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/json-serializer.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/schema-validator.d.ts +2 -0
- package/dist/types/src/internal/Obj/schema-validator.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/schema-validator.test.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/set-value.d.ts +2 -2
- package/dist/types/src/internal/Obj/set-value.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/set-value.test.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/snapshot.d.ts.map +1 -0
- package/dist/types/src/internal/{object → Obj}/typed-object.d.ts +4 -4
- package/dist/types/src/internal/Obj/typed-object.d.ts.map +1 -0
- package/dist/types/src/internal/Obj/typed-object.test.d.ts.map +1 -0
- package/dist/types/src/internal/Query.d.ts +10 -0
- package/dist/types/src/internal/Query.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/index.d.ts.map +1 -0
- package/dist/types/src/internal/{ref → Ref}/ref-array.d.ts +1 -1
- package/dist/types/src/internal/Ref/ref-array.d.ts.map +1 -0
- package/dist/types/src/internal/{ref → Ref}/ref.d.ts +15 -2
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/ref.test.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/compose.d.ts +1 -1
- package/dist/types/src/internal/Type/compose.d.ts.map +1 -0
- package/dist/types/src/internal/Type/compose.test.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/echo-schema.d.ts +7 -7
- package/dist/types/src/internal/Type/echo-schema.d.ts.map +1 -0
- package/dist/types/src/internal/Type/index.d.ts.map +1 -0
- package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -0
- package/dist/types/src/internal/{schema → Type}/persistent-schema.d.ts +2 -2
- package/dist/types/src/internal/Type/persistent-schema.d.ts.map +1 -0
- package/dist/types/src/internal/{api → common/api}/index.d.ts +0 -4
- package/dist/types/src/internal/common/api/index.d.ts.map +1 -0
- package/dist/types/src/internal/{api → common/api}/meta.d.ts +3 -3
- package/dist/types/src/internal/common/api/meta.d.ts.map +1 -0
- package/dist/types/src/internal/common/index.d.ts +4 -0
- package/dist/types/src/internal/common/index.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/change-context.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/change.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/errors.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/event-batch.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/handler.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/index.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/ownership.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/proxy-types.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/reactive-array.d.ts +1 -1
- package/dist/types/src/internal/common/proxy/reactive-array.d.ts.map +1 -0
- package/dist/types/src/internal/{proxy → common/proxy}/reactive.d.ts +2 -2
- package/dist/types/src/internal/{proxy → 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 -0
- package/dist/types/src/internal/common/proxy/schema.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/symbols.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-handler.test.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/typed-object.test.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/base.d.ts +1 -0
- package/dist/types/src/internal/common/types/base.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/entity.d.ts +5 -5
- package/dist/types/src/internal/common/types/entity.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/index.d.ts +1 -0
- package/dist/types/src/internal/common/types/index.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/meta.d.ts +2 -1
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -0
- package/dist/types/src/internal/common/types/model-symbols.d.ts +54 -0
- package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -0
- package/dist/types/src/internal/common/types/typename.d.ts.map +1 -0
- package/dist/types/src/internal/{types → common/types}/version.d.ts +2 -2
- package/dist/types/src/internal/common/types/version.d.ts.map +1 -0
- package/dist/types/src/internal/index.d.ts +9 -10
- package/dist/types/src/internal/index.d.ts.map +1 -1
- 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 +47 -46
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/dist/types/src/testing/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -14
- package/src/Annotation.ts +7 -3
- package/src/Collection.ts +37 -0
- package/src/Database.ts +63 -64
- package/src/Dataset.ts +26 -0
- package/src/Entity.ts +87 -61
- package/src/Err.ts +2 -0
- package/src/Extension.test.ts +235 -0
- package/src/Extension.ts +122 -0
- package/src/Feed.ts +304 -0
- package/src/Filter.test.ts +90 -0
- package/src/Filter.ts +85 -7
- package/src/Format.ts +3 -3
- package/src/Hypergraph.ts +9 -4
- package/src/Json.test.ts +175 -0
- package/src/Json.ts +102 -0
- package/src/JsonSchema.ts +14 -4
- package/src/Migration.ts +94 -0
- package/src/Obj.test.ts +112 -15
- package/src/Obj.ts +302 -166
- package/src/Order.ts +3 -1
- package/src/Query.test.ts +372 -15
- package/src/Query.ts +269 -26
- package/src/Ref.ts +64 -11
- package/src/Relation.test.ts +8 -2
- package/src/Relation.ts +183 -147
- package/src/SchemaRegistry.ts +5 -4
- package/src/Tag.ts +6 -5
- package/src/Type.test.ts +10 -10
- package/src/Type.ts +70 -303
- package/src/View.ts +107 -0
- package/src/exemplars.test.ts +21 -0
- package/src/index.ts +8 -0
- package/src/internal/{annotations → Annotation}/annotations.test.ts +56 -7
- package/src/internal/{annotations → Annotation}/annotations.ts +122 -19
- package/src/internal/{annotations → Annotation}/index.ts +1 -0
- package/src/internal/{api → Annotation}/sorting.ts +2 -4
- package/src/internal/{annotations → Annotation}/util.ts +1 -1
- package/src/internal/{api/entity.ts → Entity/api.ts} +3 -2
- package/src/internal/{entities → Entity}/entity.ts +6 -4
- package/src/internal/{entities → Entity}/index.ts +2 -0
- package/src/internal/{entities → Entity}/model.ts +13 -42
- package/src/internal/{entities → Entity}/object.ts +2 -3
- package/src/internal/{entities → Entity}/relation.ts +19 -36
- package/src/internal/{api → Entity}/version.ts +2 -2
- package/src/internal/{formats → Format}/date.test.ts +1 -2
- package/src/internal/{formats → Format}/format.test.ts +1 -2
- package/src/internal/{formats → Format}/types.ts +2 -2
- package/src/internal/{json-schema → JsonSchema}/annotations.ts +3 -3
- package/src/internal/{json-schema → JsonSchema}/json-schema-type.ts +4 -4
- package/src/internal/{json-schema → JsonSchema}/json-schema.test.ts +48 -49
- package/src/internal/{json-schema → JsonSchema}/json-schema.ts +6 -5
- package/src/internal/{object → Obj}/clone.ts +3 -3
- package/src/internal/{object → Obj}/common.ts +2 -2
- package/src/internal/{object → Obj}/create-object.test.ts +5 -7
- package/src/internal/{object → Obj}/create-object.ts +5 -6
- package/src/internal/{object → Obj}/deleted.ts +2 -2
- package/src/internal/{object → Obj}/inspect.ts +2 -2
- package/src/internal/{object → Obj}/json-serializer.test.ts +31 -9
- package/src/internal/{object → Obj}/json-serializer.ts +52 -27
- package/src/internal/{object → Obj}/schema-validator.ts +1 -1
- package/src/internal/{object → Obj}/set-value.test.ts +24 -24
- package/src/internal/{object → Obj}/set-value.ts +3 -3
- package/src/internal/{object → Obj}/snapshot.ts +35 -23
- package/src/internal/{object → Obj}/typed-object.test.ts +3 -3
- package/src/internal/{object → Obj}/typed-object.ts +4 -4
- package/src/internal/Query.ts +137 -0
- package/src/internal/{ref → Ref}/ref-array.ts +1 -2
- package/src/internal/{ref → Ref}/ref.test.ts +4 -5
- package/src/internal/{ref → Ref}/ref.ts +20 -3
- package/src/internal/{schema → Type}/compose.test.ts +5 -6
- package/src/internal/{schema → Type}/compose.ts +1 -1
- package/src/internal/{schema → Type}/echo-schema.ts +9 -10
- package/src/internal/{schema → Type}/manipulation.ts +1 -1
- package/src/internal/{schema → Type}/persistent-schema.ts +9 -4
- package/src/internal/{README.md → common/README.md} +2 -2
- package/src/internal/{api → common/api}/index.ts +0 -4
- package/src/internal/{api → common/api}/meta.ts +3 -3
- package/src/internal/common/index.ts +7 -0
- package/src/internal/{proxy → common/proxy}/change-context.ts +1 -1
- package/src/internal/{proxy → common/proxy}/change.test.ts +97 -97
- package/src/internal/{proxy → common/proxy}/errors.ts +2 -2
- package/src/internal/{proxy → common/proxy}/handler.test.ts +2 -4
- package/src/internal/{proxy → common/proxy}/json-serializer.ts +6 -3
- package/src/internal/{proxy → common/proxy}/make-object.ts +1 -2
- package/src/internal/{proxy → common/proxy}/ownership.ts +0 -1
- package/src/internal/{proxy → common/proxy}/reactive-array.ts +1 -1
- package/src/internal/common/proxy/reactive.test.ts +54 -0
- package/src/internal/{proxy → common/proxy}/reactive.ts +12 -4
- package/src/internal/{proxy → common/proxy}/schema.test.ts +10 -10
- package/src/internal/{proxy → common/proxy}/typed-handler.test.ts +6 -7
- package/src/internal/{proxy → common/proxy}/typed-handler.ts +10 -13
- package/src/internal/{proxy → common/proxy}/typed-object.test.ts +5 -6
- package/src/internal/{types → common/types}/base.ts +1 -1
- package/src/internal/{types → common/types}/entity.ts +2 -2
- package/src/internal/{types → common/types}/index.ts +1 -0
- package/src/internal/{types → common/types}/meta.ts +3 -1
- package/src/internal/common/types/model-symbols.ts +69 -0
- package/src/internal/{types → common/types}/version.ts +2 -3
- package/src/internal/index.ts +9 -31
- package/src/testing/api.test.ts +4 -5
- package/src/testing/test-data.ts +157 -98
- package/src/testing/test-schema.ts +20 -18
- package/dist/lib/neutral/chunk-7WE7SBA2.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7YWDDFPH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-B4FLOYG7.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EXAYCLIM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-F6BTBXL7.mjs +0 -171
- package/dist/lib/neutral/chunk-F6BTBXL7.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HQXQWXLH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MXQJZCPY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-RCBBZLVM.mjs +0 -142
- package/dist/lib/neutral/chunk-RCBBZLVM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-RIMHNJ3E.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ROKO4RKJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TMLVKIMX.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UMECVTXM.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VJ2H5MOJ.mjs +0 -3905
- package/dist/lib/neutral/chunk-VJ2H5MOJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VYEWMV5U.mjs.map +0 -7
- package/dist/lib/neutral/chunk-X2MPMYYN.mjs +0 -13
- package/dist/lib/neutral/chunk-X2MPMYYN.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XAJMXQ4H.mjs.map +0 -7
- package/dist/lib/neutral/chunk-YPIP3WGI.mjs.map +0 -7
- package/dist/types/src/internal/annotations/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/annotations.test.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/index.d.ts +0 -3
- package/dist/types/src/internal/annotations/index.d.ts.map +0 -1
- package/dist/types/src/internal/annotations/util.d.ts.map +0 -1
- package/dist/types/src/internal/api/annotations.d.ts +0 -23
- package/dist/types/src/internal/api/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/api/entity.d.ts.map +0 -1
- package/dist/types/src/internal/api/index.d.ts.map +0 -1
- package/dist/types/src/internal/api/meta.d.ts.map +0 -1
- package/dist/types/src/internal/api/sorting.d.ts.map +0 -1
- package/dist/types/src/internal/api/version.d.ts.map +0 -1
- package/dist/types/src/internal/entities/entity.d.ts.map +0 -1
- package/dist/types/src/internal/entities/index.d.ts.map +0 -1
- package/dist/types/src/internal/entities/model.d.ts.map +0 -1
- package/dist/types/src/internal/entities/object.d.ts.map +0 -1
- package/dist/types/src/internal/entities/relation.d.ts.map +0 -1
- package/dist/types/src/internal/entities/util.d.ts.map +0 -1
- package/dist/types/src/internal/formats/date.d.ts.map +0 -1
- package/dist/types/src/internal/formats/date.test.d.ts.map +0 -1
- package/dist/types/src/internal/formats/format.d.ts.map +0 -1
- package/dist/types/src/internal/formats/format.test.d.ts.map +0 -1
- package/dist/types/src/internal/formats/index.d.ts.map +0 -1
- package/dist/types/src/internal/formats/number.d.ts.map +0 -1
- package/dist/types/src/internal/formats/object.d.ts.map +0 -1
- package/dist/types/src/internal/formats/select.d.ts.map +0 -1
- package/dist/types/src/internal/formats/string.d.ts.map +0 -1
- package/dist/types/src/internal/formats/types.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/annotations.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/effect-schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/index.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema.d.ts.map +0 -1
- package/dist/types/src/internal/json-schema/json-schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/clone.d.ts.map +0 -1
- package/dist/types/src/internal/object/common.d.ts.map +0 -1
- package/dist/types/src/internal/object/create-object.d.ts.map +0 -1
- package/dist/types/src/internal/object/create-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/deleted.d.ts.map +0 -1
- package/dist/types/src/internal/object/ids.d.ts.map +0 -1
- package/dist/types/src/internal/object/index.d.ts.map +0 -1
- package/dist/types/src/internal/object/inspect.d.ts.map +0 -1
- package/dist/types/src/internal/object/json-serializer.d.ts.map +0 -1
- package/dist/types/src/internal/object/json-serializer.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/schema-validator.d.ts +0 -2
- package/dist/types/src/internal/object/schema-validator.d.ts.map +0 -1
- package/dist/types/src/internal/object/schema-validator.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/set-value.d.ts.map +0 -1
- package/dist/types/src/internal/object/set-value.test.d.ts.map +0 -1
- package/dist/types/src/internal/object/snapshot.d.ts.map +0 -1
- package/dist/types/src/internal/object/typed-object.d.ts.map +0 -1
- package/dist/types/src/internal/object/typed-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/change-context.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/change.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/define-hidden-property.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/errors.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/event-batch.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/handler.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/index.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/json-serializer.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/make-object.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/ownership.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/proxy-types.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/proxy-utils.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/reactive-array.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/schema-validator.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/schema.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/symbols.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-handler.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-handler.test.d.ts.map +0 -1
- package/dist/types/src/internal/proxy/typed-object.test.d.ts.map +0 -1
- package/dist/types/src/internal/ref/index.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref-array.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref.d.ts.map +0 -1
- package/dist/types/src/internal/ref/ref.test.d.ts.map +0 -1
- package/dist/types/src/internal/schema/compose.d.ts.map +0 -1
- package/dist/types/src/internal/schema/compose.test.d.ts.map +0 -1
- package/dist/types/src/internal/schema/echo-schema.d.ts.map +0 -1
- package/dist/types/src/internal/schema/index.d.ts.map +0 -1
- package/dist/types/src/internal/schema/manipulation.d.ts.map +0 -1
- package/dist/types/src/internal/schema/persistent-schema.d.ts.map +0 -1
- package/dist/types/src/internal/types/base.d.ts.map +0 -1
- package/dist/types/src/internal/types/entity.d.ts.map +0 -1
- package/dist/types/src/internal/types/index.d.ts.map +0 -1
- package/dist/types/src/internal/types/meta.d.ts.map +0 -1
- package/dist/types/src/internal/types/typename.d.ts.map +0 -1
- package/dist/types/src/internal/types/version.d.ts.map +0 -1
- package/src/internal/api/annotations.ts +0 -60
- /package/dist/lib/neutral/{chunk-ANHVGJI4.mjs.map → chunk-7RVZT53K.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-OMUPQMLR.mjs.map → chunk-V72DY6LU.mjs.map} +0 -0
- /package/dist/types/src/internal/{annotations → Annotation}/annotations.test.d.ts +0 -0
- /package/dist/types/src/internal/{entities → Entity}/util.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/date.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/date.test.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/format.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/format.test.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/index.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/number.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/object.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/select.d.ts +0 -0
- /package/dist/types/src/internal/{formats → Format}/string.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/effect-schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/index.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema-normalize.d.ts +0 -0
- /package/dist/types/src/internal/{json-schema → JsonSchema}/json-schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/clone.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/common.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/create-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/ids.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/index.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/inspect.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/json-serializer.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/schema-validator.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/set-value.test.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/snapshot.d.ts +0 -0
- /package/dist/types/src/internal/{object → Obj}/typed-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{ref → Ref}/index.d.ts +0 -0
- /package/dist/types/src/internal/{ref → Ref}/ref.test.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/compose.test.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/index.d.ts +0 -0
- /package/dist/types/src/internal/{schema → Type}/manipulation.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/change.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/define-hidden-property.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/event-batch.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/handler.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/index.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/json-serializer.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/make-object.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/ownership.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/proxy-types.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/proxy-utils.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/schema-validator.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/schema.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/symbols.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-handler.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-handler.test.d.ts +0 -0
- /package/dist/types/src/internal/{proxy → common/proxy}/typed-object.test.d.ts +0 -0
- /package/dist/types/src/internal/{types → common/types}/typename.d.ts +0 -0
- /package/src/internal/{entities → Entity}/util.ts +0 -0
- /package/src/internal/{formats → Format}/date.ts +0 -0
- /package/src/internal/{formats → Format}/format.ts +0 -0
- /package/src/internal/{formats → Format}/index.ts +0 -0
- /package/src/internal/{formats → Format}/number.ts +0 -0
- /package/src/internal/{formats → Format}/object.ts +0 -0
- /package/src/internal/{formats → Format}/select.ts +0 -0
- /package/src/internal/{formats → Format}/string.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/effect-schema.test.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/index.ts +0 -0
- /package/src/internal/{json-schema → JsonSchema}/json-schema-normalize.ts +0 -0
- /package/src/internal/{object → Obj}/ids.ts +0 -0
- /package/src/internal/{object → Obj}/index.ts +0 -0
- /package/src/internal/{object → Obj}/schema-validator.test.ts +0 -0
- /package/src/internal/{ref → Ref}/index.ts +0 -0
- /package/src/internal/{schema → Type}/index.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/define-hidden-property.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/event-batch.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/index.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/proxy-types.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/proxy-utils.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/schema-validator.ts +0 -0
- /package/src/internal/{proxy → common/proxy}/symbols.ts +0 -0
- /package/src/internal/{types → common/types}/typename.ts +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import * as Filter from './Filter';
|
|
8
|
+
|
|
9
|
+
describe('Filter timestamp builders', () => {
|
|
10
|
+
test('updated({ after }) produces correct AST', () => {
|
|
11
|
+
const ts = 1700000000000;
|
|
12
|
+
const f = Filter.updated({ after: ts });
|
|
13
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: ts });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('updated({ before }) produces correct AST', () => {
|
|
17
|
+
const ts = 1700000000000;
|
|
18
|
+
const f = Filter.updated({ before: ts });
|
|
19
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: ts });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('created({ after }) produces correct AST', () => {
|
|
23
|
+
const ts = 1700000000000;
|
|
24
|
+
const f = Filter.created({ after: ts });
|
|
25
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'gte', value: ts });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('created({ before }) produces correct AST', () => {
|
|
29
|
+
const ts = 1700000000000;
|
|
30
|
+
const f = Filter.created({ before: ts });
|
|
31
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'lte', value: ts });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('updated() accepts Date objects', () => {
|
|
35
|
+
const date = new Date('2026-03-20T21:00:00Z');
|
|
36
|
+
const f = Filter.updated({ after: date });
|
|
37
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: date.getTime() });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('created() accepts Date objects', () => {
|
|
41
|
+
const date = new Date('2026-03-20T09:00:00Z');
|
|
42
|
+
const f = Filter.created({ before: date });
|
|
43
|
+
expect(f.ast).toEqual({ type: 'timestamp', field: 'createdAt', operator: 'lte', value: date.getTime() });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('updated({ after, before }) produces AND of two timestamp nodes', () => {
|
|
47
|
+
const from = 1700000000000;
|
|
48
|
+
const to = 1700086400000;
|
|
49
|
+
const f = Filter.updated({ after: from, before: to });
|
|
50
|
+
expect(f.ast).toEqual({
|
|
51
|
+
type: 'and',
|
|
52
|
+
filters: [
|
|
53
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: from },
|
|
54
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: to },
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('updated({ after, before }) accepts Date objects', () => {
|
|
60
|
+
const from = new Date('2026-03-19T00:00:00Z');
|
|
61
|
+
const to = new Date('2026-03-20T00:00:00Z');
|
|
62
|
+
const f = Filter.updated({ after: from, before: to });
|
|
63
|
+
expect(f.ast).toEqual({
|
|
64
|
+
type: 'and',
|
|
65
|
+
filters: [
|
|
66
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'gte', value: from.getTime() },
|
|
67
|
+
{ type: 'timestamp', field: 'updatedAt', operator: 'lte', value: to.getTime() },
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('timestamp filters compose with and()', () => {
|
|
73
|
+
const typeFilter = Filter.everything();
|
|
74
|
+
const timeFilter = Filter.updated({ after: 1700000000000 });
|
|
75
|
+
const combined = Filter.and(typeFilter, timeFilter);
|
|
76
|
+
expect(combined.ast.type).toBe('and');
|
|
77
|
+
expect((combined.ast as any).filters).toHaveLength(2);
|
|
78
|
+
expect((combined.ast as any).filters[1]).toEqual({
|
|
79
|
+
type: 'timestamp',
|
|
80
|
+
field: 'updatedAt',
|
|
81
|
+
operator: 'gte',
|
|
82
|
+
value: 1700000000000,
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('timestamp filters pass the is() check', () => {
|
|
87
|
+
const f = Filter.updated({ after: Date.now() });
|
|
88
|
+
expect(Filter.is(f)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/Filter.ts
CHANGED
|
@@ -2,20 +2,24 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// @import-as-namespace
|
|
6
|
+
|
|
5
7
|
import * as Match from 'effect/Match';
|
|
6
8
|
import * as Schema from 'effect/Schema';
|
|
9
|
+
import * as SchemaAST from 'effect/SchemaAST';
|
|
7
10
|
import type * as Types from 'effect/Types';
|
|
8
11
|
|
|
9
12
|
import { type ForeignKey, type QueryAST } from '@dxos/echo-protocol';
|
|
10
13
|
import { assertArgument } from '@dxos/invariant';
|
|
11
14
|
import { DXN, ObjectId } from '@dxos/keys';
|
|
12
15
|
|
|
13
|
-
import
|
|
16
|
+
import * as internal from './internal';
|
|
17
|
+
import type * as Obj from './Obj';
|
|
14
18
|
import * as Ref from './Ref';
|
|
15
19
|
|
|
16
20
|
export interface Filter<T> {
|
|
17
21
|
// TODO(dmaretskyi): See new effect-schema approach to variance.
|
|
18
|
-
'~Filter': { value: Types.
|
|
22
|
+
'~Filter': { value: Types.Covariant<T> };
|
|
19
23
|
|
|
20
24
|
ast: QueryAST.Filter;
|
|
21
25
|
}
|
|
@@ -30,7 +34,7 @@ export type Any = Filter<any>;
|
|
|
30
34
|
export type Type<F extends Any> = F extends Filter<infer T> ? T : never;
|
|
31
35
|
|
|
32
36
|
class FilterClass implements Any {
|
|
33
|
-
private static variance: Any['~Filter'] = {} as Any['~Filter'];
|
|
37
|
+
private static 'variance': Any['~Filter'] = {} as Any['~Filter'];
|
|
34
38
|
|
|
35
39
|
constructor(public readonly ast: QueryAST.Filter) {}
|
|
36
40
|
|
|
@@ -101,7 +105,19 @@ export const type = <S extends Schema.Schema.All>(
|
|
|
101
105
|
schema: S | string,
|
|
102
106
|
props?: Props<Schema.Schema.Type<S>>,
|
|
103
107
|
): Filter<Schema.Schema.Type<S>> => {
|
|
104
|
-
|
|
108
|
+
if (Schema.isSchema(schema) && SchemaAST.isUnion(schema.ast)) {
|
|
109
|
+
const typenames = schema.ast.types.map((type) => internal.getTypeDXNFromSpecifier(Schema.make(type)));
|
|
110
|
+
return new FilterClass({
|
|
111
|
+
type: 'or',
|
|
112
|
+
filters: typenames.map((typename) => ({
|
|
113
|
+
type: 'object',
|
|
114
|
+
typename: typename.toString(),
|
|
115
|
+
props: {},
|
|
116
|
+
})),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const dxn = internal.getTypeDXNFromSpecifier(schema);
|
|
105
121
|
return new FilterClass({
|
|
106
122
|
type: 'object',
|
|
107
123
|
typename: dxn.toString(),
|
|
@@ -180,7 +196,7 @@ export const foreignKeys = <S extends Schema.Schema.All>(
|
|
|
180
196
|
schema: S | string,
|
|
181
197
|
keys: ForeignKey[],
|
|
182
198
|
): Filter<Schema.Schema.Type<S>> => {
|
|
183
|
-
const dxn = getTypeDXNFromSpecifier(schema);
|
|
199
|
+
const dxn = internal.getTypeDXNFromSpecifier(schema);
|
|
184
200
|
return new FilterClass({
|
|
185
201
|
type: 'object',
|
|
186
202
|
typename: dxn.toString(),
|
|
@@ -263,7 +279,7 @@ export const lte = <T>(value: T): Filter<T | undefined> => {
|
|
|
263
279
|
* Predicate for property to be in the provided array.
|
|
264
280
|
* @param values - Values to check against.
|
|
265
281
|
*/
|
|
266
|
-
const in$ = <T>(...values: T[]): Filter<T
|
|
282
|
+
const in$ = <T>(...values: T[]): Filter<T> => {
|
|
267
283
|
return new FilterClass({
|
|
268
284
|
type: 'in',
|
|
269
285
|
values,
|
|
@@ -287,7 +303,7 @@ export const contains = <T>(value: T): Filter<readonly T[] | undefined> => {
|
|
|
287
303
|
* @param from - Start of the range (inclusive).
|
|
288
304
|
* @param to - End of the range (exclusive).
|
|
289
305
|
*/
|
|
290
|
-
export const between = <T>(from: T, to: T): Filter<
|
|
306
|
+
export const between = <T>(from: T, to: T): Filter<T> => {
|
|
291
307
|
return new FilterClass({
|
|
292
308
|
type: 'range',
|
|
293
309
|
from,
|
|
@@ -295,6 +311,63 @@ export const between = <T>(from: T, to: T): Filter<unknown> => {
|
|
|
295
311
|
});
|
|
296
312
|
};
|
|
297
313
|
|
|
314
|
+
type TimeRange = { after?: Date | number; before?: Date | number };
|
|
315
|
+
|
|
316
|
+
const _toUnixMs = (date: Date | number): number => (typeof date === 'number' ? date : date.getTime());
|
|
317
|
+
|
|
318
|
+
const _timeRangeFilter = (field: 'updatedAt' | 'createdAt', range: TimeRange): Any => {
|
|
319
|
+
const filters: Any[] = [];
|
|
320
|
+
if (range.after != null) {
|
|
321
|
+
filters.push(new FilterClass({ type: 'timestamp', field, operator: 'gte', value: _toUnixMs(range.after) }));
|
|
322
|
+
}
|
|
323
|
+
if (range.before != null) {
|
|
324
|
+
filters.push(new FilterClass({ type: 'timestamp', field, operator: 'lte', value: _toUnixMs(range.before) }));
|
|
325
|
+
}
|
|
326
|
+
if (filters.length === 0) {
|
|
327
|
+
return everything();
|
|
328
|
+
}
|
|
329
|
+
return filters.length === 1 ? filters[0] : and(...filters);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Filter objects by updatedAt timestamp.
|
|
334
|
+
*/
|
|
335
|
+
export const updated = (range: TimeRange): Any => _timeRangeFilter('updatedAt', range);
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Filter objects by createdAt timestamp.
|
|
339
|
+
*/
|
|
340
|
+
export const created = (range: TimeRange): Any => _timeRangeFilter('createdAt', range);
|
|
341
|
+
|
|
342
|
+
export type ChildOfOptions = {
|
|
343
|
+
/** Whether to match transitively (grandchildren, etc.). Defaults to true. */
|
|
344
|
+
transitive?: boolean;
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Filter objects that are children of the specified parent(s).
|
|
349
|
+
* Accepts ECHO objects, Refs, or arrays of either.
|
|
350
|
+
* Refs are resolved to DXNs without loading; objects use {@link Obj.getDXN}.
|
|
351
|
+
* With transitive=true (default), also matches grandchildren and beyond.
|
|
352
|
+
*/
|
|
353
|
+
export const childOf = (
|
|
354
|
+
parents: Obj.Unknown | Ref.Unknown | readonly (Obj.Unknown | Ref.Unknown)[],
|
|
355
|
+
options?: ChildOfOptions,
|
|
356
|
+
): Any => {
|
|
357
|
+
const items = Array.isArray(parents) ? parents : [parents];
|
|
358
|
+
const dxns = items.map((item) => {
|
|
359
|
+
if (Ref.isRef(item)) {
|
|
360
|
+
return item.dxn.toString();
|
|
361
|
+
}
|
|
362
|
+
return internal.getDXN(item).toString();
|
|
363
|
+
});
|
|
364
|
+
return new FilterClass({
|
|
365
|
+
type: 'child-of',
|
|
366
|
+
parents: dxns,
|
|
367
|
+
transitive: options?.transitive ?? true,
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
|
|
298
371
|
/**
|
|
299
372
|
* Negate the filter.
|
|
300
373
|
*/
|
|
@@ -374,3 +447,8 @@ const processPredicate = (predicate: any): QueryAST.Filter => {
|
|
|
374
447
|
Match.orElse((value) => eq(value).ast),
|
|
375
448
|
);
|
|
376
449
|
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Returns a human-readable string representation of a Filter AST.
|
|
453
|
+
*/
|
|
454
|
+
export const pretty = (filter: Any): string => internal.prettyFilter(filter.ast);
|
package/src/Format.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import type * as internal from './internal';
|
|
6
6
|
|
|
7
|
-
export * from './internal/
|
|
7
|
+
export * from './internal/Format';
|
|
8
8
|
|
|
9
|
-
export type
|
|
9
|
+
export type Format = internal.TypeFormat;
|
package/src/Hypergraph.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type DXN } from '@dxos/keys';
|
|
|
6
6
|
|
|
7
7
|
import type * as Database from './Database';
|
|
8
8
|
import type * as Entity from './Entity';
|
|
9
|
-
import
|
|
9
|
+
import type * as internal from './internal';
|
|
10
10
|
import type * as Key from './Key';
|
|
11
11
|
import type * as Ref from './Ref';
|
|
12
12
|
import type * as SchemaRegistry from './SchemaRegistry';
|
|
@@ -39,13 +39,12 @@ export interface RefResolverOptions {
|
|
|
39
39
|
* Middleware to change the resolved object before returning it.
|
|
40
40
|
* @deprecated On track to be removed.
|
|
41
41
|
*/
|
|
42
|
-
middleware?: (obj: AnyProperties) => AnyProperties;
|
|
42
|
+
middleware?: (obj: internal.AnyProperties) => internal.AnyProperties;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Manages cross-space database interactions.
|
|
47
47
|
*/
|
|
48
|
-
// TODO(burdon): Comment required.
|
|
49
48
|
export interface Hypergraph extends Database.Queryable {
|
|
50
49
|
get schemaRegistry(): SchemaRegistry.SchemaRegistry;
|
|
51
50
|
|
|
@@ -71,4 +70,10 @@ export interface Hypergraph extends Database.Queryable {
|
|
|
71
70
|
*/
|
|
72
71
|
// TODO(dmaretskyi): Restructure API: Remove middleware.
|
|
73
72
|
createRefResolver(options: RefResolverOptions): Ref.Resolver;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get a database by space ID.
|
|
76
|
+
* @returns The database for the given space ID, or undefined if not found.
|
|
77
|
+
*/
|
|
78
|
+
getDatabase(spaceId: Key.SpaceId): Database.Database | undefined;
|
|
74
79
|
}
|
package/src/Json.test.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { DXN, ObjectId } from '@dxos/keys';
|
|
8
|
+
import { safeStringify } from '@dxos/util';
|
|
9
|
+
|
|
10
|
+
import * as Database from './Database';
|
|
11
|
+
import * as Json from './Json';
|
|
12
|
+
|
|
13
|
+
/** Mint a random ECHO object id usable as both a stub-db key and a DXN payload. */
|
|
14
|
+
const newId = (): string => ObjectId.random();
|
|
15
|
+
|
|
16
|
+
/** Build a fake encoded ref for a local-space object id. */
|
|
17
|
+
const encodeRef = (id: string): { '/': string } => ({ '/': DXN.fromLocalObjectId(id).toString() });
|
|
18
|
+
|
|
19
|
+
/** Minimal stub: `createRefReplacer` only touches `db.getObjectById`. */
|
|
20
|
+
const makeStubDb = (objects: Record<string, unknown>): Database.Database => {
|
|
21
|
+
return {
|
|
22
|
+
getObjectById: (id: string) => objects[id],
|
|
23
|
+
} as unknown as Database.Database;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Run a value through the replacer's public contract — `JSON.stringify(value, replacer)` —
|
|
28
|
+
* then re-parse the result so tests can assert on plain JS shapes. This mirrors the way
|
|
29
|
+
* the JSON highlighter invokes the replacer in production.
|
|
30
|
+
*/
|
|
31
|
+
const stringifyWith = (replacer: Json.JsonReplacer, value: unknown): unknown =>
|
|
32
|
+
JSON.parse(JSON.stringify(value, replacer));
|
|
33
|
+
|
|
34
|
+
describe('createRefReplacer', () => {
|
|
35
|
+
test('passes plain values through unchanged', () => {
|
|
36
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
37
|
+
const subject = { a: 1, b: 'two', c: [3, { d: 4 }] };
|
|
38
|
+
expect(stringifyWith(replacer, subject)).toEqual(subject);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('inlines refs at default depth (1)', () => {
|
|
42
|
+
const id = newId();
|
|
43
|
+
const target = { name: 'inlined' };
|
|
44
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [id]: target }) });
|
|
45
|
+
const subject = { ref: encodeRef(id) };
|
|
46
|
+
expect(stringifyWith(replacer, subject)).toEqual({ ref: target });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('does not follow refs when depth is 0', () => {
|
|
50
|
+
const id = newId();
|
|
51
|
+
const target = { name: 'inlined' };
|
|
52
|
+
const ref = encodeRef(id);
|
|
53
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [id]: target }), depth: 0 });
|
|
54
|
+
expect(stringifyWith(replacer, { ref })).toEqual({ ref });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('inlines refs across multiple levels up to depth', () => {
|
|
58
|
+
const innerId = newId();
|
|
59
|
+
const middleId = newId();
|
|
60
|
+
const inner = { name: 'inner' };
|
|
61
|
+
const middle = { ref: encodeRef(innerId) };
|
|
62
|
+
const outer = { ref: encodeRef(middleId) };
|
|
63
|
+
const db = makeStubDb({ [innerId]: inner, [middleId]: middle });
|
|
64
|
+
|
|
65
|
+
expect(stringifyWith(Json.createRefReplacer({ db, depth: 1 }), outer)).toEqual({
|
|
66
|
+
ref: { ref: encodeRef(innerId) },
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(stringifyWith(Json.createRefReplacer({ db, depth: 2 }), outer)).toEqual({
|
|
70
|
+
ref: { ref: inner },
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('leaves refs encoded when the target is missing in the db', () => {
|
|
75
|
+
const ref = encodeRef(newId());
|
|
76
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
77
|
+
expect(stringifyWith(replacer, { ref })).toEqual({ ref });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('leaves non-DXN single-key { "/": string } objects untouched', () => {
|
|
81
|
+
// Same `{ '/': string }` shape is used by other IPLD-style refs (e.g. CIDs); those should
|
|
82
|
+
// not crash the replacer and should pass through verbatim.
|
|
83
|
+
const cidLike = { '/': 'bafybeibwzifw7izxykxz' };
|
|
84
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
85
|
+
expect(stringifyWith(replacer, { ref: cidLike })).toEqual({ ref: cidLike });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('leaves malformed dxn strings untouched', () => {
|
|
89
|
+
const malformed = { '/': 'dxn:not-a-real-dxn' };
|
|
90
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
91
|
+
expect(stringifyWith(replacer, { ref: malformed })).toEqual({ ref: malformed });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test('leaves non-echo dxns untouched (e.g. type DXN)', () => {
|
|
95
|
+
// Type DXNs share the `dxn:` prefix but `asEchoDXN()` returns undefined.
|
|
96
|
+
const typeRef = { '/': DXN.fromTypename('com.example.Thing').toString() };
|
|
97
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
98
|
+
expect(stringifyWith(replacer, { ref: typeRef })).toEqual({ ref: typeRef });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('inlines refs inside arrays', () => {
|
|
102
|
+
const idA = newId();
|
|
103
|
+
const idB = newId();
|
|
104
|
+
const a = { name: 'a' };
|
|
105
|
+
const b = { name: 'b' };
|
|
106
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [idA]: a, [idB]: b }) });
|
|
107
|
+
expect(stringifyWith(replacer, { items: [encodeRef(idA), encodeRef(idB), { plain: true }] })).toEqual({
|
|
108
|
+
items: [a, b, { plain: true }],
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('walks nested objects recursively', () => {
|
|
113
|
+
const innerId = newId();
|
|
114
|
+
const inner = { name: 'inner' };
|
|
115
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [innerId]: inner }) });
|
|
116
|
+
const subject = { outer: { mid: { ref: encodeRef(innerId) } } };
|
|
117
|
+
expect(stringifyWith(replacer, subject)).toEqual({ outer: { mid: { ref: inner } } });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('a single replacer invocation does not recurse on its own', () => {
|
|
121
|
+
// The replacer is per-call; JSON.stringify drives the tree walk. Calling the replacer
|
|
122
|
+
// directly on a cyclic input must therefore return without touching the cycle.
|
|
123
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({}) });
|
|
124
|
+
const node: any = { name: 'self' };
|
|
125
|
+
node.self = node;
|
|
126
|
+
|
|
127
|
+
expect(() => replacer('', node)).not.toThrow();
|
|
128
|
+
expect(replacer('', node)).toBe(node);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('invokes `toJSON` on resolved targets so refs in the target are re-walked', () => {
|
|
132
|
+
// Simulates the ECHO-object branch: `db.getObjectById` returns a live proxy, the replacer
|
|
133
|
+
// calls `.toJSON()` to get the encoded form, then continues walking that form. A ref nested
|
|
134
|
+
// inside the target should be inlined when there's depth budget remaining.
|
|
135
|
+
const outerId = newId();
|
|
136
|
+
const innerId = newId();
|
|
137
|
+
const inner = { name: 'inner' };
|
|
138
|
+
const target = {
|
|
139
|
+
toJSON: () => ({ nestedRef: encodeRef(innerId) }),
|
|
140
|
+
};
|
|
141
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [outerId]: target, [innerId]: inner }), depth: 2 });
|
|
142
|
+
expect(stringifyWith(replacer, { ref: encodeRef(outerId) })).toEqual({
|
|
143
|
+
ref: { nestedRef: inner },
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('depth budget counts ref hops, not tree depth — a ref deep in a plain tree still resolves', () => {
|
|
148
|
+
// A ref nested under arbitrarily many plain objects is one ref hop from the root, so
|
|
149
|
+
// `depth: 1` resolves it. `depth: 0` leaves it encoded.
|
|
150
|
+
const innerId = newId();
|
|
151
|
+
const inner = { name: 'inner' };
|
|
152
|
+
const subject = { a: { b: { c: { d: { ref: encodeRef(innerId) } } } } };
|
|
153
|
+
|
|
154
|
+
const inlining = Json.createRefReplacer({ db: makeStubDb({ [innerId]: inner }), depth: 1 });
|
|
155
|
+
expect(stringifyWith(inlining, subject)).toEqual({ a: { b: { c: { d: { ref: inner } } } } });
|
|
156
|
+
|
|
157
|
+
const passthrough = Json.createRefReplacer({ db: makeStubDb({ [innerId]: inner }), depth: 0 });
|
|
158
|
+
expect(stringifyWith(passthrough, subject)).toEqual(subject);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('inlines refs when invoked through safeStringify (production path)', () => {
|
|
162
|
+
// `JsonHighlighter` runs the replacer through `@dxos/util/safeStringify`, whose inner
|
|
163
|
+
// wrapper short-circuits the root call without forwarding it to the user's filter. The
|
|
164
|
+
// replacer must therefore work on a per-call basis — not as a one-shot root tree walk.
|
|
165
|
+
// This regression-tests that integration: the `content` ref must inline.
|
|
166
|
+
const targetId = newId();
|
|
167
|
+
const target = { toJSON: () => ({ name: 'README content' }) };
|
|
168
|
+
const document = { id: '01ABC', name: 'README', content: encodeRef(targetId) };
|
|
169
|
+
|
|
170
|
+
const replacer = Json.createRefReplacer({ db: makeStubDb({ [targetId]: target }) });
|
|
171
|
+
const out = JSON.parse(safeStringify(document, replacer, 0)!);
|
|
172
|
+
|
|
173
|
+
expect(out).toEqual({ id: '01ABC', name: 'README', content: { name: 'README content' } });
|
|
174
|
+
});
|
|
175
|
+
});
|
package/src/Json.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { DXN } from '@dxos/keys';
|
|
6
|
+
|
|
7
|
+
import * as Database from './Database';
|
|
8
|
+
import * as Obj from './Obj';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `JSON.stringify` replacer signature.
|
|
12
|
+
*
|
|
13
|
+
* Defined here (rather than re-imported from a UI package) so other ECHO-aware utilities can
|
|
14
|
+
* share a stable signature without creating a dependency edge into the UI tree.
|
|
15
|
+
*/
|
|
16
|
+
export type JsonReplacer = (key: string, value: any) => any;
|
|
17
|
+
|
|
18
|
+
export type CreateRefReplacerOptions = {
|
|
19
|
+
db: Database.Database;
|
|
20
|
+
/** How many ref hops to follow. `0` leaves all refs as-is. Default: `1`. */
|
|
21
|
+
depth?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const isEncodedRef = (value: unknown): value is { '/': string } =>
|
|
25
|
+
typeof value === 'object' &&
|
|
26
|
+
value !== null &&
|
|
27
|
+
Object.keys(value as object).length === 1 &&
|
|
28
|
+
typeof (value as { '/': unknown })['/'] === 'string';
|
|
29
|
+
|
|
30
|
+
const toJson = (obj: Obj.Any): unknown => (typeof (obj as any).toJSON === 'function' ? (obj as any).toJSON() : obj);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns a {@link JsonReplacer} that inlines ECHO ref objects (`{ "/": "dxn:echo:..." }`) up to
|
|
34
|
+
* `depth` ref hops. Beyond that depth refs are left in their encoded form.
|
|
35
|
+
*
|
|
36
|
+
* Implemented as a per-call `JSON.stringify` replacer (not a one-shot tree walk at root) so it
|
|
37
|
+
* composes with wrappers like `safeStringify` that intercept the root call. JSON.stringify
|
|
38
|
+
* already drives the recursion; we only need to (a) detect a ref at the current callback,
|
|
39
|
+
* (b) resolve and return the target if hop budget remains, and (c) tag the returned object
|
|
40
|
+
* with its hop count so children know how far in they are.
|
|
41
|
+
*
|
|
42
|
+
* The hop count is tracked per-object via a `WeakMap`: a ref-resolved target's children inherit
|
|
43
|
+
* `parentHops + 1`; a regular intermediate object's children inherit `parentHops`. This makes the
|
|
44
|
+
* budget count *ref hops*, not tree depth — a ref deep in a tree still resolves once when
|
|
45
|
+
* `depth >= 1`.
|
|
46
|
+
*
|
|
47
|
+
* Note: ECHO objects' `toJSON` runs before the replacer is invoked, so by the time we see a
|
|
48
|
+
* value refs are already encoded as `{ "/": "dxn:..." }`.
|
|
49
|
+
*/
|
|
50
|
+
export const createRefReplacer = ({ db, depth = 1 }: CreateRefReplacerOptions): JsonReplacer => {
|
|
51
|
+
// Per-object hop count. Set when we return an object (via ref resolution or pass-through) so
|
|
52
|
+
// the child callbacks (which carry that object as `this`) can read it.
|
|
53
|
+
const hops = new WeakMap<object, number>();
|
|
54
|
+
|
|
55
|
+
return function (this: any, key: string, value: any) {
|
|
56
|
+
// Hop count for this call: hops at the parent, or 0 for the root.
|
|
57
|
+
const parentHops = this && typeof this === 'object' ? (hops.get(this) ?? 0) : 0;
|
|
58
|
+
if (isEncodedRef(value)) {
|
|
59
|
+
if (parentHops >= depth) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The `{ '/': string }` shape is shared with non-DXN IPLD-style refs (e.g. CIDs);
|
|
64
|
+
// an unparseable string would otherwise crash the whole `JSON.stringify`.
|
|
65
|
+
// Treat any parse miss as "leave as-is" rather than propagating.
|
|
66
|
+
const dxnString = value['/'];
|
|
67
|
+
if (!dxnString.startsWith('dxn:')) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let echoId: string | undefined;
|
|
72
|
+
try {
|
|
73
|
+
echoId = DXN.parse(dxnString).asEchoDXN()?.echoId;
|
|
74
|
+
} catch {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!echoId) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
const target = db.getObjectById(echoId);
|
|
82
|
+
if (!target) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const encoded = toJson(target);
|
|
87
|
+
if (encoded != null && typeof encoded === 'object') {
|
|
88
|
+
// Children of the resolved target are one hop deeper.
|
|
89
|
+
hops.set(encoded as object, parentHops + 1);
|
|
90
|
+
}
|
|
91
|
+
return encoded;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Pass-through object: children inherit the parent's hop count (this branch doesn't burn
|
|
95
|
+
// budget).
|
|
96
|
+
if (value != null && typeof value === 'object') {
|
|
97
|
+
hops.set(value, parentHops);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return value;
|
|
101
|
+
};
|
|
102
|
+
};
|
package/src/JsonSchema.ts
CHANGED
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
// @import-as-namespace
|
|
6
|
+
|
|
5
7
|
import type * as Schema from 'effect/Schema';
|
|
6
8
|
|
|
7
|
-
import
|
|
9
|
+
import * as jsonSchemaInternal from './internal/JsonSchema';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Decode JSON Schema to Effect Schema.
|
|
13
|
+
*/
|
|
14
|
+
export const toEffectSchema = jsonSchemaInternal.toEffectSchema;
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Encode Effect Schema to JSON Schema.
|
|
18
|
+
*/
|
|
19
|
+
export const toJsonSchema = jsonSchemaInternal.toJsonSchema;
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
22
|
* Serializable JsonSchema type definition.
|
|
13
23
|
*/
|
|
14
|
-
export type JsonSchema = JsonSchemaType;
|
|
24
|
+
export type JsonSchema = jsonSchemaInternal.JsonSchemaType;
|
|
15
25
|
|
|
16
|
-
export const JsonSchema: Schema.Schema<JsonSchemaType> = JsonSchemaType;
|
|
26
|
+
export const JsonSchema: Schema.Schema<jsonSchemaInternal.JsonSchemaType> = jsonSchemaInternal.JsonSchemaType;
|