@dxos/echo 0.8.4-staging.ac66bdf99f → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +7 -7
  3. package/dist/lib/neutral/Annotation.mjs +37 -6
  4. package/dist/lib/neutral/Database.mjs +6 -17
  5. package/dist/lib/neutral/Entity.mjs +31 -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 +29 -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-3PBP4V4O.mjs +101 -0
  26. package/dist/lib/neutral/chunk-3PBP4V4O.mjs.map +7 -0
  27. package/dist/lib/neutral/chunk-4ZUHOTCG.mjs +184 -0
  28. package/dist/lib/neutral/chunk-4ZUHOTCG.mjs.map +7 -0
  29. package/dist/lib/neutral/chunk-5SMDBFVB.mjs +108 -0
  30. package/dist/lib/neutral/chunk-5SMDBFVB.mjs.map +7 -0
  31. package/dist/lib/neutral/{chunk-OS35K56T.mjs → chunk-5SUJPHAE.mjs} +3 -3
  32. package/dist/lib/neutral/{chunk-OS35K56T.mjs.map → chunk-5SUJPHAE.mjs.map} +2 -2
  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-V36VO5SS.mjs → chunk-6YDI3J37.mjs} +32 -40
  36. package/dist/lib/neutral/chunk-6YDI3J37.mjs.map +7 -0
  37. package/dist/lib/neutral/{chunk-MOR5ERFM.mjs → chunk-7FPIAJIV.mjs} +701 -1256
  38. package/dist/lib/neutral/chunk-7FPIAJIV.mjs.map +7 -0
  39. package/dist/lib/neutral/{chunk-ANHVGJI4.mjs → chunk-7LOUAPYZ.mjs} +9 -5
  40. package/dist/lib/neutral/chunk-7LOUAPYZ.mjs.map +7 -0
  41. package/dist/lib/neutral/{chunk-JUXPFOEI.mjs → chunk-7PI7C4EF.mjs} +48 -88
  42. package/dist/lib/neutral/chunk-7PI7C4EF.mjs.map +7 -0
  43. package/dist/lib/neutral/{chunk-UBEZSGXY.mjs → chunk-BBFJWWAV.mjs} +6 -6
  44. package/dist/lib/neutral/chunk-BBFJWWAV.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-7RO7CPBZ.mjs → chunk-IGK6FN65.mjs} +2 -2
  48. package/dist/lib/neutral/{chunk-HBUZJNZO.mjs → chunk-LWXVKPPW.mjs} +94 -99
  49. package/dist/lib/neutral/chunk-LWXVKPPW.mjs.map +7 -0
  50. package/dist/lib/neutral/{chunk-BVOFLCVF.mjs → chunk-MZ7K3MLL.mjs} +9 -6
  51. package/dist/lib/neutral/chunk-MZ7K3MLL.mjs.map +7 -0
  52. package/dist/lib/neutral/{chunk-TBKX6JQO.mjs → chunk-O6BH7EPN.mjs} +30 -3
  53. package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +7 -0
  54. package/dist/lib/neutral/{chunk-EAMSSLZC.mjs → chunk-QQIYS74I.mjs} +83 -46
  55. package/dist/lib/neutral/chunk-QQIYS74I.mjs.map +7 -0
  56. package/dist/lib/neutral/chunk-R5W6DXR4.mjs +678 -0
  57. package/dist/lib/neutral/chunk-R5W6DXR4.mjs.map +7 -0
  58. package/dist/lib/neutral/{chunk-WAK4DMFV.mjs → chunk-RIVWNMSF.mjs} +12 -7
  59. package/dist/lib/neutral/chunk-RIVWNMSF.mjs.map +7 -0
  60. package/dist/lib/neutral/{chunk-T6W2LEZU.mjs → chunk-SBVFRTST.mjs} +73 -38
  61. package/dist/lib/neutral/chunk-SBVFRTST.mjs.map +7 -0
  62. package/dist/lib/neutral/chunk-T6E37YIP.mjs +251 -0
  63. package/dist/lib/neutral/chunk-T6E37YIP.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-B4BASU6W.mjs → chunk-TYGKCRMK.mjs} +85 -76
  67. package/dist/lib/neutral/chunk-TYGKCRMK.mjs.map +7 -0
  68. package/dist/lib/neutral/{chunk-4OIBYSXE.mjs → chunk-UUP46KUQ.mjs} +78 -32
  69. package/dist/lib/neutral/chunk-UUP46KUQ.mjs.map +7 -0
  70. package/dist/lib/neutral/chunk-WISOH2XH.mjs +36 -0
  71. package/dist/lib/neutral/chunk-WISOH2XH.mjs.map +7 -0
  72. package/dist/lib/neutral/{chunk-G3IQMKF7.mjs → chunk-WTQJHC75.mjs} +111 -112
  73. package/dist/lib/neutral/chunk-WTQJHC75.mjs.map +7 -0
  74. package/dist/lib/neutral/chunk-WU3GIANS.mjs +31 -0
  75. package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +7 -0
  76. package/dist/lib/neutral/{chunk-TU3GW67D.mjs → chunk-ZGNNFYHS.mjs} +40 -40
  77. package/dist/lib/neutral/chunk-ZGNNFYHS.mjs.map +7 -0
  78. package/dist/lib/neutral/index.mjs +47 -41
  79. package/dist/lib/neutral/internal/index.mjs +137 -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 +56 -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 +101 -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 +66 -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 +104 -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 +362 -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 +79 -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 +38 -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/ref-array.d.ts +2 -2
  207. package/dist/types/src/internal/Ref/ref.d.ts +50 -19
  208. package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
  209. package/dist/types/src/internal/Ref/utils.d.ts +8 -0
  210. package/dist/types/src/internal/Ref/utils.d.ts.map +1 -0
  211. package/dist/types/src/internal/Type/compose.d.ts.map +1 -1
  212. package/dist/types/src/internal/Type/index.d.ts +1 -2
  213. package/dist/types/src/internal/Type/index.d.ts.map +1 -1
  214. package/dist/types/src/internal/Type/manipulation.d.ts +0 -1
  215. package/dist/types/src/internal/Type/manipulation.d.ts.map +1 -1
  216. package/dist/types/src/internal/Type/type-schema.d.ts +52 -0
  217. package/dist/types/src/internal/Type/type-schema.d.ts.map +1 -0
  218. package/dist/types/src/internal/common/api/meta.d.ts +14 -11
  219. package/dist/types/src/internal/common/api/meta.d.ts.map +1 -1
  220. package/dist/types/src/internal/common/proxy/change-context.d.ts +1 -1
  221. package/dist/types/src/internal/common/proxy/change-context.d.ts.map +1 -1
  222. package/dist/types/src/internal/common/proxy/define-hidden-property.d.ts.map +1 -1
  223. package/dist/types/src/internal/common/proxy/errors.d.ts +1 -1
  224. package/dist/types/src/internal/common/proxy/errors.d.ts.map +1 -1
  225. package/dist/types/src/internal/common/proxy/event-batch.d.ts.map +1 -1
  226. package/dist/types/src/internal/common/proxy/json-serializer.d.ts.map +1 -1
  227. package/dist/types/src/internal/common/proxy/make-object.d.ts +11 -5
  228. package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
  229. package/dist/types/src/internal/common/proxy/ownership.d.ts.map +1 -1
  230. package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
  231. package/dist/types/src/internal/common/proxy/reactive-array.d.ts +1 -1
  232. package/dist/types/src/internal/common/proxy/reactive.d.ts +1 -1
  233. package/dist/types/src/internal/common/proxy/reactive.d.ts.map +1 -1
  234. package/dist/types/src/internal/common/proxy/reactive.test.d.ts +2 -0
  235. package/dist/types/src/internal/common/proxy/reactive.test.d.ts.map +1 -0
  236. package/dist/types/src/internal/common/proxy/schema-validator.d.ts.map +1 -1
  237. package/dist/types/src/internal/common/proxy/typed-handler.d.ts +18 -2
  238. package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
  239. package/dist/types/src/internal/common/types/base.d.ts +4 -4
  240. package/dist/types/src/internal/common/types/base.d.ts.map +1 -1
  241. package/dist/types/src/internal/common/types/entity.d.ts +62 -5
  242. package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
  243. package/dist/types/src/internal/common/types/index.d.ts +1 -1
  244. package/dist/types/src/internal/common/types/index.d.ts.map +1 -1
  245. package/dist/types/src/internal/common/types/meta.d.ts +33 -12
  246. package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
  247. package/dist/types/src/internal/common/types/model-symbols.d.ts +15 -4
  248. package/dist/types/src/internal/common/types/model-symbols.d.ts.map +1 -1
  249. package/dist/types/src/internal/common/types/typename.d.ts +7 -0
  250. package/dist/types/src/internal/common/types/typename.d.ts.map +1 -1
  251. package/dist/types/src/internal/common/types/version.d.ts +1 -1
  252. package/dist/types/src/internal/common/types/well-known-types.d.ts +11 -0
  253. package/dist/types/src/internal/common/types/well-known-types.d.ts.map +1 -0
  254. package/dist/types/src/internal/index.d.ts +2 -2
  255. package/dist/types/src/internal/index.d.ts.map +1 -1
  256. package/dist/types/src/testing/index.d.ts +1 -0
  257. package/dist/types/src/testing/index.d.ts.map +1 -1
  258. package/dist/types/src/testing/registry.d.ts +9 -0
  259. package/dist/types/src/testing/registry.d.ts.map +1 -0
  260. package/dist/types/src/testing/test-data.d.ts +8 -8
  261. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  262. package/dist/types/src/testing/test-schema.d.ts +83 -89
  263. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  264. package/dist/types/src/testing/util.d.ts +5 -3
  265. package/dist/types/src/testing/util.d.ts.map +1 -1
  266. package/dist/types/tsconfig.tsbuildinfo +1 -1
  267. package/package.json +26 -24
  268. package/src/Annotation.test.ts +439 -0
  269. package/src/Annotation.ts +158 -4
  270. package/src/Collection.ts +5 -9
  271. package/src/Database.ts +93 -100
  272. package/src/Dataset.ts +10 -2
  273. package/src/Entity.test.ts +116 -6
  274. package/src/Entity.ts +134 -32
  275. package/src/Err.ts +4 -4
  276. package/src/Feed.ts +92 -44
  277. package/src/Filter.ts +70 -40
  278. package/src/Format.ts +0 -4
  279. package/src/Hypergraph.ts +14 -9
  280. package/src/Json.test.ts +175 -0
  281. package/src/Json.ts +103 -0
  282. package/src/Key.ts +1 -1
  283. package/src/Migration.ts +39 -19
  284. package/src/Obj.test.ts +122 -20
  285. package/src/Obj.ts +168 -91
  286. package/src/Order.ts +22 -0
  287. package/src/Query.test.ts +183 -154
  288. package/src/Query.ts +172 -85
  289. package/src/QueryResult.ts +26 -0
  290. package/src/Ref.ts +22 -4
  291. package/src/Registry.ts +155 -0
  292. package/src/Relation.test.ts +10 -10
  293. package/src/Relation.ts +116 -69
  294. package/src/Scope.ts +50 -0
  295. package/src/Tag.md +88 -0
  296. package/src/Tag.ts +49 -6
  297. package/src/Type.test.ts +223 -18
  298. package/src/Type.ts +609 -131
  299. package/src/View.ts +14 -23
  300. package/src/exemplars.test.ts +21 -0
  301. package/src/index.ts +4 -4
  302. package/src/internal/Annotation/annotations.test.ts +31 -11
  303. package/src/internal/Annotation/annotations.ts +143 -111
  304. package/src/internal/Annotation/dictionary.ts +47 -0
  305. package/src/internal/Annotation/entity-dictionary.ts +74 -0
  306. package/src/internal/Annotation/index.ts +4 -2
  307. package/src/internal/Annotation/util.ts +17 -8
  308. package/src/internal/Entity/api.ts +54 -7
  309. package/src/internal/Entity/entity.ts +196 -47
  310. package/src/internal/Entity/guard.ts +26 -0
  311. package/src/internal/Entity/index.ts +2 -0
  312. package/src/internal/Entity/model.ts +38 -28
  313. package/src/internal/Entity/object.ts +21 -5
  314. package/src/internal/Entity/relation.ts +68 -34
  315. package/src/internal/Entity/type-kind.ts +75 -0
  316. package/src/internal/Entity/type-uri.ts +92 -0
  317. package/src/internal/Entity/util.ts +9 -9
  318. package/src/internal/Format/date.ts +0 -4
  319. package/src/internal/Format/format.test.ts +21 -0
  320. package/src/internal/Format/index.ts +2 -3
  321. package/src/internal/Format/object.ts +21 -4
  322. package/src/internal/Format/types.ts +1 -1
  323. package/src/internal/JsonSchema/annotations.ts +1 -1
  324. package/src/internal/JsonSchema/json-schema-type.ts +4 -4
  325. package/src/internal/JsonSchema/json-schema.test.ts +71 -145
  326. package/src/internal/JsonSchema/json-schema.ts +49 -35
  327. package/src/internal/Obj/atoms.ts +244 -0
  328. package/src/internal/Obj/clone.ts +9 -4
  329. package/src/internal/Obj/create-object.test.ts +12 -10
  330. package/src/internal/Obj/create-object.ts +68 -22
  331. package/src/internal/Obj/index.ts +1 -1
  332. package/src/internal/Obj/inspect.ts +5 -3
  333. package/src/internal/Obj/json-serializer.test.ts +101 -22
  334. package/src/internal/Obj/json-serializer.ts +89 -33
  335. package/src/internal/Obj/set-value.test.ts +22 -45
  336. package/src/internal/Obj/set-value.ts +12 -19
  337. package/src/internal/Obj/snapshot.ts +13 -4
  338. package/src/internal/Obj/typed-object.test.ts +9 -11
  339. package/src/internal/Obj/typed-object.ts +1 -1
  340. package/src/internal/Query/index.ts +5 -0
  341. package/src/internal/{Query.ts → Query/pretty.ts} +40 -12
  342. package/src/internal/Ref/atoms.ts +20 -0
  343. package/src/internal/Ref/ref-array.ts +3 -3
  344. package/src/internal/Ref/ref.test.ts +18 -27
  345. package/src/internal/Ref/ref.ts +137 -59
  346. package/src/internal/Ref/utils.ts +45 -0
  347. package/src/internal/Type/compose.test.ts +3 -1
  348. package/src/internal/Type/index.ts +1 -2
  349. package/src/internal/Type/manipulation.ts +0 -25
  350. package/src/internal/Type/type-schema.ts +60 -0
  351. package/src/internal/common/README.md +2 -2
  352. package/src/internal/common/api/meta.ts +19 -17
  353. package/src/internal/common/proxy/change-context.ts +1 -1
  354. package/src/internal/common/proxy/change.test.ts +91 -83
  355. package/src/internal/common/proxy/errors.ts +2 -2
  356. package/src/internal/common/proxy/handler.test.ts +1 -1
  357. package/src/internal/common/proxy/json-serializer.ts +27 -16
  358. package/src/internal/common/proxy/make-object.ts +44 -20
  359. package/src/internal/common/proxy/ownership.ts +2 -2
  360. package/src/internal/common/proxy/reactive-array.ts +1 -1
  361. package/src/internal/common/proxy/reactive.test.ts +54 -0
  362. package/src/internal/common/proxy/reactive.ts +11 -2
  363. package/src/internal/common/proxy/schema.test.ts +48 -86
  364. package/src/internal/common/proxy/typed-handler.test.ts +12 -11
  365. package/src/internal/common/proxy/typed-handler.ts +78 -16
  366. package/src/internal/common/proxy/typed-object.test.ts +16 -28
  367. package/src/internal/common/types/base.ts +4 -4
  368. package/src/internal/common/types/entity.ts +80 -1
  369. package/src/internal/common/types/index.ts +6 -1
  370. package/src/internal/common/types/meta.ts +62 -20
  371. package/src/internal/common/types/model-symbols.ts +24 -4
  372. package/src/internal/common/types/typename.ts +39 -3
  373. package/src/internal/common/types/well-known-types.ts +15 -0
  374. package/src/internal/index.ts +6 -4
  375. package/src/testing/api.test.ts +15 -9
  376. package/src/testing/index.ts +1 -0
  377. package/src/testing/registry.ts +44 -0
  378. package/src/testing/test-data.ts +159 -99
  379. package/src/testing/test-schema.ts +22 -58
  380. package/src/testing/util.ts +14 -11
  381. package/dist/lib/neutral/Extension.mjs +0 -18
  382. package/dist/lib/neutral/SchemaRegistry.mjs +0 -2
  383. package/dist/lib/neutral/chunk-2KHZ36F5.mjs +0 -361
  384. package/dist/lib/neutral/chunk-2KHZ36F5.mjs.map +0 -7
  385. package/dist/lib/neutral/chunk-4OIBYSXE.mjs.map +0 -7
  386. package/dist/lib/neutral/chunk-4P3IXBLT.mjs +0 -45
  387. package/dist/lib/neutral/chunk-4P3IXBLT.mjs.map +0 -7
  388. package/dist/lib/neutral/chunk-ANHVGJI4.mjs.map +0 -7
  389. package/dist/lib/neutral/chunk-B4BASU6W.mjs.map +0 -7
  390. package/dist/lib/neutral/chunk-BNCCGLJN.mjs +0 -7
  391. package/dist/lib/neutral/chunk-BNCCGLJN.mjs.map +0 -7
  392. package/dist/lib/neutral/chunk-BVOFLCVF.mjs.map +0 -7
  393. package/dist/lib/neutral/chunk-DQYLD2RB.mjs.map +0 -7
  394. package/dist/lib/neutral/chunk-EAMSSLZC.mjs.map +0 -7
  395. package/dist/lib/neutral/chunk-G3IQMKF7.mjs.map +0 -7
  396. package/dist/lib/neutral/chunk-GZQTCRJB.mjs.map +0 -7
  397. package/dist/lib/neutral/chunk-HBUZJNZO.mjs.map +0 -7
  398. package/dist/lib/neutral/chunk-JUXPFOEI.mjs.map +0 -7
  399. package/dist/lib/neutral/chunk-MOR5ERFM.mjs.map +0 -7
  400. package/dist/lib/neutral/chunk-OMUPQMLR.mjs.map +0 -7
  401. package/dist/lib/neutral/chunk-PHU22NLC.mjs +0 -136
  402. package/dist/lib/neutral/chunk-PHU22NLC.mjs.map +0 -7
  403. package/dist/lib/neutral/chunk-ROG4RXXL.mjs +0 -97
  404. package/dist/lib/neutral/chunk-ROG4RXXL.mjs.map +0 -7
  405. package/dist/lib/neutral/chunk-T6W2LEZU.mjs.map +0 -7
  406. package/dist/lib/neutral/chunk-TBKX6JQO.mjs.map +0 -7
  407. package/dist/lib/neutral/chunk-TU3GW67D.mjs.map +0 -7
  408. package/dist/lib/neutral/chunk-UBEZSGXY.mjs.map +0 -7
  409. package/dist/lib/neutral/chunk-UI6MWK5W.mjs.map +0 -7
  410. package/dist/lib/neutral/chunk-V36VO5SS.mjs.map +0 -7
  411. package/dist/lib/neutral/chunk-WAK4DMFV.mjs.map +0 -7
  412. package/dist/lib/neutral/chunk-YAHXAYOW.mjs +0 -56
  413. package/dist/lib/neutral/chunk-YAHXAYOW.mjs.map +0 -7
  414. package/dist/lib/neutral/chunk-YS6Q3XAD.mjs +0 -50
  415. package/dist/lib/neutral/chunk-YS6Q3XAD.mjs.map +0 -7
  416. package/dist/types/src/Extension.d.ts +0 -80
  417. package/dist/types/src/Extension.d.ts.map +0 -1
  418. package/dist/types/src/Extension.test.d.ts +0 -2
  419. package/dist/types/src/Extension.test.d.ts.map +0 -1
  420. package/dist/types/src/SchemaRegistry.d.ts +0 -84
  421. package/dist/types/src/SchemaRegistry.d.ts.map +0 -1
  422. package/dist/types/src/internal/Obj/ids.d.ts +0 -6
  423. package/dist/types/src/internal/Obj/ids.d.ts.map +0 -1
  424. package/dist/types/src/internal/Query.d.ts.map +0 -1
  425. package/dist/types/src/internal/Type/echo-schema.d.ts +0 -181
  426. package/dist/types/src/internal/Type/echo-schema.d.ts.map +0 -1
  427. package/dist/types/src/internal/Type/persistent-schema.d.ts +0 -20
  428. package/dist/types/src/internal/Type/persistent-schema.d.ts.map +0 -1
  429. package/src/Extension.test.ts +0 -235
  430. package/src/Extension.ts +0 -122
  431. package/src/SchemaRegistry.ts +0 -106
  432. package/src/internal/Obj/ids.ts +0 -12
  433. package/src/internal/Type/echo-schema.ts +0 -423
  434. package/src/internal/Type/persistent-schema.ts +0 -33
  435. /package/dist/lib/neutral/{Extension.mjs.map → Registry.mjs.map} +0 -0
  436. /package/dist/lib/neutral/{SchemaRegistry.mjs.map → Scope.mjs.map} +0 -0
  437. /package/dist/lib/neutral/{chunk-7RO7CPBZ.mjs.map → chunk-IGK6FN65.mjs.map} +0 -0
