@dxos/echo 0.8.4-staging.ac66bdf99f → 0.9.1-main.c7dcc2e112

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.
Files changed (444) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +7 -7
  3. package/dist/lib/neutral/Annotation.mjs +45 -6
  4. package/dist/lib/neutral/Database.mjs +10 -17
  5. package/dist/lib/neutral/Entity.mjs +35 -20
  6. package/dist/lib/neutral/Err.mjs +3 -3
  7. package/dist/lib/neutral/Feed.mjs +23 -19
  8. package/dist/lib/neutral/Filter.mjs +13 -15
  9. package/dist/lib/neutral/Format.mjs +23 -3
  10. package/dist/lib/neutral/JsonSchema.mjs +7 -8
  11. package/dist/lib/neutral/Key.mjs +9 -5
  12. package/dist/lib/neutral/Migration.mjs +11 -10
  13. package/dist/lib/neutral/Obj.mjs +33 -20
  14. package/dist/lib/neutral/Order.mjs +7 -3
  15. package/dist/lib/neutral/Query.mjs +17 -17
  16. package/dist/lib/neutral/QueryResult.mjs +1 -1
  17. package/dist/lib/neutral/Ref.mjs +10 -9
  18. package/dist/lib/neutral/Registry.mjs +14 -0
  19. package/dist/lib/neutral/Relation.mjs +28 -25
  20. package/dist/lib/neutral/Scope.mjs +12 -0
  21. package/dist/lib/neutral/Tag.mjs +17 -14
  22. package/dist/lib/neutral/Type.mjs +54 -26
  23. package/dist/lib/neutral/{chunk-OMUPQMLR.mjs → chunk-35INCYOE.mjs} +1 -1
  24. package/dist/lib/neutral/chunk-35INCYOE.mjs.map +7 -0
  25. package/dist/lib/neutral/{chunk-4OIBYSXE.mjs → chunk-3JXQUMUI.mjs} +78 -32
  26. package/dist/lib/neutral/chunk-3JXQUMUI.mjs.map +7 -0
  27. package/dist/lib/neutral/{chunk-G3IQMKF7.mjs → chunk-4TPQZPLY.mjs} +130 -119
  28. package/dist/lib/neutral/chunk-4TPQZPLY.mjs.map +7 -0
  29. package/dist/lib/neutral/{chunk-TU3GW67D.mjs → chunk-5GAIWRQB.mjs} +40 -40
  30. package/dist/lib/neutral/chunk-5GAIWRQB.mjs.map +7 -0
  31. package/dist/lib/neutral/{chunk-B4BASU6W.mjs → chunk-6CEISA3V.mjs} +93 -76
  32. package/dist/lib/neutral/chunk-6CEISA3V.mjs.map +7 -0
  33. package/dist/lib/neutral/{chunk-GZQTCRJB.mjs → chunk-6M2Z6WBH.mjs} +22 -2
  34. package/dist/lib/neutral/chunk-6M2Z6WBH.mjs.map +7 -0
  35. package/dist/lib/neutral/{chunk-ANHVGJI4.mjs → chunk-7LOUAPYZ.mjs} +9 -5
  36. package/dist/lib/neutral/chunk-7LOUAPYZ.mjs.map +7 -0
  37. package/dist/lib/neutral/{chunk-WAK4DMFV.mjs → chunk-A53NTBHE.mjs} +12 -7
  38. package/dist/lib/neutral/chunk-A53NTBHE.mjs.map +7 -0
  39. package/dist/lib/neutral/{chunk-EAMSSLZC.mjs → chunk-AFANXSGV.mjs} +83 -46
  40. package/dist/lib/neutral/chunk-AFANXSGV.mjs.map +7 -0
  41. package/dist/lib/neutral/{chunk-UBEZSGXY.mjs → chunk-BBFJWWAV.mjs} +6 -6
  42. package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +7 -0
  43. package/dist/lib/neutral/chunk-E7IOTOZD.mjs +108 -0
  44. package/dist/lib/neutral/chunk-E7IOTOZD.mjs.map +7 -0
  45. package/dist/lib/neutral/{chunk-UI6MWK5W.mjs → chunk-EVK6XBXO.mjs} +16 -2
  46. package/dist/lib/neutral/chunk-EVK6XBXO.mjs.map +7 -0
  47. package/dist/lib/neutral/chunk-HGWQR5KH.mjs +259 -0
  48. package/dist/lib/neutral/chunk-HGWQR5KH.mjs.map +7 -0
  49. package/dist/lib/neutral/chunk-JZ6LFQU5.mjs +109 -0
  50. package/dist/lib/neutral/chunk-JZ6LFQU5.mjs.map +7 -0
  51. package/dist/lib/neutral/{chunk-JUXPFOEI.mjs → chunk-K3S7D5PR.mjs} +48 -88
  52. package/dist/lib/neutral/chunk-K3S7D5PR.mjs.map +7 -0
  53. package/dist/lib/neutral/{chunk-OS35K56T.mjs → chunk-L3OBWBV2.mjs} +3 -3
  54. package/dist/lib/neutral/{chunk-OS35K56T.mjs.map → chunk-L3OBWBV2.mjs.map} +2 -2
  55. package/dist/lib/neutral/{chunk-V36VO5SS.mjs → chunk-NOL7O3BL.mjs} +32 -40
  56. package/dist/lib/neutral/chunk-NOL7O3BL.mjs.map +7 -0
  57. package/dist/lib/neutral/{chunk-TBKX6JQO.mjs → chunk-O6BH7EPN.mjs} +30 -3
  58. package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +7 -0
  59. package/dist/lib/neutral/{chunk-7RO7CPBZ.mjs → chunk-PLDMJJJC.mjs} +2 -2
  60. package/dist/lib/neutral/{chunk-HBUZJNZO.mjs → chunk-SZ5WB6HF.mjs} +94 -99
  61. package/dist/lib/neutral/chunk-SZ5WB6HF.mjs.map +7 -0
  62. package/dist/lib/neutral/{chunk-BVOFLCVF.mjs → chunk-TF5BSLF6.mjs} +9 -6
  63. package/dist/lib/neutral/chunk-TF5BSLF6.mjs.map +7 -0
  64. package/dist/lib/neutral/{chunk-DQYLD2RB.mjs → chunk-TFEWTY5A.mjs} +155 -129
  65. package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +7 -0
  66. package/dist/lib/neutral/{chunk-MOR5ERFM.mjs → chunk-VQYL2OQF.mjs} +771 -1252
  67. package/dist/lib/neutral/chunk-VQYL2OQF.mjs.map +7 -0
  68. package/dist/lib/neutral/chunk-WISOH2XH.mjs +36 -0
  69. package/dist/lib/neutral/chunk-WISOH2XH.mjs.map +7 -0
  70. package/dist/lib/neutral/chunk-WU3GIANS.mjs +31 -0
  71. package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +7 -0
  72. package/dist/lib/neutral/chunk-WZ32BF53.mjs +702 -0
  73. package/dist/lib/neutral/chunk-WZ32BF53.mjs.map +7 -0
  74. package/dist/lib/neutral/chunk-X3NUUON4.mjs +184 -0
  75. package/dist/lib/neutral/chunk-X3NUUON4.mjs.map +7 -0
  76. package/dist/lib/neutral/chunk-Z3WMRRAZ.mjs +168 -0
  77. package/dist/lib/neutral/chunk-Z3WMRRAZ.mjs.map +7 -0
  78. package/dist/lib/neutral/index.mjs +47 -41
  79. package/dist/lib/neutral/internal/index.mjs +157 -72
  80. package/dist/lib/neutral/meta.json +1 -1
  81. package/dist/lib/neutral/testing/index.mjs +261 -178
  82. package/dist/lib/neutral/testing/index.mjs.map +4 -4
  83. package/dist/types/src/Annotation.d.ts +108 -4
  84. package/dist/types/src/Annotation.d.ts.map +1 -1
  85. package/dist/types/src/Annotation.test.d.ts +2 -0
  86. package/dist/types/src/Annotation.test.d.ts.map +1 -0
  87. package/dist/types/src/Collection.d.ts +2 -3
  88. package/dist/types/src/Collection.d.ts.map +1 -1
  89. package/dist/types/src/Database.d.ts +78 -49
  90. package/dist/types/src/Database.d.ts.map +1 -1
  91. package/dist/types/src/Dataset.d.ts +16 -6
  92. package/dist/types/src/Dataset.d.ts.map +1 -1
  93. package/dist/types/src/Entity.d.ts +103 -28
  94. package/dist/types/src/Entity.d.ts.map +1 -1
  95. package/dist/types/src/Err.d.ts +27 -27
  96. package/dist/types/src/Err.d.ts.map +1 -1
  97. package/dist/types/src/Feed.d.ts +69 -19
  98. package/dist/types/src/Feed.d.ts.map +1 -1
  99. package/dist/types/src/Filter.d.ts +38 -12
  100. package/dist/types/src/Filter.d.ts.map +1 -1
  101. package/dist/types/src/Format.d.ts +0 -2
  102. package/dist/types/src/Format.d.ts.map +1 -1
  103. package/dist/types/src/Hypergraph.d.ts +14 -9
  104. package/dist/types/src/Hypergraph.d.ts.map +1 -1
  105. package/dist/types/src/Json.d.ts +33 -0
  106. package/dist/types/src/Json.d.ts.map +1 -0
  107. package/dist/types/src/Json.test.d.ts +2 -0
  108. package/dist/types/src/Json.test.d.ts.map +1 -0
  109. package/dist/types/src/JsonSchema.d.ts +2 -2
  110. package/dist/types/src/JsonSchema.d.ts.map +1 -1
  111. package/dist/types/src/Key.d.ts +1 -1
  112. package/dist/types/src/Key.d.ts.map +1 -1
  113. package/dist/types/src/Migration.d.ts +26 -11
  114. package/dist/types/src/Migration.d.ts.map +1 -1
  115. package/dist/types/src/Obj.d.ts +106 -61
  116. package/dist/types/src/Obj.d.ts.map +1 -1
  117. package/dist/types/src/Order.d.ts +10 -0
  118. package/dist/types/src/Order.d.ts.map +1 -1
  119. package/dist/types/src/Query.d.ts +34 -12
  120. package/dist/types/src/Query.d.ts.map +1 -1
  121. package/dist/types/src/QueryResult.d.ts +21 -0
  122. package/dist/types/src/QueryResult.d.ts.map +1 -1
  123. package/dist/types/src/Ref.d.ts +15 -7
  124. package/dist/types/src/Ref.d.ts.map +1 -1
  125. package/dist/types/src/Registry.d.ts +131 -0
  126. package/dist/types/src/Registry.d.ts.map +1 -0
  127. package/dist/types/src/Relation.d.ts +73 -41
  128. package/dist/types/src/Relation.d.ts.map +1 -1
  129. package/dist/types/src/Scope.d.ts +35 -0
  130. package/dist/types/src/Scope.d.ts.map +1 -0
  131. package/dist/types/src/Tag.d.ts +21 -5
  132. package/dist/types/src/Tag.d.ts.map +1 -1
  133. package/dist/types/src/Type.d.ts +366 -95
  134. package/dist/types/src/Type.d.ts.map +1 -1
  135. package/dist/types/src/View.d.ts +9 -12
  136. package/dist/types/src/View.d.ts.map +1 -1
  137. package/dist/types/src/exemplars.test.d.ts +2 -0
  138. package/dist/types/src/exemplars.test.d.ts.map +1 -0
  139. package/dist/types/src/index.d.ts +4 -3
  140. package/dist/types/src/index.d.ts.map +1 -1
  141. package/dist/types/src/internal/Annotation/annotations.d.ts +120 -38
  142. package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -1
  143. package/dist/types/src/internal/Annotation/dictionary.d.ts +24 -0
  144. package/dist/types/src/internal/Annotation/dictionary.d.ts.map +1 -0
  145. package/dist/types/src/internal/Annotation/entity-dictionary.d.ts +14 -0
  146. package/dist/types/src/internal/Annotation/entity-dictionary.d.ts.map +1 -0
  147. package/dist/types/src/internal/Annotation/index.d.ts +4 -2
  148. package/dist/types/src/internal/Annotation/index.d.ts.map +1 -1
  149. package/dist/types/src/internal/Annotation/sorting.d.ts.map +1 -1
  150. package/dist/types/src/internal/Annotation/util.d.ts +14 -5
  151. package/dist/types/src/internal/Annotation/util.d.ts.map +1 -1
  152. package/dist/types/src/internal/Entity/api.d.ts +17 -3
  153. package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
  154. package/dist/types/src/internal/Entity/entity.d.ts +72 -8
  155. package/dist/types/src/internal/Entity/entity.d.ts.map +1 -1
  156. package/dist/types/src/internal/Entity/guard.d.ts +10 -0
  157. package/dist/types/src/internal/Entity/guard.d.ts.map +1 -0
  158. package/dist/types/src/internal/Entity/index.d.ts +2 -0
  159. package/dist/types/src/internal/Entity/index.d.ts.map +1 -1
  160. package/dist/types/src/internal/Entity/model.d.ts +21 -17
  161. package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
  162. package/dist/types/src/internal/Entity/object.d.ts +3 -3
  163. package/dist/types/src/internal/Entity/object.d.ts.map +1 -1
  164. package/dist/types/src/internal/Entity/relation.d.ts +30 -7
  165. package/dist/types/src/internal/Entity/relation.d.ts.map +1 -1
  166. package/dist/types/src/internal/Entity/type-kind.d.ts +24 -0
  167. package/dist/types/src/internal/Entity/type-kind.d.ts.map +1 -0
  168. package/dist/types/src/internal/Entity/type-uri.d.ts +24 -0
  169. package/dist/types/src/internal/Entity/type-uri.d.ts.map +1 -0
  170. package/dist/types/src/internal/Entity/version.d.ts.map +1 -1
  171. package/dist/types/src/internal/Format/date.d.ts.map +1 -1
  172. package/dist/types/src/internal/Format/format.d.ts +3 -2
  173. package/dist/types/src/internal/Format/format.d.ts.map +1 -1
  174. package/dist/types/src/internal/Format/index.d.ts +2 -2
  175. package/dist/types/src/internal/Format/index.d.ts.map +1 -1
  176. package/dist/types/src/internal/Format/number.d.ts.map +1 -1
  177. package/dist/types/src/internal/Format/object.d.ts +3 -1
  178. package/dist/types/src/internal/Format/object.d.ts.map +1 -1
  179. package/dist/types/src/internal/Format/types.d.ts.map +1 -1
  180. package/dist/types/src/internal/JsonSchema/json-schema-normalize.d.ts.map +1 -1
  181. package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts +34 -34
  182. package/dist/types/src/internal/JsonSchema/json-schema-type.d.ts.map +1 -1
  183. package/dist/types/src/internal/JsonSchema/json-schema.d.ts +3 -2
  184. package/dist/types/src/internal/JsonSchema/json-schema.d.ts.map +1 -1
  185. package/dist/types/src/internal/Obj/atoms.d.ts +43 -0
  186. package/dist/types/src/internal/Obj/atoms.d.ts.map +1 -0
  187. package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
  188. package/dist/types/src/internal/Obj/common.d.ts.map +1 -1
  189. package/dist/types/src/internal/Obj/create-object.d.ts +12 -12
  190. package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
  191. package/dist/types/src/internal/Obj/deleted.d.ts.map +1 -1
  192. package/dist/types/src/internal/Obj/index.d.ts +1 -1
  193. package/dist/types/src/internal/Obj/index.d.ts.map +1 -1
  194. package/dist/types/src/internal/Obj/json-serializer.d.ts +8 -8
  195. package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
  196. package/dist/types/src/internal/Obj/set-value.d.ts +1 -1
  197. package/dist/types/src/internal/Obj/set-value.d.ts.map +1 -1
  198. package/dist/types/src/internal/Obj/snapshot.d.ts.map +1 -1
  199. package/dist/types/src/internal/Obj/typed-object.d.ts +1 -1
  200. package/dist/types/src/internal/Query/index.d.ts +2 -0
  201. package/dist/types/src/internal/Query/index.d.ts.map +1 -0
  202. package/dist/types/src/internal/{Query.d.ts → Query/pretty.d.ts} +1 -1
  203. package/dist/types/src/internal/Query/pretty.d.ts.map +1 -0
  204. package/dist/types/src/internal/Ref/atoms.d.ts +10 -0
  205. package/dist/types/src/internal/Ref/atoms.d.ts.map +1 -0
  206. package/dist/types/src/internal/Ref/index.d.ts +1 -0
  207. package/dist/types/src/internal/Ref/index.d.ts.map +1 -1
  208. package/dist/types/src/internal/Ref/ref-array.d.ts +2 -2
  209. package/dist/types/src/internal/Ref/ref.d.ts +114 -19
  210. package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
  211. package/dist/types/src/internal/Ref/strong-deps.d.ts +35 -0
  212. package/dist/types/src/internal/Ref/strong-deps.d.ts.map +1 -0
  213. package/dist/types/src/internal/Ref/utils.d.ts +8 -0
  214. package/dist/types/src/internal/Ref/utils.d.ts.map +1 -0
  215. package/dist/types/src/internal/Type/compose.d.ts.map +1 -1
  216. package/dist/types/src/internal/Type/index.d.ts +1 -2
  217. package/dist/types/src/internal/Type/index.d.ts.map +1 -1
  218. package/dist/types/src/internal/Type/manipulation.d.ts +0 -1
  219. package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -1
  220. package/dist/types/src/internal/Type/type-schema.d.ts +52 -0
  221. package/dist/types/src/internal/Type/type-schema.d.ts.map +1 -0
  222. package/dist/types/src/internal/common/api/meta.d.ts +14 -11
  223. package/dist/types/src/internal/common/api/meta.d.ts.map +1 -1
  224. package/dist/types/src/internal/common/proxy/change-context.d.ts +1 -1
  225. package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -1
  226. package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -1
  227. package/dist/types/src/internal/common/proxy/errors.d.ts +1 -1
  228. package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -1
  229. package/dist/types/src/internal/common/proxy/event-batch.d.ts.map +1 -1
  230. package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -1
  231. package/dist/types/src/internal/common/proxy/make-object.d.ts +11 -5
  232. package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
  233. package/dist/types/src/internal/common/proxy/ownership.d.ts.map +1 -1
  234. package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
  235. package/dist/types/src/internal/common/proxy/reactive-array.d.ts +1 -1
  236. package/dist/types/src/internal/common/proxy/reactive.d.ts +1 -1
  237. package/dist/types/src/internal/common/proxy/reactive.d.ts.map +1 -1
  238. package/dist/types/src/internal/common/proxy/reactive.test.d.ts +2 -0
  239. package/dist/types/src/internal/common/proxy/reactive.test.d.ts.map +1 -0
  240. package/dist/types/src/internal/common/proxy/schema-validator.d.ts.map +1 -1
  241. package/dist/types/src/internal/common/proxy/typed-handler.d.ts +18 -2
  242. package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
  243. package/dist/types/src/internal/common/types/base.d.ts +4 -4
  244. package/dist/types/src/internal/common/types/base.d.ts.map +1 -1
  245. package/dist/types/src/internal/common/types/entity.d.ts +62 -5
  246. package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
  247. package/dist/types/src/internal/common/types/index.d.ts +1 -1
  248. package/dist/types/src/internal/common/types/index.d.ts.map +1 -1
  249. package/dist/types/src/internal/common/types/meta.d.ts +33 -12
  250. package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
  251. package/dist/types/src/internal/common/types/model-symbols.d.ts +15 -4
  252. package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -1
  253. package/dist/types/src/internal/common/types/typename.d.ts +7 -0
  254. package/dist/types/src/internal/common/types/typename.d.ts.map +1 -1
  255. package/dist/types/src/internal/common/types/version.d.ts +1 -1
  256. package/dist/types/src/internal/common/types/well-known-types.d.ts +11 -0
  257. package/dist/types/src/internal/common/types/well-known-types.d.ts.map +1 -0
  258. package/dist/types/src/internal/index.d.ts +2 -2
  259. package/dist/types/src/internal/index.d.ts.map +1 -1
  260. package/dist/types/src/testing/index.d.ts +1 -0
  261. package/dist/types/src/testing/index.d.ts.map +1 -1
  262. package/dist/types/src/testing/registry.d.ts +9 -0
  263. package/dist/types/src/testing/registry.d.ts.map +1 -0
  264. package/dist/types/src/testing/test-data.d.ts +8 -8
  265. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  266. package/dist/types/src/testing/test-schema.d.ts +83 -89
  267. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  268. package/dist/types/src/testing/util.d.ts +5 -3
  269. package/dist/types/src/testing/util.d.ts.map +1 -1
  270. package/dist/types/tsconfig.tsbuildinfo +1 -1
  271. package/package.json +26 -24
  272. package/src/Annotation.test.ts +439 -0
  273. package/src/Annotation.ts +163 -4
  274. package/src/Collection.ts +5 -9
  275. package/src/Database.ts +126 -101
  276. package/src/Dataset.ts +10 -2
  277. package/src/Entity.test.ts +116 -6
  278. package/src/Entity.ts +136 -32
  279. package/src/Err.ts +4 -4
  280. package/src/Feed.ts +95 -44
  281. package/src/Filter.ts +70 -40
  282. package/src/Format.ts +0 -4
  283. package/src/Hypergraph.ts +14 -9
  284. package/src/Json.test.ts +175 -0
  285. package/src/Json.ts +103 -0
  286. package/src/Key.ts +1 -1
  287. package/src/Migration.ts +39 -19
  288. package/src/Obj.test.ts +122 -20
  289. package/src/Obj.ts +170 -91
  290. package/src/Order.ts +22 -0
  291. package/src/Query.test.ts +183 -154
  292. package/src/Query.ts +172 -85
  293. package/src/QueryResult.ts +26 -0
  294. package/src/Ref.ts +22 -4
  295. package/src/Registry.ts +155 -0
  296. package/src/Relation.test.ts +10 -10
  297. package/src/Relation.ts +116 -69
  298. package/src/Scope.ts +50 -0
  299. package/src/Tag.md +88 -0
  300. package/src/Tag.ts +50 -6
  301. package/src/Type.test.ts +223 -18
  302. package/src/Type.ts +623 -131
  303. package/src/View.ts +14 -23
  304. package/src/exemplars.test.ts +21 -0
  305. package/src/index.ts +4 -4
  306. package/src/internal/Annotation/annotations.test.ts +31 -11
  307. package/src/internal/Annotation/annotations.ts +199 -111
  308. package/src/internal/Annotation/dictionary.ts +47 -0
  309. package/src/internal/Annotation/entity-dictionary.ts +74 -0
  310. package/src/internal/Annotation/index.ts +4 -2
  311. package/src/internal/Annotation/util.ts +17 -8
  312. package/src/internal/Entity/api.ts +54 -7
  313. package/src/internal/Entity/entity.ts +196 -47
  314. package/src/internal/Entity/guard.ts +26 -0
  315. package/src/internal/Entity/index.ts +2 -0
  316. package/src/internal/Entity/model.ts +38 -28
  317. package/src/internal/Entity/object.ts +21 -5
  318. package/src/internal/Entity/relation.ts +68 -34
  319. package/src/internal/Entity/type-kind.ts +75 -0
  320. package/src/internal/Entity/type-uri.ts +92 -0
  321. package/src/internal/Entity/util.ts +9 -9
  322. package/src/internal/Format/date.ts +0 -4
  323. package/src/internal/Format/format.test.ts +21 -0
  324. package/src/internal/Format/index.ts +2 -3
  325. package/src/internal/Format/object.ts +21 -4
  326. package/src/internal/Format/types.ts +1 -1
  327. package/src/internal/JsonSchema/annotations.ts +1 -1
  328. package/src/internal/JsonSchema/json-schema-type.ts +4 -4
  329. package/src/internal/JsonSchema/json-schema.test.ts +71 -145
  330. package/src/internal/JsonSchema/json-schema.ts +49 -35
  331. package/src/internal/Obj/atoms.ts +275 -0
  332. package/src/internal/Obj/clone.ts +9 -4
  333. package/src/internal/Obj/create-object.test.ts +12 -10
  334. package/src/internal/Obj/create-object.ts +68 -22
  335. package/src/internal/Obj/index.ts +1 -1
  336. package/src/internal/Obj/inspect.ts +5 -3
  337. package/src/internal/Obj/json-serializer.test.ts +101 -22
  338. package/src/internal/Obj/json-serializer.ts +92 -36
  339. package/src/internal/Obj/set-value.test.ts +22 -45
  340. package/src/internal/Obj/set-value.ts +12 -19
  341. package/src/internal/Obj/snapshot.ts +13 -4
  342. package/src/internal/Obj/typed-object.test.ts +9 -11
  343. package/src/internal/Obj/typed-object.ts +1 -1
  344. package/src/internal/Query/index.ts +5 -0
  345. package/src/internal/{Query.ts → Query/pretty.ts} +40 -12
  346. package/src/internal/Ref/atoms.ts +20 -0
  347. package/src/internal/Ref/index.ts +1 -0
  348. package/src/internal/Ref/ref-array.ts +3 -3
  349. package/src/internal/Ref/ref.test.ts +18 -27
  350. package/src/internal/Ref/ref.ts +224 -69
  351. package/src/internal/Ref/strong-deps.ts +107 -0
  352. package/src/internal/Ref/utils.ts +45 -0
  353. package/src/internal/Type/compose.test.ts +3 -1
  354. package/src/internal/Type/index.ts +1 -2
  355. package/src/internal/Type/manipulation.ts +0 -25
  356. package/src/internal/Type/type-schema.ts +60 -0
  357. package/src/internal/common/README.md +2 -2
  358. package/src/internal/common/api/meta.ts +19 -17
  359. package/src/internal/common/proxy/change-context.ts +1 -1
  360. package/src/internal/common/proxy/change.test.ts +91 -83
  361. package/src/internal/common/proxy/errors.ts +2 -2
  362. package/src/internal/common/proxy/handler.test.ts +1 -1
  363. package/src/internal/common/proxy/json-serializer.ts +27 -16
  364. package/src/internal/common/proxy/make-object.ts +44 -20
  365. package/src/internal/common/proxy/ownership.ts +2 -2
  366. package/src/internal/common/proxy/reactive-array.ts +1 -1
  367. package/src/internal/common/proxy/reactive.test.ts +54 -0
  368. package/src/internal/common/proxy/reactive.ts +11 -2
  369. package/src/internal/common/proxy/schema.test.ts +48 -86
  370. package/src/internal/common/proxy/typed-handler.test.ts +12 -11
  371. package/src/internal/common/proxy/typed-handler.ts +78 -16
  372. package/src/internal/common/proxy/typed-object.test.ts +16 -28
  373. package/src/internal/common/types/base.ts +4 -4
  374. package/src/internal/common/types/entity.ts +80 -1
  375. package/src/internal/common/types/index.ts +6 -1
  376. package/src/internal/common/types/meta.ts +62 -20
  377. package/src/internal/common/types/model-symbols.ts +24 -4
  378. package/src/internal/common/types/typename.ts +39 -3
  379. package/src/internal/common/types/well-known-types.ts +15 -0
  380. package/src/internal/index.ts +6 -4
  381. package/src/testing/api.test.ts +15 -9
  382. package/src/testing/index.ts +1 -0
  383. package/src/testing/registry.ts +44 -0
  384. package/src/testing/test-data.ts +159 -99
  385. package/src/testing/test-schema.ts +22 -58
  386. package/src/testing/util.ts +14 -11
  387. package/dist/lib/neutral/Extension.mjs +0 -18
  388. package/dist/lib/neutral/SchemaRegistry.mjs +0 -2
  389. package/dist/lib/neutral/chunk-2KHZ36F5.mjs +0 -361
  390. package/dist/lib/neutral/chunk-2KHZ36F5.mjs.map +0 -7
  391. package/dist/lib/neutral/chunk-4OIBYSXE.mjs.map +0 -7
  392. package/dist/lib/neutral/chunk-4P3IXBLT.mjs +0 -45
  393. package/dist/lib/neutral/chunk-4P3IXBLT.mjs.map +0 -7
  394. package/dist/lib/neutral/chunk-ANHVGJI4.mjs.map +0 -7
  395. package/dist/lib/neutral/chunk-B4BASU6W.mjs.map +0 -7
  396. package/dist/lib/neutral/chunk-BNCCGLJN.mjs +0 -7
  397. package/dist/lib/neutral/chunk-BNCCGLJN.mjs.map +0 -7
  398. package/dist/lib/neutral/chunk-BVOFLCVF.mjs.map +0 -7
  399. package/dist/lib/neutral/chunk-DQYLD2RB.mjs.map +0 -7
  400. package/dist/lib/neutral/chunk-EAMSSLZC.mjs.map +0 -7
  401. package/dist/lib/neutral/chunk-G3IQMKF7.mjs.map +0 -7
  402. package/dist/lib/neutral/chunk-GZQTCRJB.mjs.map +0 -7
  403. package/dist/lib/neutral/chunk-HBUZJNZO.mjs.map +0 -7
  404. package/dist/lib/neutral/chunk-JUXPFOEI.mjs.map +0 -7
  405. package/dist/lib/neutral/chunk-MOR5ERFM.mjs.map +0 -7
  406. package/dist/lib/neutral/chunk-OMUPQMLR.mjs.map +0 -7
  407. package/dist/lib/neutral/chunk-PHU22NLC.mjs +0 -136
  408. package/dist/lib/neutral/chunk-PHU22NLC.mjs.map +0 -7
  409. package/dist/lib/neutral/chunk-ROG4RXXL.mjs +0 -97
  410. package/dist/lib/neutral/chunk-ROG4RXXL.mjs.map +0 -7
  411. package/dist/lib/neutral/chunk-T6W2LEZU.mjs +0 -125
  412. package/dist/lib/neutral/chunk-T6W2LEZU.mjs.map +0 -7
  413. package/dist/lib/neutral/chunk-TBKX6JQO.mjs.map +0 -7
  414. package/dist/lib/neutral/chunk-TU3GW67D.mjs.map +0 -7
  415. package/dist/lib/neutral/chunk-UBEZSGXY.mjs.map +0 -7
  416. package/dist/lib/neutral/chunk-UI6MWK5W.mjs.map +0 -7
  417. package/dist/lib/neutral/chunk-V36VO5SS.mjs.map +0 -7
  418. package/dist/lib/neutral/chunk-WAK4DMFV.mjs.map +0 -7
  419. package/dist/lib/neutral/chunk-YAHXAYOW.mjs +0 -56
  420. package/dist/lib/neutral/chunk-YAHXAYOW.mjs.map +0 -7
  421. package/dist/lib/neutral/chunk-YS6Q3XAD.mjs +0 -50
  422. package/dist/lib/neutral/chunk-YS6Q3XAD.mjs.map +0 -7
  423. package/dist/types/src/Extension.d.ts +0 -80
  424. package/dist/types/src/Extension.d.ts.map +0 -1
  425. package/dist/types/src/Extension.test.d.ts +0 -2
  426. package/dist/types/src/Extension.test.d.ts.map +0 -1
  427. package/dist/types/src/SchemaRegistry.d.ts +0 -84
  428. package/dist/types/src/SchemaRegistry.d.ts.map +0 -1
  429. package/dist/types/src/internal/Obj/ids.d.ts +0 -6
  430. package/dist/types/src/internal/Obj/ids.d.ts.map +0 -1
  431. package/dist/types/src/internal/Query.d.ts.map +0 -1
  432. package/dist/types/src/internal/Type/echo-schema.d.ts +0 -181
  433. package/dist/types/src/internal/Type/echo-schema.d.ts.map +0 -1
  434. package/dist/types/src/internal/Type/persistent-schema.d.ts +0 -20
  435. package/dist/types/src/internal/Type/persistent-schema.d.ts.map +0 -1
  436. package/src/Extension.test.ts +0 -235
  437. package/src/Extension.ts +0 -122
  438. package/src/SchemaRegistry.ts +0 -106
  439. package/src/internal/Obj/ids.ts +0 -12
  440. package/src/internal/Type/echo-schema.ts +0 -423
  441. package/src/internal/Type/persistent-schema.ts +0 -33
  442. /package/dist/lib/neutral/{Extension.mjs.map → Registry.mjs.map} +0 -0
  443. /package/dist/lib/neutral/{SchemaRegistry.mjs.map → Scope.mjs.map} +0 -0
  444. /package/dist/lib/neutral/{chunk-7RO7CPBZ.mjs.map → chunk-PLDMJJJC.mjs.map} +0 -0