@@ -11,19 +11,22 @@ import * as SchemaAST from 'effect/SchemaAST';
11
11
  import type * as Types from 'effect/Types';
12
12
 
13
13
  import { raise } from '@dxos/debug';
14
- import { mapAst } from '@dxos/effect';
14
+ import { SchemaEx } from '@dxos/effect';
15
15
  import { assertArgument, invariant } from '@dxos/invariant';
16
- import { DXN, ObjectId } from '@dxos/keys';
16
+ import { DXN, EID, EntityId } from '@dxos/keys';
17
17
  import { log } from '@dxos/log';
18
18
  import { clearUndefined, orderKeys, removeProperties } from '@dxos/util';
19
19
 
20
+ import type * as Type from '../../Type';
21
+ import { type TypeAnnotation, TypeAnnotationId, TypeIdentifierAnnotationId } from '../Annotation/annotations';
22
+ import { makeTypeJsonSchemaAnnotation } from '../Annotation/util';
20
23
  import {
21
- type TypeAnnotation,
22
- TypeAnnotationId,
23
- TypeIdentifierAnnotationId,
24
- makeTypeJsonSchemaAnnotation,
25
- } from '../Annotation';
26
- import { ANY_OBJECT_TYPENAME, ANY_OBJECT_VERSION, EntityKind, EntityKindSchema } from '../common/types';
24
+ ANY_OBJECT_TYPENAME,
25
+ ANY_OBJECT_VERSION,
26
+ EntityKind,
27
+ EntityKindSchema,
28
+ getStaticTypeSchema,
29
+ } from '../common/types';
27
30
  import { type JsonSchemaReferenceInfo, createEchoReferenceSchema } from '../Ref';