@@ -4,41 +4,57 @@
4
4
 
5
5
  import type * as Schema from 'effect/Schema';
6
6
 
7
- import { ObjectId } from '@dxos/keys';
7
+ import { EntityId } from '@dxos/keys';
8
8
 
9
- import { getTypeAnnotation } from '../../Annotation';
10
- import { type AnyProperties, KindId, MetaId, type ObjectMeta, ObjectMetaSchema, ParentId } from '../types';
9
+ import { getTypeAnnotation } from '../../Annotation/annotations';
10
+ import { type AnyProperties, KindId, ParentId, SchemaKindId, StaticTypeSchemaSlot } from '../types';
11
+ import { type EntityMeta, EntityMetaSchema } from '../types/meta';
12
+ import { MetaId } from '../types/model-symbols';
11
13
  import { defineHiddenProperty } from './define-hidden-property';
12
14
  import { attachTypedJsonSerializer } from './json-serializer';
13
15
  import { createProxy, getProxyTarget, isValidProxyTarget } from './proxy-utils';
14
- import { TypedReactiveHandler, prepareTypedTarget, setMetaOwner } from './typed-handler';
16
+ import { TypeSource, TypedReactiveHandler, prepareTypedTarget, setMetaOwner } from './typed-handler';
15
17
 
16
18
  /**
17
19
  *
18
20
  */
19
21
  // TODO(burdon): Make internal
20
- export type MakeObjectProps<T extends AnyProperties> = Omit<T, 'id' | KindId>;
22
+ // Omits the brand slots those get stamped on the instance by the entity
23
+ // handler (KindId via setKind, SchemaKindId derived in the proxy `get` trap
24
+ // from kind + jsonSchema.entityKind, StaticTypeSchemaSlot lazily via the
25
+ // proxy), not supplied by the caller.
26
+ export type MakeObjectProps<T extends AnyProperties> = Omit<T, 'id' | KindId | SchemaKindId | StaticTypeSchemaSlot>;
21
27
 
22
28
  /**
23
29
  * Creates a reactive object from a plain Javascript object.
24
30
  * Requires a TS-effect schema.
31
+ *
32
+ * Callers that have a `Type.Type` entity (not a raw schema) must unwrap it
33
+ * themselves — `Obj.make` / `Relation.make` do this via `Type.getSchema(...)`
34
+ * and pass the entity through as `typeSource` so the instance carries a
35
+ * back-reference for `Obj.getType` and resolves the live source schema
36
+ * uniformly via the entity's `[StaticTypeSchemaSlot]`.
25
37
  */
26
38
  // TODO(burdon): Make internal