28
31
  import { CustomAnnotations, DecodedAnnotations, EchoAnnotations } from './annotations';
29
32
  import {
@@ -81,11 +84,22 @@ export type JsonSchemaOptions = {
81
84
  // We add additional propertyOrder (but the object properties ARE ordered); and type "string" for literals.
82
85
  // TODO(wittjosiah): This is mutable because its a pojo, perhaps should be left as readonly at type level though?
83
86
  export const toJsonSchema = (
84
- schema: Schema.Schema.All,
87
+ schema: Schema.Schema.All | Type.AnyEntity,
85
88
  options: JsonSchemaOptions = {},
86
89
  ): Types.DeepMutable<JsonSchemaType> => {
90
+ // Allow passing a `Type.Type` entity — use its hidden source schema (or its
91
+ // already-built jsonSchema as a fallback).
92
+ const slot = getStaticTypeSchema(schema);
93
+ if (slot != null) {
94
+ schema = slot;
95
+ } else if (!Schema.isSchema(schema)) {
96
+ const entityJsonSchema = (schema as { jsonSchema?: JsonSchemaType }).jsonSchema;
97
+ if (entityJsonSchema != null) {
98
+ return entityJsonSchema as Types.DeepMutable<JsonSchemaType>;
99
+ }
100
+ }
87
101
  assertArgument(Schema.isSchema(schema), 'schema');
88
- let jsonSchema = _toJsonSchemaAST(schema.ast);
102
+ let jsonSchema = _toJsonSchemaAST((schema as Schema.Schema.All).ast);
89
103
  if (options.strict) {
90
104
  // TOOD(burdon): Workaround to ensure JSON schema is valid (for agv parsing).
91
105
  jsonSchema = removeProperties(jsonSchema, (key, value) => {
@@ -143,7 +157,7 @@ const withEchoRefinements = (
143
157
  }
144
158
  } else if (SchemaAST.isTypeLiteral(ast)) {
145
159
  // Add property order annotations
146
- recursiveResult = mapAst(ast, (ast, key) =>
160
+ recursiveResult = SchemaEx.mapAst(ast, (ast, key) =>
147
161
  withEchoRefinements(ast, path && typeof key === 'string' ? `${path}/${key}` : undefined, suspendCache),
148
162
  );
149
163
  recursiveResult = addJsonSchemaFields(recursiveResult, {
@@ -153,7 +167,7 @@ const withEchoRefinements = (
153
167
  // Ignore undefined keyword that appears in the optional fields.
154
168
  return ast;
155
169
  } else {
156
- recursiveResult = mapAst(ast, (ast, key) =>
170
+ recursiveResult = SchemaEx.mapAst(ast, (ast, key) =>
157
171
  withEchoRefinements(
158
172
  ast,
159
173
  path && (typeof key === 'string' || typeof key === 'number') ? `${path}/${key}` : undefined,
@@ -190,7 +204,7 @@ export const toEffectSchema = (root: JsonSchemaType, _defs?: JsonSchemaType['$de
190
204
  }
191
205
  }
192
206
  } else if ('$id' in root) {
193
- switch (root.$id as string) {
207
+ switch (decodeURIComponent(root.$id as string)) {
194
208
  case '/schemas/any': {
195
209
  result = anyToEffectSchema(root as JSONSchema.JsonSchema7Any);
196
210
  break;
@@ -201,7 +215,7 @@ export const toEffectSchema = (root: JsonSchemaType, _defs?: JsonSchemaType['$de
201
215
  }
202
216
  case '/schemas/{}':
203
217
  case '/schemas/object': {
204
- result = Schema.Object;
218
+ result = Schema.Struct({});
205
219
  break;
206
220
  }
207
221
  // Custom ECHO object reference.
@@ -340,9 +354,9 @@ const anyToEffectSchema = (root: JSONSchema.JsonSchema7Any): Schema.Schema.AnyNo
340
354
  const echoRefinement: JsonSchemaEchoAnnotations = (root as any)[ECHO_ANNOTATIONS_NS_DEPRECATED_KEY];
341
355
  // TODO(dmaretskyi): Is this branch still taken?
342
356
  if ((echoRefinement as any)?.reference != null) {
343
- const echoId = root.$id.startsWith('dxn:echo:') ? root.$id : undefined;
357
+ const echoUri = root.$id.startsWith('echo:') ? root.$id : undefined;
344
358
  return createEchoReferenceSchema(
345
- echoId,
359
+ echoUri,
346
360
  (echoRefinement as any).reference.typename,
347
361
  (echoRefinement as any).reference.version,
348
362
  );
@@ -363,14 +377,11 @@ const refToEffectSchema = (root: any): Schema.Schema.AnyNoContext => {
363
377
  throw new Error('Invalid reference field in ref schema');
364
378
  }
365
379
 
366
- const targetSchemaDXN = DXN.parse(reference.schema.$ref);
367
- invariant(targetSchemaDXN.kind === DXN.kind.TYPE);
380
+ const ref = reference.schema.$ref;
381
+ const targetSchemaDXN = DXN.tryMake(ref);
382
+ invariant(targetSchemaDXN, `Expected a type DXN, got: ${ref}`);
368
383
 
369
- return createEchoReferenceSchema(
370
- targetSchemaDXN.toString(),
371
- targetSchemaDXN.kind === DXN.kind.TYPE ? targetSchemaDXN.parts[0] : undefined,
372
- reference.schemaVersion,
373
- );
384
+ return createEchoReferenceSchema(ref, DXN.getName(targetSchemaDXN), reference.schemaVersion);
374
385
  };
375
386
 
376
387
  //
@@ -391,10 +402,11 @@ const annotations_toJsonSchemaFields = (annotations: SchemaAST.Annotations): Rec
391
402
  schemaFields[ECHO_ANNOTATIONS_NS_KEY] = echoAnnotations;
392
403
  }
393
404
 
405
+ // For stored schemas the storage URI is the definitive identifier — it overrides
406
+ // the typename `$id` written above.
394
407
  const echoIdentifier = annotations[TypeIdentifierAnnotationId];
395
408
  if (echoIdentifier) {
396
- schemaFields[ECHO_ANNOTATIONS_NS_KEY] ??= {};
397
- schemaFields[ECHO_ANNOTATIONS_NS_KEY].schemaId = echoIdentifier;
409
+ schemaFields.$id = echoIdentifier;
398
410
  }
399
411
 
400
412
  // Custom (at end).
@@ -409,14 +421,14 @@ const annotations_toJsonSchemaFields = (annotations: SchemaAST.Annotations): Rec
409
421
  };
410
422
 
411
423
  const decodeTypeIdentifierAnnotation = (schema: JsonSchemaType): string | undefined => {
412
- // Limit to dxn:echo: URIs.
413
- if (schema.$id && schema.$id.startsWith('dxn:echo:')) {
424
+ // For stored schemas `$id` IS the storage URI (echo:/<id>).
425
+ if (schema.$id && schema.$id.startsWith('echo:')) {
414
426
  return schema.$id;
415
- } else if (schema.$id && schema.$id.startsWith('dxn:type:') && schema?.echo?.type?.schemaId) {
416
- const id = schema?.echo?.type?.schemaId;
417
- if (ObjectId.isValid(id)) {
418
- return DXN.fromLocalObjectId(id).toString();
419
- }
427
+ }
428
+ // Older serializations stored the EID on echo.type.schemaId.
429
+ const legacySchemaId = schema.echo?.type?.schemaId;
430
+ if (legacySchemaId) {
431
+ return EntityId.isValid(legacySchemaId) ? EID.make({ entityId: legacySchemaId }) : legacySchemaId;
420
432
  }
421
433
  return undefined;
422
434
  };
@@ -433,8 +445,8 @@ const decodeTypeAnnotation = (schema: JsonSchemaType): TypeAnnotation | undefine
433
445
  if (annotation.kind === EntityKind.Relation) {
434
446
  const source = schema.relationSource?.$ref ?? raise(new Error('Relation source not set'));
435
447
  const target = schema.relationTarget?.$ref ?? raise(new Error('Relation target not set'));
436
- annotation.sourceSchema = DXN.parse(source).toString();
437
- annotation.targetSchema = DXN.parse(target).toString();
448
+ annotation.sourceSchema = DXN.tryMake(source) ?? raise(new Error(`Invalid relation source: ${source}`));
449
+ annotation.targetSchema = DXN.tryMake(target) ?? raise(new Error(`Invalid relation target: ${target}`));
438
450
  }
439
451
 
440
452
  return annotation;
@@ -470,7 +482,9 @@ const jsonSchemaFieldsToAnnotations = (schema: JsonSchemaType): SchemaAST.Annota
470
482
  if (typeAnnotation) {
471
483
  annotations[TypeAnnotationId] = typeAnnotation;
472
484
  annotations[SchemaAST.JSONSchemaAnnotationId] = makeTypeJsonSchemaAnnotation({
473
- identifier: typeIdentifier,
485
+ // $id is the typename DXN — the schema's type identity. The storage EID (if any)
486
+ // is preserved separately on TypeIdentifierAnnotation / echo.schemaId.
487
+ identifier: DXN.make(typeAnnotation.typename, typeAnnotation.version),
474
488
  kind: typeAnnotation.kind,
475
489
  typename: typeAnnotation.typename,
476
490
  version: typeAnnotation.version,
@@ -0,0 +1,244 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Atom from '@effect-atom/atom/Atom';
6
+ import * as Result from '@effect-atom/atom/Result';
7
+ import * as Effect from 'effect/Effect';
8
+ import * as Function from 'effect/Function';
9
+ import * as Option from 'effect/Option';
10
+
11
+ import { assertArgument } from '@dxos/invariant';
12
+
13
+ import type * as Entity from '../../Entity';
14
+ import type * as Obj from '../../Obj';
15
+ import type * as Ref from '../../Ref';
16
+ import type * as Relation from '../../Relation';
17
+ import { subscribe } from '../common/proxy/reactive';
18
+ import { isEntity, getDatabase } from '../Entity';
19
+ import { RefTypeId } from '../Ref/ref';
20
+ import { loadRefTarget } from '../Ref/utils';
21
+ import { getSnapshot } from './snapshot';
22
+
23
+ const isRef = (obj: unknown): obj is Ref.Ref<any> =>
24
+ obj != null && typeof obj === 'object' && RefTypeId in (obj as object);
25
+
26
+ const getReactiveOption = <T extends Obj.Unknown>(snapshot: Obj.Snapshot<T>): Effect.Effect<Option.Option<T>, never> =>
27
+ Effect.gen(function* () {
28
+ const db = getDatabase(snapshot as any);
29
+ if (!db) {
30
+ return Option.none();
31
+ }
32
+ const obj = db.getObjectById((snapshot as any).id);
33
+ return obj ? Option.some(obj as T) : Option.none();
34
+ });
35
+
36
+ /**
37
+ * Atom family for ECHO objects.
38
+ * Uses object reference as key — same object returns same atom.
39
+ */
40
+ const objectFamily = Atom.family(<T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>> => {
41
+ return Atom.make<Obj.Snapshot<T>>((get) => {
42
+ const unsubscribe = subscribe(obj, () => {
43
+ // getSnapshot adds SnapshotKindId brand at runtime; cast bridges static types.
44
+ get.setSelf(getSnapshot(obj) as unknown as Obj.Snapshot<T>);
45
+ });
46
+
47
+ get.addFinalizer(() => unsubscribe());
48
+
49
+ return getSnapshot(obj) as unknown as Obj.Snapshot<T>;
50
+ }).pipe(Atom.keepAlive);
51
+ });
52
+
53
+ /**
54
+ * Atom family for ECHO refs (snapshot version).
55
+ * Uses ref as key — same ref returns same atom.
56
+ * Subscribes to target object changes after loading.
57
+ */
58
+ const refFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined> => {
59
+ return Atom.make<Obj.Snapshot<T> | undefined>((get) => {
60
+ let unsubscribeTarget: (() => void) | undefined;
61
+
62
+ const setupTargetSubscription = (target: T): Obj.Snapshot<T> => {
63
+ unsubscribeTarget?.();
64
+ unsubscribeTarget = subscribe(target, () => {
65
+ // getSnapshot adds SnapshotKindId brand at runtime; cast bridges static types.
66
+ get.setSelf(getSnapshot(target) as unknown as Obj.Snapshot<T>);
67
+ });
68
+ return getSnapshot(target) as unknown as Obj.Snapshot<T>;
69
+ };
70
+
71
+ get.addFinalizer(() => {
72
+ unsubscribeTarget?.();
73
+ });
74
+
75
+ return loadRefTarget(ref, get, setupTargetSubscription);
76
+ }).pipe(Atom.keepAlive);
77
+ });
78
+
79
+ /**
80
+ * Snapshot a value to create a new reference for comparison and React dependency tracking.
81
+ */
82
+ const snapshotForComparison = <V>(value: V): V => {
83
+ if (Array.isArray(value)) {
84
+ return [...value] as V;
85
+ }
86
+ if (value !== null && typeof value === 'object') {
87
+ return { ...value } as V;
88
+ }
89
+ return value;
90
+ };
91
+
92
+ /**
93
+ * Atom family for ECHO object properties.
94
+ * Uses nested families: outer keyed by object, inner keyed by property key.
95
+ */
96
+ const propertyFamily = Atom.family(<T extends Obj.Unknown>(obj: T) =>
97
+ Atom.family(<K extends keyof T>(key: K): Atom.Atom<T[K]> => {
98
+ return Atom.make<T[K]>((get) => {
99
+ let previousSnapshot = snapshotForComparison(obj[key]);
100
+
101
+ const unsubscribe2 = subscribe(obj, () => {
102
+ const newValue = obj[key];
103
+ const newSnapshot = snapshotForComparison(newValue);
104
+ if (newSnapshot !== previousSnapshot) {
105
+ previousSnapshot = newSnapshot;
106
+ get.setSelf(newSnapshot);
107
+ }
108
+ });
109
+
110
+ get.addFinalizer(() => unsubscribe2());
111
+
112
+ return snapshotForComparison(obj[key]);
113
+ }).pipe(Atom.keepAlive);
114
+ }),
115
+ );
116
+
117
+ /**
118
+ * Atom family for ECHO objects — returns the live object, not a snapshot.
119
+ */
120
+ const objectWithReactiveFamily = Atom.family(<T extends Obj.Unknown>(obj: T): Atom.Atom<T> => {
121
+ return Atom.make<T>((get) => {
122
+ const unsubscribe = subscribe(obj, () => {
123
+ get.setSelf(obj);
124
+ });
125
+
126
+ get.addFinalizer(() => unsubscribe());
127
+
128
+ return obj;
129
+ }).pipe(Atom.keepAlive);
130
+ });
131
+
132
+ /**
133
+ * Atom family for ECHO refs — returns the live reactive object, not a snapshot.
134
+ */
135
+ const refWithReactiveFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<T | undefined> => {
136
+ const effect = (get: Atom.Context) =>
137
+ Effect.gen(function* () {
138
+ const snapshot = get(makeAtom(ref));
139
+ if (snapshot == null) {
140
+ return undefined;
141
+ }
142
+ const option = yield* getReactiveOption(snapshot);
143
+ return Option.getOrElse(option, () => undefined);
144
+ });
145
+
146
+ return Function.pipe(
147
+ Atom.make(effect),
148
+ Atom.map((result) => Result.getOrElse(result, () => undefined)),
149
+ );
150
+ });
151
+
152
+ /**
153
+ * Atom family for any ECHO entity (obj or relation) — returns a snapshot.
154
+ */
155
+ const entityFamily = Atom.family(<T extends Entity.Unknown>(entity: T): Atom.Atom<Entity.Snapshot> => {
156
+ return Atom.make<Entity.Snapshot>((get) => {
157
+ const unsubscribe = subscribe(entity, () => {
158
+ // getSnapshot adds SnapshotKindId brand at runtime; cast bridges static types.
159
+ get.setSelf(getSnapshot(entity) as unknown as Entity.Snapshot);
160
+ });
161
+
162
+ get.addFinalizer(() => unsubscribe());
163
+
164
+ return getSnapshot(entity) as unknown as Entity.Snapshot;
165
+ }).pipe(Atom.keepAlive);
166
+ });
167
+
168
+ /**
169
+ * Atom family for ECHO relations — returns a typed relation snapshot.
170
+ */
171
+ const relationFamily = Atom.family(<T extends Relation.Unknown>(relation: T): Atom.Atom<Relation.Snapshot<T>> => {
172
+ return Atom.make<Relation.Snapshot<T>>((get) => {
173
+ const unsubscribe = subscribe(relation, () => {
174
+ // getSnapshot adds SnapshotKindId brand at runtime; cast bridges static types.
175
+ get.setSelf(getSnapshot(relation) as unknown as Relation.Snapshot<T>);
176
+ });
177
+
178
+ get.addFinalizer(() => unsubscribe());
179
+
180
+ return getSnapshot(relation) as unknown as Relation.Snapshot<T>;
181
+ }).pipe(Atom.keepAlive);
182
+ });
183
+
184
+ /**
185
+ * Create a read-only snapshot atom for a reactive object or ref.
186
+ * Updates automatically when the object is mutated.
187
+ * For refs, subscribes to target object changes after loading.
188
+ */
189
+ export const makeAtom: {
190
+ <T extends Obj.Unknown>(obj: T): Atom.Atom<Obj.Snapshot<T>>;
191
+ <T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<Obj.Snapshot<T> | undefined>;
192
+ } = (objOrRef: Obj.Unknown | Ref.Ref<any>): Atom.Atom<any> => {
193
+ if (isRef(objOrRef)) {
194
+ return refFamily(objOrRef as any);
195
+ }
196
+
197
+ const obj = objOrRef as Obj.Unknown;
198
+ assertArgument(isEntity(obj), 'obj', 'Object must be a reactive object');
199
+ return objectFamily(obj as any);
200
+ };
201
+
202
+ /**
203
+ * Create a read-only atom for a specific property of a reactive object.
204
+ * Only fires updates when the property value actually changes.
205
+ */
206
+ export const makeProperty = <T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]> => {
207
+ assertArgument(isEntity(obj), 'obj', 'Object must be a reactive object');
208
+ return propertyFamily(obj)(key);
209
+ };
210
+
211
+ /**
212
+ * Like `makeAtom` but returns the live reactive object instead of a snapshot.
213
+ * Prefer `makeAtom` (snapshot) unless you need the live Obj for generic mutations.
214
+ */
215
+ export const makeWithReactive: {
216
+ <T extends Obj.Unknown>(obj: T): Atom.Atom<T>;
217
+ <T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Atom<T | undefined>;
218
+ } = (objOrRef: Obj.Unknown | Ref.Ref<any>): Atom.Atom<any> => {
219
+ if (isRef(objOrRef)) {
220
+ return refWithReactiveFamily(objOrRef as Ref.Ref<any>);
221
+ }
222
+
223
+ const obj = objOrRef as Obj.Unknown;
224
+ assertArgument(isEntity(obj), 'obj', 'Object must be a reactive object');
225
+ return objectWithReactiveFamily(obj);
226
+ };
227
+
228
+ /**
229
+ * Create a read-only snapshot atom for any ECHO entity (obj or relation).
230
+ * Updates automatically when the entity is mutated.
231
+ */
232
+ export const makeEntity = <T extends Entity.Unknown>(entity: T): Atom.Atom<Entity.Snapshot> => {
233
+ assertArgument(isEntity(entity), 'entity', 'Must be a reactive ECHO entity');
234
+ return entityFamily(entity);
235
+ };
236
+
237
+ /**
238
+ * Create a read-only snapshot atom for a reactive relation.
239
+ * Updates automatically when the relation is mutated.
240
+ */
241
+ export const makeRelation = <T extends Relation.Unknown>(relation: T): Atom.Atom<Relation.Snapshot<T>> => {
242
+ assertArgument(isEntity(relation), 'relation', 'Must be a reactive ECHO relation');
243
+ return relationFamily(relation);
244
+ };
@@ -7,7 +7,8 @@ import { deepMapValues } from '@dxos/util';
7
7
 
8
8
  import type * as Obj from '../../Obj';
9
9
  import { makeObject } from '../common/proxy';
10
- import { getMeta, getSchema } from '../common/types';
10
+ import { getSchema, getStaticTypeSchema, getType } from '../common/types';
11
+ import { getMeta } from '../common/types/meta';
11
12
  import { Ref } from '../Ref';
12
13
 
13
14
  /**
@@ -17,8 +18,12 @@ import { Ref } from '../Ref';
17
18
  */
18
19
  export const clone = <T extends Obj.Any>(obj: T, opts?: Obj.CloneOptions): T => {
19
20
  const { id, ...data } = obj;
20
- const schema = getSchema(obj);
21
- invariant(schema != null, 'Object should have a schema');
21
+ // Prefer cloning through the type entity so the cloned instance preserves
22
+ // `Obj.getType` identity. Falls back to the raw schema for older instances
23
+ // that don't have a type-entity back-reference set (e.g. deserialized).
24
+ const typeEntity = getType(obj);
25
+ const schema = typeEntity != null ? getStaticTypeSchema(typeEntity) : getSchema(obj);
26
+ invariant(schema != null, 'Object should have a type or schema');
22
27
  const props: any = deepMapValues(data, (value, recurse) => {
23
28
  if (Ref.isRef(value)) {
24
29
  if (opts?.deep) {
@@ -44,5 +49,5 @@ export const clone = <T extends Obj.Any>(obj: T, opts?: Obj.CloneOptions): T =>
44
49
  return recurse(value);
45
50
  });
46
51
 
47
- return makeObject(schema, props, meta);
52
+ return makeObject(schema, props, meta, typeEntity as object | undefined);
48
53
  };
@@ -6,13 +6,15 @@ import * as Schema from 'effect/Schema';
6
6
  import { inspect } from 'util';
7
7
  import { describe, expect, test } from 'vitest';
8
8
 
9
- import { DXN } from '@dxos/keys';
9
+ import { DXN, EID } from '@dxos/keys';
10
10
 
11
11
  import { Relation } from '../../index';
12
12
  import { TestSchema } from '../../testing';
13
- import { getSchemaDXN, getTypeDXN, isInstanceOf } from '../Annotation';
14
- import { ATTR_META, ATTR_TYPE, getSchema } from '../common/types';
15
- import { ATTR_RELATION_SOURCE, ATTR_RELATION_TARGET } from '../Entity';
13
+ import * as Type from '../../Type';
14
+ import { getTypeURI } from '../Annotation';
15
+ import { ATTR_TYPE, getSchema } from '../common/types';
16
+ import { ATTR_META } from '../common/types/meta';
17
+ import { ATTR_RELATION_SOURCE, ATTR_RELATION_TARGET, isInstanceOf } from '../Entity';
16
18
  import { createObject } from './create-object';
17
19
  import { objectToJSON } from './json-serializer';
18
20
 
@@ -40,7 +42,7 @@ describe('create (static version)', () => {
40
42
  expect(contact.name).toBe('Bot');
41
43
  expect(contact.email).toBe('bot@example.com');
42
44
  expect((contact as any)['@type']).toBeUndefined();
43
- expect(getTypeDXN(contact)?.toString()).toBe(getSchemaDXN(TestSchema.Person)!.toString());
45
+ expect(getTypeURI(contact)?.toString()).toBe(Type.getURI(TestSchema.Person).toString());
44
46
  expect(isInstanceOf(TestSchema.Person, contact)).toBe(true);
45
47
  });
46
48
 
@@ -53,7 +55,7 @@ describe('create (static version)', () => {
53
55
  const json = JSON.parse(JSON.stringify(contact));
54
56
  expect(json).toEqual({
55
57
  id: contact.id,
56
- '@type': DXN.fromTypenameAndVersion(TestSchema.Person.typename, TestSchema.Person.version).toString(),
58
+ '@type': DXN.make(Type.getTypename(TestSchema.Person), Type.getVersion(TestSchema.Person)),
57
59
  '@meta': {
58
60
  keys: [],
59
61
  },
@@ -81,9 +83,9 @@ describe('create (static version)', () => {
81
83
  const json = JSON.parse(JSON.stringify(manager));
82
84
  expect(json).toEqual({
83
85
  id: manager.id,
84
- [ATTR_TYPE]: DXN.fromTypenameAndVersion(TestSchema.HasManager.typename, TestSchema.HasManager.version).toString(),
85
- [ATTR_RELATION_SOURCE]: DXN.fromLocalObjectId(person1.id).toString(),
86
- [ATTR_RELATION_TARGET]: DXN.fromLocalObjectId(person2.id).toString(),
86
+ [ATTR_TYPE]: DXN.make(Type.getTypename(TestSchema.HasManager), Type.getVersion(TestSchema.HasManager)),
87
+ [ATTR_RELATION_SOURCE]: EID.make({ entityId: person1.id }),
88
+ [ATTR_RELATION_TARGET]: EID.make({ entityId: person2.id }),
87
89
  [ATTR_META]: {
88
90
  keys: [],
89
91
  },
@@ -96,7 +98,7 @@ describe('create (static version)', () => {
96
98
  email: 'bot@example.com',
97
99
  });
98
100
 
99
- expect(getSchema(contact)).toBe(TestSchema.Person);
101
+ expect(getSchema(contact)).toBe(Type.getSchema(TestSchema.Person));
100
102
  });
101
103
 
102
104
  test('inspect', () => {
@@ -2,27 +2,45 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import type * as Schema from 'effect/Schema';
6
-
7
5
  import { raise } from '@dxos/debug';
8
6
  import { assertArgument, failedInvariant } from '@dxos/invariant';
9
- import { ObjectId } from '@dxos/keys';
7
+ import { EntityId } from '@dxos/keys';
10
8
 
11
- import { getSchemaDXN, getTypeAnnotation, setTypename } from '../Annotation';
9
+ import type * as Type from '../../Type';
10
+ import { getSchemaURI, getTypeAnnotation, setTypename } from '../Annotation';
12
11
  import { defineHiddenProperty } from '../common/proxy';
13
- import { EntityKind, KindId, MetaId, setSchema } from '../common/types';
12
+ import {
13
+ EntityKind,
14
+ KindId,
15
+ SchemaKindId,
16
+ StaticTypeSchemaSlot,
17
+ getStaticTypeSchema,
18
+ setSchema,
19
+ setType,
20
+ } from '../common/types';
21
+ import { type EntityMeta } from '../common/types/meta';
22
+ import { MetaId } from '../common/types/model-symbols';
14
23
  import {
15
24
  RelationSourceDXNId,
16
25
  RelationSourceId,
17
26
  RelationTargetDXNId,
18
27
  RelationTargetId,
19
28
  assertObjectModel,
20
- getObjectDXN,
29
+ getObjectEchoUri,
21
30
  } from '../Entity';
22
31
  import { attachedTypedObjectInspector } from './inspect';
23
32
  import { attachTypedJsonSerializer } from './json-serializer';
24
33
 
25
- export type CreateObjectProps<T> = T extends { id: string } ? Omit<T, 'id' | KindId> & { id?: string } : T;
34
+ // Omits the brand slots those get stamped on the instance by the entity
35
+ // handler (KindId via setKind, SchemaKindId derived in the proxy `get` trap
36
+ // from kind + jsonSchema.entityKind, StaticTypeSchemaSlot lazily via the
37
+ // proxy), not supplied by the caller. Allows `[Obj.Meta]` (MetaId symbol) for
38
+ // seeding registry-provenance meta at construction (mirrors `Obj.make`).
39
+ export type CreateObjectProps<T> = (T extends { id: string }
40
+ ? Omit<T, 'id' | KindId | SchemaKindId | StaticTypeSchemaSlot> & { id?: string }
41
+ : Omit<T, KindId | SchemaKindId | StaticTypeSchemaSlot>) & {
42
+ readonly [MetaId]?: Partial<EntityMeta>;
43
+ };
26
44
 
27
45
  /**
28
46
  * Creates a new object instance from a schema and data, without signal reactivity.
@@ -40,10 +58,7 @@ export type CreateObjectProps<T> = T extends { id: string } ? Omit<T, 'id' | Kin
40
58
  * const Contact = Schema.Struct({
41
59
  * name: Schema.String,
42
60
  * email: Schema.String,
43
- * }).pipe(Type.object({
44
- * typename: 'com.example.type.person',
45
- * version: '0.1.0',
46
- * }))
61
+ * }).pipe(Type.makeObject(DXN.make('com.example.type.person', '0.1.0')))
47
62
  *
48
63
  * const contact = createObject(Contact, {
49
64
  * name: "John",
@@ -52,10 +67,13 @@ export type CreateObjectProps<T> = T extends { id: string } ? Omit<T, 'id' | Kin
52
67
  * ```
53
68
  */
54
69
  // TODO(burdon): Make internal.
55
- export const createObject = <S extends Schema.Schema.AnyNoContext>(
56
- schema: S,
57
- props: CreateObjectProps<Schema.Schema.Type<S>>,
58
- ): CreateObjectProps<Schema.Schema.Type<S>> & { id: string; [KindId]: EntityKind } => {
70
+ export const createObject: {
71
+ <T extends Type.AnyEntity>(input: T, props: NoInfer<CreateObjectProps<Type.InstanceType<T>>>): Type.InstanceType<T>;
72
+ } = (input: any, props: any): any => {
73
+ // `Type.Type` entities aren't `Schema.Schema` themselves; read the source
74
+ // schema off the hidden slot (persisted entities synthesize it lazily via
75
+ // the proxy `get` trap).
76
+ const schema = getStaticTypeSchema(input) ?? failedInvariant('Type entity is missing its source schema');
59
77
  const annotation = getTypeAnnotation(schema);
60
78
  if (!annotation) {
61
79
  throw new Error('Schema is not an ECHO schema');
@@ -69,22 +87,50 @@ export const createObject = <S extends Schema.Schema.AnyNoContext>(
69
87
  'Relation source and target must be provided together',
70
88
  );
71
89
 
90
+ // Pull `[Obj.Meta]` (MetaId-symbol) off props before spreading so it doesn't
91
+ // leak into data. Callers use this to seed registry-provenance meta fields
92
+ // (`key`, `version`) and foreign keys / tags at construction time, mirroring
93
+ // `Obj.make`'s symbol-keyed meta convention.
94
+ const metaOverride = props[MetaId];
95
+ if (metaOverride !== undefined) {
96
+ delete props[MetaId];
97
+ }
98
+
72
99
  // Raw object.
73
- const obj = { ...props, id: props.id ?? ObjectId.random() };
100
+ const obj = { ...props, id: props.id ?? EntityId.random() };
74
101
 
75
- // Metadata.
76
- const kind = RelationSourceId in props ? EntityKind.Relation : EntityKind.Object;
102
+ // Metadata. Instance-kind is read from the schema's TypeAnnotation (set by
103
+ // EchoObjectSchema / EchoRelationSchema / EchoTypeKindSchema): instances of
104
+ // a type-kind meta-schema are themselves type-kind entities, etc. The
105
+ // RelationSourceId-in-props check covers the legacy path where the schema
106
+ // annotation isn't authoritative.
107
+ const kind =
108
+ annotation.kind === EntityKind.Type
109
+ ? EntityKind.Type
110
+ : annotation.kind === EntityKind.Relation || RelationSourceId in props
111
+ ? EntityKind.Relation
112
+ : EntityKind.Object;
77
113
  defineHiddenProperty(obj, KindId, kind);
78
- defineHiddenProperty(obj, MetaId, { keys: [] });
114
+ defineHiddenProperty(obj, MetaId, {
115
+ ...metaOverride,
116
+ keys: metaOverride?.keys ?? [],
117
+ tags: metaOverride?.tags ?? [],
118
+ annotations: metaOverride?.annotations ?? {},
119
+ });
79
120
  setSchema(obj, schema);
80
- setTypename(obj, getSchemaDXN(schema) ?? failedInvariant('Missing schema DXN'));
121
+ // If the caller passed a type entity (recognised via the schema slot), keep
122
+ // a reference to it on the instance for `Obj.getType` / `Relation.getType`.
123
+ if (input !== schema) {
124
+ setType(obj, input);
125
+ }
126
+ setTypename(obj, getSchemaURI(schema) ?? failedInvariant('Missing schema URI'));
81
127
  attachTypedJsonSerializer(obj);
82
128
  attachedTypedObjectInspector(obj);
83
129
 
84
130
  // Relation.
85
131
  if (kind === EntityKind.Relation) {
86
- const sourceDXN = getObjectDXN(props[RelationSourceId]) ?? raise(new Error('Unresolved relation source'));
87
- const targetDXN = getObjectDXN(props[RelationTargetId]) ?? raise(new Error('Unresolved relation target'));
132
+ const sourceDXN = getObjectEchoUri(props[RelationSourceId]) ?? raise(new Error('Unresolved relation source'));
133
+ const targetDXN = getObjectEchoUri(props[RelationTargetId]) ?? raise(new Error('Unresolved relation target'));
88
134
  defineHiddenProperty(obj, RelationSourceDXNId, sourceDXN);
89
135
  defineHiddenProperty(obj, RelationTargetDXNId, targetDXN);
90
136
  }
@@ -5,10 +5,10 @@
5
5
  export * from './common';
6
6
  export * from './create-object';
7
7
  export * from './deleted';
8
- export * from './ids';
9
8
  export * from './json-serializer';
10
9
  export * from './schema-validator';
11
10
  export * from './set-value';
12
11
  export * from './snapshot';
13
12
  export * from './typed-object';
13
+ export * from './atoms';
14
14
  export * from './clone';