27
39
  // TODO(dmaretskyi): Deep mutability.
28
40
  // TODO(dmaretskyi): Invert generics (generic over schema) to have better error messages.
29
41
  // TODO(dmaretskyi): Could mutate original object making it unusable.
30
- export const makeObject: {
31
- <T extends AnyProperties>(
32
- schema: Schema.Schema<T, any, never>,
33
- obj: NoInfer<MakeObjectProps<T>>,
34
- meta?: ObjectMeta,
35
- ): T;
36
- } = <T extends AnyProperties>(schema: Schema.Schema<T, any>, obj: MakeObjectProps<T>, meta?: ObjectMeta): T => {
42
+ export const makeObject = <T extends AnyProperties>(
43
+ schema: Schema.Schema<T, any, never>,
44
+ obj: NoInfer<MakeObjectProps<T>>,
45
+ meta?: Partial<EntityMeta>,
46
+ typeSource?: TypeSource,
47
+ ): T => {
37
48
  // Use Object.assign to copy symbol properties (like ParentId) that spread operator doesn't copy.
38
- return createReactiveObject<T>(Object.assign({}, obj) as T, meta, schema);
49
+ return createReactiveObject<T>(Object.assign({}, obj) as T, meta, schema as Schema.Schema<T, any>, typeSource);
39
50
  };
40
51
 
41
- const createReactiveObject = <T extends AnyProperties>(obj: T, meta?: ObjectMeta, schema?: Schema.Schema<T>): T => {
52
+ const createReactiveObject = <T extends AnyProperties>(
53
+ obj: T,
54
+ meta?: Partial<EntityMeta>,
55
+ schema?: Schema.Schema<T>,
56
+ typeSource?: TypeSource,
57
+ ): T => {
42
58
  if (!isValidProxyTarget(obj)) {
43
59
  throw new Error('Value cannot be made into a reactive object.');
44
60
  }
@@ -62,7 +78,7 @@ const createReactiveObject = <T extends AnyProperties>(obj: T, meta?: ObjectMeta
62
78
  if (parent !== undefined) {
63
79
  defineHiddenProperty(obj, ParentId, parent);
64
80
  }
65
- prepareTypedTarget(obj, schema);
81
+ prepareTypedTarget(obj, schema, typeSource);
66
82
  attachTypedJsonSerializer(obj);
67
83
  const proxy = createProxy<T>(obj, TypedReactiveHandler.instance);
68
84
 
@@ -87,11 +103,11 @@ const createReactiveObject = <T extends AnyProperties>(obj: T, meta?: ObjectMeta
87
103
  const setIdOnTarget = (target: any) => {
88
104
  // invariant(!('id' in target), 'Object already has an `id` field, which is reserved.');
89
105
  if ('id' in target && target.id !== undefined && target.id !== null) {
90
- if (!ObjectId.isValid(target.id)) {
106
+ if (!EntityId.isValid(target.id)) {
91
107
  throw new Error('Invalid object id format.');
92
108
  }
93
109
  } else {
94
- target.id = ObjectId.random();
110
+ target.id = EntityId.random();
95
111
  }
96
112
  };
97
113
 
@@ -99,7 +115,15 @@ const setIdOnTarget = (target: any) => {
99
115
  * Set metadata on object.
100
116
  */
101
117
  // TODO(dmaretskyi): Move to echo-schema.
102
- const initMeta = <T>(obj: T, meta: ObjectMeta = { keys: [] }) => {
103
- prepareTypedTarget(meta, ObjectMetaSchema);
104
- defineHiddenProperty(obj, MetaId, createProxy(meta, TypedReactiveHandler.instance as any));
118
+ const initMeta = <T>(obj: T, meta?: Partial<EntityMeta>) => {
119
+ // Backfill required fields so callers may pass a partial meta, or one whose `keys`/`tags`/
120
+ // `annotations` are explicitly `undefined` (coalesce, don't let a spread reintroduce undefined).
121
+ const fullMeta: EntityMeta = {
122
+ ...meta,
123
+ keys: meta?.keys ?? [],
124
+ tags: meta?.tags ?? [],
125
+ annotations: meta?.annotations ?? {},
126
+ };
127
+ prepareTypedTarget(fullMeta, EntityMetaSchema);
128
+ defineHiddenProperty(obj, MetaId, createProxy(fullMeta, TypedReactiveHandler.instance as any));
105
129
  };
@@ -221,12 +221,12 @@ export const getEchoRoot = (target: object, depth = 0): object => {
221
221
 
222
222
  // Root ECHO objects (those created with Obj.make or Relation.make) have KindId set.
223
223
  // They maintain their own change context identity even when nested inside another object.
224
- // Nested helper objects like ObjectMeta don't have KindId and should follow their owner.
224
+ // Nested helper objects like EntityMeta don't have KindId and should follow their owner.
225
225
  if (KindId in target) {
226
226
  return target;
227
227
  }
228
228
 
229
- // For non-root objects (nested records, ObjectMeta, etc.), follow the owner chain.
229
+ // For non-root objects (nested records, EntityMeta, etc.), follow the owner chain.
230
230
  const owner = getOwner(target);
231
231
  if (owner) {
232
232
  return getEchoRoot(owner, depth + 1);
@@ -34,7 +34,7 @@ const checkArrayMutationAllowed = (arr: any, method: string): void => {
34
34
 
35
35
  /**
36
36
  * Extends the native array to make sure that arrays methods are correctly reactive.
37
- * Enforces that mutations only happen within Obj.change() context.
37
+ * Enforces that mutations only happen within Obj.update() context.
38
38
  */
39
39
  export class ReactiveArray<T> extends Array<T> {
40
40
  static override get [Symbol.species]() {
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, expect, test } from 'vitest';
6
+
7
+ import * as Obj from '../../../Obj';
8
+ import { TestSchema } from '../../../testing';
9
+
10
+ describe('Obj.subscribe', () => {
11
+ test('subscribes and fires for reactive proxies', () => {
12
+ const obj = Obj.make(TestSchema.Person, { name: 'Test' });
13
+ let calls = 0;
14
+ const unsubscribe = Obj.subscribe(obj, () => {
15
+ calls++;
16
+ });
17
+
18
+ Obj.update(obj, (obj) => {
19
+ obj.name = 'Updated';
20
+ });
21
+ expect(calls).toBeGreaterThan(0);
22
+
23
+ unsubscribe();
24
+ const seen = calls;
25
+ Obj.update(obj, (obj) => {
26
+ obj.name = 'After unsubscribe';
27
+ });
28
+ expect(calls).toBe(seen);
29
+ });
30
+
31
+ // Regression: queue-stored typed objects (e.g. AiContext.Binding) and other Obj-shaped values
32
+ // satisfy `Obj.isObject` (KindId is set) but are not wrapped in a reactive Proxy. Earlier
33
+ // versions invariant'd inside `getProxyTarget` when an atom body did `Obj.subscribe(obj)` on
34
+ // such an input. The contract is "no-op for non-reactive inputs"; verify the function
35
+ // returns gracefully instead of throwing.
36
+ test('returns a no-op unsubscribe for non-proxy inputs', () => {
37
+ const queueShaped: any = {
38
+ id: '01KQ5NKXJWSKMRPVTVG2GHV8V3',
39
+ blueprints: { added: [], removed: [] },
40
+ objects: { added: [], removed: [] },
41
+ };
42
+ const unsubscribe = Obj.subscribe(queueShaped, () => {});
43
+ expect(typeof unsubscribe).toBe('function');
44
+ expect(() => unsubscribe()).not.toThrow();
45
+ });
46
+
47
+ test('returns a no-op unsubscribe for primitives, null, and undefined', () => {
48
+ for (const value of [null, undefined, 42, 'string', true]) {
49
+ const unsubscribe = Obj.subscribe(value as any, () => {});
50
+ expect(typeof unsubscribe).toBe('function');
51
+ expect(() => unsubscribe()).not.toThrow();
52
+ }
53
+ });
54
+ });
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { type RefTypeId } from '../../Ref/ref';
6
- import { getProxyTarget } from './proxy-utils';
6
+ import { getProxyTarget, isProxy } from './proxy-utils';
7
7
  import { ChangeId, EventId } from './symbols';
8
8
 
9
9
  /**
@@ -14,6 +14,15 @@ import { ChangeId, EventId } from './symbols';
14
14
  */
15
15
  // TODO(wittjosiah): Consider throwing if obj doesn't have EventId instead of returning no-op.
16
16
  export const subscribe = (obj: unknown, callback: () => void): (() => void) => {
17
+ // Guard against non-reactive inputs (queue-stored typed objects, snapshots, plain shapes
18
+ // with branded symbols) before `getProxyTarget`'s `ProxyHandlerSlot` invariant kicks in.
19
+ // `Obj.isObject` (KindId-based) is satisfied by these inputs, so callers like
20
+ // `Atom.family((obj) => Atom.make((get) => Obj.subscribe(obj, ...)))` legitimately reach
21
+ // here with a non-proxy. Falling back to a no-op preserves the documented contract that
22
+ // values without subscription support get a no-op unsubscribe.
23
+ if (!isProxy(obj)) {
24
+ return () => {};
25
+ }
17
26
  const target = getProxyTarget(obj as any);
18
27
  if (target && EventId in target) {
19
28
  return (target as any)[EventId].on(callback);
@@ -23,7 +32,7 @@ export const subscribe = (obj: unknown, callback: () => void): (() => void) => {
23
32
 
24
33
  /**
25
34
  * Deeply removes readonly modifiers from all properties of T.
26
- * Inside Obj.change, all properties are fully mutable regardless of schema definition.
35
+ * Inside Obj.update, all properties are fully mutable regardless of schema definition.
27
36
  * Ref types are preserved as-is since they are value-like objects that are replaced, not mutated.
28
37
  * Primitive types (including branded primitives) are preserved as-is.
29
38
  */
@@ -6,34 +6,43 @@ import * as Schema from 'effect/Schema';
6
6
  import * as SchemaAST from 'effect/SchemaAST';
7
7
  import { describe, expect, test } from 'vitest';
8
8
 
9
+ import { invariant } from '@dxos/invariant';
10
+ import { DXN } from '@dxos/keys';
11
+
9
12
  import { createEchoSchema } from '../../../testing';
13
+ import * as Type from '../../../Type';
10
14
  import { PropertyMeta, getPropertyMetaAnnotation, getTypeAnnotation } from '../../Annotation';
11
15
  import { EchoObjectSchema } from '../../Entity';
12
16
 
13
- // TODO(dmaretskyi): Comment.
14
- const EmptySchemaType = Schema.Struct({}).pipe(
15
- EchoObjectSchema({
16
- typename: 'com.example.type.empty',
17
- version: '0.1.0',
18
- }),
19
- );
17
+ // Test-local: introspect a Type.Type entity's properties via its rebuilt Effect
18
+ // Schema, filter the implicit `id` field, and unwrap `T | undefined` optionality.
19
+ const getProperties = (type: Type.Type): SchemaAST.PropertySignature[] => {
20
+ const ast = Type.getSchema(type).ast;
21
+ invariant(SchemaAST.isTypeLiteral(ast));
22
+ return [...ast.propertySignatures]
23
+ .filter((p) => p.name !== 'id')
24
+ .map((p) => {
25
+ if (!SchemaAST.isUnion(p.type)) {
26
+ return p;
27
+ }
28
+ const nonUndefined = p.type.types.find((t) => !SchemaAST.isUndefinedKeyword(t))!;
29
+ return { ...p, type: nonUndefined } as SchemaAST.PropertySignature;
30
+ });
31
+ };
32
+
33
+ const EmptySchemaType = Schema.Struct({}).pipe(EchoObjectSchema(DXN.make('com.example.type.empty', '0.1.0')));
20
34
 
21
- interface EmptySchemaType extends Schema.Schema.Type<typeof EmptySchemaType> {}
35
+ type EmptySchemaType = Type.InstanceType<typeof EmptySchemaType>;
22
36
 
23
37
  describe('dynamic schema', () => {
24
38
  test('getProperties filters out id and unwraps optionality', async () => {
25
39
  const TestSchema = Schema.Struct({
26
40
  field1: Schema.String,
27
41
  field2: Schema.Boolean,
28
- }).pipe(
29
- EchoObjectSchema({
30
- typename: 'com.example.type.test',
31
- version: '0.1.0',
32
- }),
33
- );
42
+ }).pipe(EchoObjectSchema(DXN.make('com.example.type.test', '0.1.0')));
34
43
 
35
- const registered = createEchoSchema(TestSchema);
36
- expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
44
+ const registered = createEchoSchema(Type.getSchema(TestSchema));
45
+ expect(getProperties(registered).map((p) => [p.name, p.type])).to.deep.eq([
37
46
  ['field1', SchemaAST.stringKeyword],
38
47
  ['field2', SchemaAST.booleanKeyword],
39
48
  ]);
@@ -42,28 +51,23 @@ describe('dynamic schema', () => {
42
51
  test('addColumns', async () => {
43
52
  const TestSchema = Schema.Struct({
44
53
  field1: Schema.String,
45
- }).pipe(
46
- EchoObjectSchema({
47
- typename: 'com.example.type.test',
48
- version: '0.1.0',
49
- }),
50
- );
54
+ }).pipe(EchoObjectSchema(DXN.make('com.example.type.test', '0.1.0')));
51
55
 
52
- const registered = createEchoSchema(TestSchema);
53
- registered.addFields({ field2: Schema.Boolean });
54
- expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
56
+ const registered = createEchoSchema(Type.getSchema(TestSchema));
57
+ Type.addFields(registered, { field2: Schema.Boolean });
58
+ expect(getProperties(registered).map((p) => [p.name, p.type])).to.deep.eq([
55
59
  ['field1', SchemaAST.stringKeyword],
56
60
  ['field2', SchemaAST.booleanKeyword],
57
61
  ]);
58
62
  });
59
63
 
60
64
  test('updateColumns preserves order of existing and appends new fields', async () => {
61
- const registered = createEchoSchema(EmptySchemaType);
62
- registered.addFields({ field1: Schema.String });
63
- registered.addFields({ field2: Schema.Boolean });
64
- registered.addFields({ field3: Schema.Number });
65
- registered.updateFields({ field4: Schema.Boolean, field2: Schema.String });
66
- expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
65
+ const registered = createEchoSchema(Type.getSchema(EmptySchemaType));
66
+ Type.addFields(registered, { field1: Schema.String });
67
+ Type.addFields(registered, { field2: Schema.Boolean });
68
+ Type.addFields(registered, { field3: Schema.Number });
69
+ Type.updateFields(registered, { field4: Schema.Boolean, field2: Schema.String });
70
+ expect(getProperties(registered).map((p) => [p.name, p.type])).to.deep.eq([
67
71
  ['field1', SchemaAST.stringKeyword],
68
72
  ['field2', SchemaAST.stringKeyword],
69
73
  ['field3', SchemaAST.numberKeyword],
@@ -72,12 +76,12 @@ describe('dynamic schema', () => {
72
76
  });
73
77
 
74
78
  test('removeColumns', async () => {
75
- const registered = createEchoSchema(EmptySchemaType);
76
- registered.addFields({ field1: Schema.String });
77
- registered.addFields({ field2: Schema.Boolean });
78
- registered.addFields({ field3: Schema.Number });
79
- registered.removeFields(['field2']);
80
- expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
79
+ const registered = createEchoSchema(Type.getSchema(EmptySchemaType));
80
+ Type.addFields(registered, { field1: Schema.String });
81
+ Type.addFields(registered, { field2: Schema.Boolean });
82
+ Type.addFields(registered, { field3: Schema.Number });
83
+ Type.removeFields(registered, ['field2']);
84
+ expect(getProperties(registered).map((p) => [p.name, p.type])).to.deep.eq([
81
85
  ['field1', SchemaAST.stringKeyword],
82
86
  ['field3', SchemaAST.numberKeyword],
83
87
  ]);
@@ -86,60 +90,18 @@ describe('dynamic schema', () => {
86
90
  test('schema manipulations preserve annotations', async () => {
87
91
  const metaNamespace = 'dxos.test';
88
92
  const metaInfo = { maxLength: 10 };
89
- const registered = createEchoSchema(EmptySchemaType);
90
- registered.addFields({
93
+ const registered = createEchoSchema(Type.getSchema(EmptySchemaType));
94
+ Type.addFields(registered, {
91
95
  field1: Schema.String.pipe(PropertyMeta(metaNamespace, metaInfo)),
92
96
  field2: Schema.String,
93
97
  });
94
- registered.addFields({ field3: Schema.String });
95
- registered.updateFields({ field3: Schema.Boolean });
96
- registered.removeFields(['field2']);
97
- expect(getTypeAnnotation(registered)).to.deep.contain({
98
+ Type.addFields(registered, { field3: Schema.String });
99
+ Type.updateFields(registered, { field3: Schema.Boolean });
100
+ Type.removeFields(registered, ['field2']);
101
+ expect(getTypeAnnotation(Type.getSchema(registered))).to.deep.contain({
98
102
  typename: 'com.example.type.empty',
99
103
  version: '0.1.0',
100
104
  });
101
- expect(getPropertyMetaAnnotation(registered.getProperties()[0], metaNamespace)).to.deep.eq(metaInfo);
102
- });
103
-
104
- test('updates typename', async ({ expect }) => {
105
- // Create schema with some fields and annotations.
106
- const registered = createEchoSchema(EmptySchemaType);
107
- const originalVersion = registered.persistentSchema.version;
108
- registered.addFields({
109
- name: Schema.String.pipe(PropertyMeta('test', { maxLength: 10 })),
110
- age: Schema.Number,
111
- });
112
-
113
- // First update.
114
- const newTypename1 = 'com.example.type.individual';
115
- registered.updateTypename(newTypename1);
116
-
117
- // Basic typename update checks.
118
- expect(registered.typename).toBe(newTypename1);
119
- expect(registered.jsonSchema.$id).toBe(`dxn:type:${newTypename1}`);
120
- expect(registered.jsonSchema.typename).toBe(newTypename1);
121
-
122
- // Version preservation check.
123
- expect(registered.persistentSchema.version).toBe(originalVersion);
124
-
125
- // Field preservation check.
126
- const properties = registered.getProperties();
127
- expect(properties).toHaveLength(2);
128
- expect(properties[0].name).toBe('name');
129
-
130
- // Annotation preservation check.
131
- const nameMeta = getPropertyMetaAnnotation(properties[0], 'test');
132
- expect(nameMeta).toEqual({ maxLength: 10 });
133
-
134
- // Second update to ensure multiple updates work.
135
- const newTypename2 = 'com.example.type.person';
136
- registered.updateTypename(newTypename2);
137
- expect(registered.typename).toBe(newTypename2);
138
- expect(registered.jsonSchema.$id).toBe(`dxn:type:${newTypename2}`);
139
- expect(registered.jsonSchema.typename).toBe(newTypename2);
140
- expect(getTypeAnnotation(registered)).to.deep.contain({
141
- typename: 'com.example.type.person',
142
- version: '0.1.0',
143
- });
105
+ expect(getPropertyMetaAnnotation(getProperties(registered)[0], metaNamespace)).to.deep.eq(metaInfo);
144
106
  });
145
107
  });
@@ -5,11 +5,14 @@
5
5
  import * as Schema from 'effect/Schema';
6
6
  import { describe, expect, test } from 'vitest';
7
7
 
8
+ import { DXN } from '@dxos/keys';
9
+
10
+ import * as Obj from '../../../Obj';
8
11
  import { TestSchema } from '../../../testing';
9
12
  import { EchoObjectSchema } from '../../Entity';
10
13
  import { setValue } from '../../Obj';
11
14
  import { Ref } from '../../Ref';
12
- import { foreignKey, getMeta } from '../types';
15
+ import { foreignKey, getMeta } from '../types/meta';
13
16
  import { makeObject } from './make-object';
14
17
  import { change, subscribe } from './reactive';
15
18
 
@@ -39,15 +42,13 @@ describe('complex schema validations', () => {
39
42
 
40
43
  test('references', () => {
41
44
  const Foo = Schema.Struct({ field: Schema.String }).pipe(
42
- EchoObjectSchema({ typename: 'com.example.type.foo', version: '0.1.0' }),
43
- );
44
- const Bar = Schema.Struct({ fooRef: Ref(Foo) }).pipe(
45
- EchoObjectSchema({ typename: 'com.example.type.bar', version: '0.1.0' }),
45
+ EchoObjectSchema(DXN.make('com.example.type.foo', '0.1.0')),
46
46
  );
47
+ const Bar = Schema.Struct({ fooRef: Ref(Foo) }).pipe(EchoObjectSchema(DXN.make('com.example.type.bar', '0.1.0')));
47
48
  const field = 'hello';
48
- expect(() => makeObject(Bar, { fooRef: { id: '1', field } as any })).to.throw();
49
- expect(() => makeObject(Bar, { fooRef: undefined as any })).to.throw(); // Unresolved reference.
50
- const bar = makeObject(Bar, { fooRef: Ref.make(makeObject(Foo, { field })) });
49
+ expect(() => Obj.make(Bar, { fooRef: { id: '1', field } as any })).to.throw();
50
+ expect(() => Obj.make(Bar, { fooRef: undefined as any })).to.throw(); // Unresolved reference.
51
+ const bar = Obj.make(Bar, { fooRef: Ref.make(Obj.make(Foo, { field })) });
51
52
  expect(bar.fooRef.target?.field).to.eq(field);
52
53
  });
53
54
 
@@ -79,7 +80,7 @@ describe('complex schema validations', () => {
79
80
  // Untyped reactive objects are no longer supported - use Atoms for untyped reactive state.
80
81
 
81
82
  test('creating an object with data from another object', () => {
82
- const contact = makeObject(TestSchema.Person, {
83
+ const contact = Obj.make(TestSchema.Person, {
83
84
  name: 'Robert Smith',
84
85
  email: 'robert@example.com',
85
86
  });
@@ -94,9 +95,9 @@ describe('complex schema validations', () => {
94
95
 
95
96
  test('subscribe', () => {
96
97
  const TestSchema = Schema.Struct({ field: Schema.String }).pipe(
97
- EchoObjectSchema({ typename: 'Test', version: '0.1.0' }),
98
+ EchoObjectSchema(DXN.make('com.test.type.test', '0.1.0')),
98
99
  );
99
- const object = makeObject(TestSchema, { field: 'value' });
100
+ const object = Obj.make(TestSchema, { field: 'value' });
100
101
  let called = 0;
101
102
  const unsubscribe = subscribe(object as any, () => {
102
103
  called++;
@@ -8,10 +8,11 @@ import { type InspectOptionsStylized } from 'node:util';
8
8
 
9
9
  import { Event } from '@dxos/async';
10
10
  import { inspectCustom } from '@dxos/debug';
11
- import { invariant } from '@dxos/invariant';
11
+ import { assertArgument, invariant } from '@dxos/invariant';
12
12
 
13
- import { getSchemaDXN } from '../../Annotation';
14
- import { ObjectDeletedId, ParentId, SchemaId, TypeId } from '../types';
13
+ import { getSchemaURI } from '../../Annotation/annotations';
14
+ import { toEffectSchema } from '../../JsonSchema/json-schema';
15
+ import { ObjectDeletedId, ParentId, SchemaId, StaticTypeSchemaSlot, TypeEntityId, TypeId } from '../types';
15
16
  import { executeChange, isInChangeContext, queueNotification } from './change-context';
16
17
  import { defineHiddenProperty } from './define-hidden-property';
17
18
  import { createPropertyDeleteError } from './errors';
@@ -142,7 +143,7 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
142
143
  private constructor() {}
143
144
 
144
145
  init(target: ProxyTarget): void {
145
- invariant(typeof target === 'object' && target !== null);
146
+ assertArgument(typeof target === 'object' && target !== null, 'target');
146
147
  invariant(SchemaId in target, 'Schema is not defined for the target');
147
148
 
148
149
  // Only set EventId on root objects (those without an owner).
@@ -208,6 +209,27 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
208
209
  // Uses target as both the context key and event target for non-database objects.
209
210
  return (callback: (obj: any) => void) => executeChange(target, target, receiver, callback);
210
211
  }
212
+ case TypeEntityId: {
213
+ // The back-reference to the type entity is metadata — return the raw
214
+ // value so we don't re-wrap an already-reactive `Type.Type` entity in
215
+ // another proxy (which would fail the SchemaId-in-target invariant).
216
+ return Reflect.get(target, prop, receiver);
217
+ }
218
+ case StaticTypeSchemaSlot: {
219
+ // Lazily rebuild the source Effect Schema from `jsonSchema` and cache it on
220
+ // the slot; the set-trap invalidates the cache when `jsonSchema` is mutated.
221
+ const existing = Reflect.get(target, prop, receiver);
222
+ if (existing !== undefined) {
223
+ return existing;
224
+ }
225
+ const jsonSchema = (target as any).jsonSchema;
226
+ if (jsonSchema == null) {
227
+ return undefined;
228
+ }
229
+ const rebuilt = toEffectSchema(jsonSchema);
230
+ defineHiddenProperty(target, StaticTypeSchemaSlot, rebuilt);
231
+ return rebuilt;
232
+ }
211
233
  }
212
234
 
213
235
  // Handle getter properties.
@@ -226,7 +248,7 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
226
248
  set(target: ProxyTarget, prop: string | symbol, value: any, receiver: any): boolean {
227
249
  const echoRoot = getEchoRoot(target);
228
250
 
229
- // Check readonly enforcement - mutations only allowed within Obj.change().
251
+ // Check readonly enforcement - mutations only allowed within Obj.update().
230
252
  // Skip check if the object is still being initialized (no ChangeId handler yet).
231
253
  // Also skip for non-initialized root objects (those without EventId).
232
254
  // Skip for symbol properties (internal infrastructure, not user data).
@@ -234,8 +256,8 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
234
256
  const isSymbolProp = typeof prop === 'symbol';
235
257
  if (isInitialized && !isSymbolProp && !isInChangeContext(echoRoot)) {
236
258
  throw new Error(
237
- `Cannot modify object property "${String(prop)}" outside of Obj.change(). ` +
238
- 'Use Obj.change(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
259
+ `Cannot modify object property "${String(prop)}" outside of Obj.update(). ` +
260
+ 'Use Obj.update(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
239
261
  );
240
262
  }
241
263
 
@@ -245,6 +267,11 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
245
267
  batchEvents(() => {
246
268
  const { echoRoot: _, preparedValue } = this._prepareValueForAssignment(target, prop, value);
247
269
  result = Reflect.set(target, prop, preparedValue, receiver);
270
+ // Invalidate the cached source Effect Schema when `jsonSchema` changes
271
+ // (e.g. `Type.addFields`) so `Type.getSchema` rebuilds from the new shape.
272
+ if (prop === 'jsonSchema') {
273
+ Reflect.deleteProperty(target, StaticTypeSchemaSlot);
274
+ }
248
275
  // Queue notification instead of emitting immediately (batched).
249
276
  if (isInitialized) {
250
277
  queueNotification(echoRoot);
@@ -265,7 +292,7 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
265
292
  deleteProperty(target: ProxyTarget, property: string | symbol): boolean {
266
293
  const echoRoot = getEchoRoot(target);
267
294
 
268
- // Check readonly enforcement - mutations only allowed within Obj.change().
295
+ // Check readonly enforcement - mutations only allowed within Obj.update().
269
296
  // Skip for symbol properties (internal infrastructure, not user data).
270
297
  const isInitialized = (echoRoot as any)[ChangeId] === true || EventId in echoRoot;
271
298
  const isSymbolProp = typeof property === 'symbol';
@@ -283,15 +310,15 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
283
310
  defineProperty(target: ProxyTarget, property: string | symbol, attributes: PropertyDescriptor): boolean {
284
311
  const echoRoot = getEchoRoot(target);
285
312
 
286
- // Check readonly enforcement - mutations only allowed within Obj.change().
313
+ // Check readonly enforcement - mutations only allowed within Obj.update().
287
314
  // Skip check if the object is still being initialized (no ChangeId handler yet).
288
315
  // Skip for symbol properties (internal infrastructure, not user data).
289
316
  const isInitialized = ChangeId in echoRoot || EventId in echoRoot;
290
317
  const isSymbolProp = typeof property === 'symbol';
291
318
  if (isInitialized && !isSymbolProp && !isInChangeContext(echoRoot)) {
292
319
  throw new Error(
293
- `Cannot modify object property "${String(property)}" outside of Obj.change(). ` +
294
- 'Use Obj.change(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
320
+ `Cannot modify object property "${String(property)}" outside of Obj.update(). ` +
321
+ 'Use Obj.update(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
295
322
  );
296
323
  }
297
324
 
@@ -400,16 +427,49 @@ const toJSON = (target: ProxyTarget): any => {
400
427
  return { '@type': 'TypedReactiveObject', ...target };
401
428
  };
402
429
 
430
+ /**
431
+ * Pointer to a `Type.Type` entity, stamped as the back-reference (`TypeEntityId`)
432
+ * on instances and read by the `SchemaId` getter installed below.
433
+ *
434
+ * Structural shape (not `Type.AnyEntity`) because `internal/common/proxy/`
435
+ * can't import the top-level `Type` module without a cycle. Every kind of
436
+ * `Type.Type` entity satisfies this shape:
437
+ * - Static (`Type.makeObject(dxn)` pipe) — slot set directly on the object.
438
+ * - Persisted (echo-handler-wrapped) — slot exposed via that handler's
439
+ * `get` trap (rebuilds from `data.jsonSchema`).
440
+ * - In-memory pre-persist (`Type.makeObjectFromJsonSchema`) — slot exposed
441
+ * via the `case StaticTypeSchemaSlot:` arm in this file's `get` trap.
442
+ */
443
+ export type TypeSource = { readonly [StaticTypeSchemaSlot]?: Schema.Schema.AnyNoContext };
444
+
403
445
  /**
404
446
  * Recursively set AST on all potential proxy targets.
405
447
  */
406
- const setSchemaProperties = (obj: any, schema: Schema.Schema.AnyNoContext) => {
407
- const schemaType = getSchemaDXN(schema);
448
+ const setSchemaProperties = (obj: any, schema: Schema.Schema.AnyNoContext, typeSource?: TypeSource) => {
449
+ const schemaType = getSchemaURI(schema);
408
450
  if (schemaType != null) {
409
451
  defineHiddenProperty(obj, TypeId, schemaType);
410
452
  }
411
453
 
412
- defineHiddenProperty(obj, SchemaId, schema);
454
+ if (typeSource != null) {
455
+ // Keep a back-reference to the type entity so `Obj.getType` /
456
+ // `Relation.getType` / `Entity.getType` can return it.
457
+ defineHiddenProperty(obj, TypeEntityId, typeSource);
458
+
459
+ // Install `SchemaId` as a getter that reads through the entity's static
460
+ // schema slot. The three entity shapes (static / persisted / in-memory
461
+ // pre-persist) each populate the slot via their own get-trap path, so
462
+ // `Type.update` / `Type.addFields` mutations propagate into validation
463
+ // for objects created via `Obj.make(typeEntity, ...)` without this file
464
+ // having to rebuild from `jsonSchema` itself.
465
+ Object.defineProperty(obj, SchemaId, {
466
+ get: () => typeSource[StaticTypeSchemaSlot] ?? schema,
467
+ enumerable: false,
468
+ configurable: true,
469
+ });
470
+ } else {
471
+ defineHiddenProperty(obj, SchemaId, schema);
472
+ }
413
473
  for (const key in obj) {
414
474
  if (isValidProxyTarget(obj[key])) {
415
475
  const elementSchema = SchemaValidator.getTargetPropertySchema(obj, key);
@@ -420,7 +480,9 @@ const setSchemaProperties = (obj: any, schema: Schema.Schema.AnyNoContext) => {
420
480
  }
421
481
  };
422
482
 
423
- export const prepareTypedTarget = <T>(target: T, schema: Schema.Schema<T>) => {
483
+ // Accepts any encoded type: the typed handler operates on the decoded representation, so schemas
484
+ // whose encoded form differs (e.g. refs encode as `{ '/': uri }`) are valid here.
485
+ export const prepareTypedTarget = <T>(target: T, schema: Schema.Schema<T, any>, typeSource?: TypeSource) => {
424
486
  // log.info('prepareTypedTarget', { target, schema });
425
487
  if (!SchemaAST.isTypeLiteral(schema.ast)) {
426
488
  throw new Error('schema has to describe an object type');
@@ -429,7 +491,7 @@ export const prepareTypedTarget = <T>(target: T, schema: Schema.Schema<T>) => {
429
491
  SchemaValidator.validateSchema(schema);
430
492
  const _ = Schema.asserts(schema)(target);
431
493
  makeArraysReactive(target);
432
- setSchemaProperties(target, schema);
494
+ setSchemaProperties(target, schema, typeSource);
433
495
  };
434
496
 
435
497
  const makeArraysReactive = (target: any) => {