@dxos/echo 0.8.4-main.ead640a → 0.8.4-main.ef1bc66f44

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 (535) hide show
  1. package/README.md +1 -2
  2. package/dist/lib/neutral/Annotation.mjs +35 -0
  3. package/dist/lib/neutral/Database.mjs +45 -0
  4. package/dist/lib/neutral/Entity.mjs +51 -0
  5. package/dist/lib/neutral/Err.mjs +10 -0
  6. package/dist/lib/neutral/Filter.mjs +61 -0
  7. package/dist/lib/neutral/Format.mjs +66 -0
  8. package/dist/lib/neutral/JsonSchema.mjs +19 -0
  9. package/dist/lib/neutral/JsonSchema.mjs.map +7 -0
  10. package/dist/lib/neutral/Key.mjs +12 -0
  11. package/dist/lib/neutral/Key.mjs.map +7 -0
  12. package/dist/lib/neutral/Obj.mjs +96 -0
  13. package/dist/lib/neutral/Obj.mjs.map +7 -0
  14. package/dist/lib/neutral/Order.mjs +12 -0
  15. package/dist/lib/neutral/Order.mjs.map +7 -0
  16. package/dist/lib/neutral/Query.mjs +26 -0
  17. package/dist/lib/neutral/Query.mjs.map +7 -0
  18. package/dist/lib/neutral/QueryResult.mjs +2 -0
  19. package/dist/lib/neutral/QueryResult.mjs.map +7 -0
  20. package/dist/lib/neutral/Ref.mjs +22 -0
  21. package/dist/lib/neutral/Ref.mjs.map +7 -0
  22. package/dist/lib/neutral/Relation.mjs +84 -0
  23. package/dist/lib/neutral/Relation.mjs.map +7 -0
  24. package/dist/lib/neutral/SchemaRegistry.mjs +2 -0
  25. package/dist/lib/neutral/SchemaRegistry.mjs.map +7 -0
  26. package/dist/lib/neutral/Tag.mjs +25 -0
  27. package/dist/lib/neutral/Tag.mjs.map +7 -0
  28. package/dist/lib/neutral/Type.mjs +47 -0
  29. package/dist/lib/neutral/Type.mjs.map +7 -0
  30. package/dist/lib/neutral/chunk-2AF5GMG6.mjs +171 -0
  31. package/dist/lib/neutral/chunk-2AF5GMG6.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-4L6DOFXP.mjs +7 -0
  33. package/dist/lib/neutral/chunk-4L6DOFXP.mjs.map +7 -0
  34. package/dist/lib/neutral/chunk-7WE7SBA2.mjs +402 -0
  35. package/dist/lib/neutral/chunk-7WE7SBA2.mjs.map +7 -0
  36. package/dist/lib/neutral/chunk-ANHVGJI4.mjs +21 -0
  37. package/dist/lib/neutral/chunk-ANHVGJI4.mjs.map +7 -0
  38. package/dist/lib/neutral/chunk-DLPC7DHQ.mjs +56 -0
  39. package/dist/lib/neutral/chunk-DLPC7DHQ.mjs.map +7 -0
  40. package/dist/lib/neutral/chunk-EBUAT5ID.mjs +229 -0
  41. package/dist/lib/neutral/chunk-EBUAT5ID.mjs.map +7 -0
  42. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  43. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  44. package/dist/lib/neutral/chunk-K5K3Z62A.mjs +40 -0
  45. package/dist/lib/neutral/chunk-K5K3Z62A.mjs.map +7 -0
  46. package/dist/lib/neutral/chunk-KB7RIVLK.mjs +67 -0
  47. package/dist/lib/neutral/chunk-KB7RIVLK.mjs.map +7 -0
  48. package/dist/lib/neutral/chunk-LKFNEFHF.mjs +130 -0
  49. package/dist/lib/neutral/chunk-LKFNEFHF.mjs.map +7 -0
  50. package/dist/lib/neutral/chunk-MTEHHY62.mjs +251 -0
  51. package/dist/lib/neutral/chunk-MTEHHY62.mjs.map +7 -0
  52. package/dist/lib/neutral/chunk-N2QNHMT5.mjs +73 -0
  53. package/dist/lib/neutral/chunk-N2QNHMT5.mjs.map +7 -0
  54. package/dist/lib/neutral/chunk-OMUPQMLR.mjs +7 -0
  55. package/dist/lib/neutral/chunk-OMUPQMLR.mjs.map +7 -0
  56. package/dist/lib/neutral/chunk-QARLJVDB.mjs +23 -0
  57. package/dist/lib/neutral/chunk-QARLJVDB.mjs.map +7 -0
  58. package/dist/lib/neutral/chunk-RIMHNJ3E.mjs +296 -0
  59. package/dist/lib/neutral/chunk-RIMHNJ3E.mjs.map +7 -0
  60. package/dist/lib/neutral/chunk-ROKO4RKJ.mjs +42 -0
  61. package/dist/lib/neutral/chunk-ROKO4RKJ.mjs.map +7 -0
  62. package/dist/lib/neutral/chunk-RPB6V4BE.mjs +38 -0
  63. package/dist/lib/neutral/chunk-RPB6V4BE.mjs.map +7 -0
  64. package/dist/lib/neutral/chunk-TLGNKUUG.mjs +3905 -0
  65. package/dist/lib/neutral/chunk-TLGNKUUG.mjs.map +7 -0
  66. package/dist/lib/neutral/chunk-TQT6WTIJ.mjs +142 -0
  67. package/dist/lib/neutral/chunk-TQT6WTIJ.mjs.map +7 -0
  68. package/dist/lib/neutral/chunk-VUQGRDRI.mjs +97 -0
  69. package/dist/lib/neutral/chunk-VUQGRDRI.mjs.map +7 -0
  70. package/dist/lib/neutral/chunk-X2MPMYYN.mjs +13 -0
  71. package/dist/lib/neutral/chunk-X2MPMYYN.mjs.map +7 -0
  72. package/dist/lib/neutral/chunk-XAJMXQ4H.mjs +43 -0
  73. package/dist/lib/neutral/chunk-XAJMXQ4H.mjs.map +7 -0
  74. package/dist/lib/neutral/chunk-ZAHWXGK4.mjs +287 -0
  75. package/dist/lib/neutral/chunk-ZAHWXGK4.mjs.map +7 -0
  76. package/dist/lib/neutral/index.mjs +84 -0
  77. package/dist/lib/neutral/index.mjs.map +7 -0
  78. package/dist/lib/{node-esm → neutral}/internal/index.mjs +251 -121
  79. package/dist/lib/neutral/internal/index.mjs.map +7 -0
  80. package/dist/lib/neutral/meta.json +1 -0
  81. package/dist/lib/neutral/testing/index.mjs +366 -0
  82. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  83. package/dist/types/src/Annotation.d.ts +24 -0
  84. package/dist/types/src/Annotation.d.ts.map +1 -0
  85. package/dist/types/src/Database.d.ts +216 -0
  86. package/dist/types/src/Database.d.ts.map +1 -0
  87. package/dist/types/src/Entity.d.ts +142 -0
  88. package/dist/types/src/Entity.d.ts.map +1 -0
  89. package/dist/types/src/Entity.test.d.ts +2 -0
  90. package/dist/types/src/Entity.test.d.ts.map +1 -0
  91. package/dist/types/src/{errors.d.ts → Err.d.ts} +23 -31
  92. package/dist/types/src/Err.d.ts.map +1 -0
  93. package/dist/types/src/Filter.d.ts +120 -0
  94. package/dist/types/src/Filter.d.ts.map +1 -0
  95. package/dist/types/src/Format.d.ts +4 -0
  96. package/dist/types/src/Format.d.ts.map +1 -0
  97. package/dist/types/src/Hypergraph.d.ts +60 -0
  98. package/dist/types/src/Hypergraph.d.ts.map +1 -0
  99. package/dist/types/src/JsonSchema.d.ts +9 -0
  100. package/dist/types/src/JsonSchema.d.ts.map +1 -0
  101. package/dist/types/src/Key.d.ts +1 -0
  102. package/dist/types/src/Key.d.ts.map +1 -1
  103. package/dist/types/src/Obj.d.ts +327 -99
  104. package/dist/types/src/Obj.d.ts.map +1 -1
  105. package/dist/types/src/Obj.test.d.ts +2 -0
  106. package/dist/types/src/Obj.test.d.ts.map +1 -0
  107. package/dist/types/src/Order.d.ts +16 -0
  108. package/dist/types/src/Order.d.ts.map +1 -0
  109. package/dist/types/src/Query.d.ts +125 -0
  110. package/dist/types/src/Query.d.ts.map +1 -0
  111. package/dist/types/src/Query.test.d.ts +2 -0
  112. package/dist/types/src/Query.test.d.ts.map +1 -0
  113. package/dist/types/src/QueryResult.d.ts +80 -0
  114. package/dist/types/src/QueryResult.d.ts.map +1 -0
  115. package/dist/types/src/Ref.d.ts +13 -11
  116. package/dist/types/src/Ref.d.ts.map +1 -1
  117. package/dist/types/src/Relation.d.ts +243 -23
  118. package/dist/types/src/Relation.d.ts.map +1 -1
  119. package/dist/types/src/Relation.test.d.ts +2 -0
  120. package/dist/types/src/Relation.test.d.ts.map +1 -0
  121. package/dist/types/src/SchemaRegistry.d.ts +84 -0
  122. package/dist/types/src/SchemaRegistry.d.ts.map +1 -0
  123. package/dist/types/src/Tag.d.ts +17 -0
  124. package/dist/types/src/Tag.d.ts.map +1 -0
  125. package/dist/types/src/Type.d.ts +225 -72
  126. package/dist/types/src/Type.d.ts.map +1 -1
  127. package/dist/types/src/Type.test.d.ts +2 -0
  128. package/dist/types/src/Type.test.d.ts.map +1 -0
  129. package/dist/types/src/hierarchy.test.d.ts +2 -0
  130. package/dist/types/src/hierarchy.test.d.ts.map +1 -0
  131. package/dist/types/src/index.d.ts +15 -5
  132. package/dist/types/src/index.d.ts.map +1 -1
  133. package/dist/types/src/internal/annotations/annotations.d.ts +177 -0
  134. package/dist/types/src/internal/annotations/annotations.d.ts.map +1 -0
  135. package/dist/types/src/internal/annotations/annotations.test.d.ts.map +1 -0
  136. package/dist/types/src/internal/annotations/index.d.ts +3 -0
  137. package/dist/types/src/internal/annotations/index.d.ts.map +1 -0
  138. package/dist/types/src/internal/annotations/util.d.ts +39 -0
  139. package/dist/types/src/internal/annotations/util.d.ts.map +1 -0
  140. package/dist/types/src/internal/api/annotations.d.ts +23 -0
  141. package/dist/types/src/internal/api/annotations.d.ts.map +1 -0
  142. package/dist/types/src/internal/api/entity.d.ts +13 -0
  143. package/dist/types/src/internal/api/entity.d.ts.map +1 -0
  144. package/dist/types/src/internal/api/index.d.ts +15 -0
  145. package/dist/types/src/internal/api/index.d.ts.map +1 -0
  146. package/dist/types/src/internal/api/meta.d.ts +42 -0
  147. package/dist/types/src/internal/api/meta.d.ts.map +1 -0
  148. package/dist/types/src/internal/api/sorting.d.ts +24 -0
  149. package/dist/types/src/internal/api/sorting.d.ts.map +1 -0
  150. package/dist/types/src/internal/api/version.d.ts +42 -0
  151. package/dist/types/src/internal/api/version.d.ts.map +1 -0
  152. package/dist/types/src/internal/entities/entity.d.ts +20 -0
  153. package/dist/types/src/internal/entities/entity.d.ts.map +1 -0
  154. package/dist/types/src/internal/entities/index.d.ts +6 -0
  155. package/dist/types/src/internal/entities/index.d.ts.map +1 -0
  156. package/dist/types/src/internal/entities/model.d.ts +79 -0
  157. package/dist/types/src/internal/entities/model.d.ts.map +1 -0
  158. package/dist/types/src/internal/entities/object.d.ts +18 -0
  159. package/dist/types/src/internal/entities/object.d.ts.map +1 -0
  160. package/dist/types/src/internal/entities/relation.d.ts +62 -0
  161. package/dist/types/src/internal/entities/relation.d.ts.map +1 -0
  162. package/dist/types/src/internal/entities/util.d.ts +2 -0
  163. package/dist/types/src/internal/entities/util.d.ts.map +1 -0
  164. package/dist/types/src/internal/formats/format.d.ts +4 -2
  165. package/dist/types/src/internal/formats/format.d.ts.map +1 -1
  166. package/dist/types/src/internal/formats/select.d.ts +6 -4
  167. package/dist/types/src/internal/formats/select.d.ts.map +1 -1
  168. package/dist/types/src/internal/formats/string.d.ts +4 -0
  169. package/dist/types/src/internal/formats/string.d.ts.map +1 -1
  170. package/dist/types/src/internal/formats/types.d.ts +13 -9
  171. package/dist/types/src/internal/formats/types.d.ts.map +1 -1
  172. package/dist/types/src/internal/index.d.ts +7 -10
  173. package/dist/types/src/internal/index.d.ts.map +1 -1
  174. package/dist/types/src/internal/json-schema/annotations.d.ts.map +1 -0
  175. package/dist/types/src/internal/json-schema/effect-schema.test.d.ts.map +1 -0
  176. package/dist/types/src/internal/json-schema/index.d.ts +2 -0
  177. package/dist/types/src/internal/json-schema/index.d.ts.map +1 -1
  178. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +1 -1
  179. package/dist/types/src/internal/json-schema/json-schema-type.d.ts +130 -29
  180. package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +1 -1
  181. package/dist/types/src/internal/{json → json-schema}/json-schema.d.ts +4 -2
  182. package/dist/types/src/internal/json-schema/json-schema.d.ts.map +1 -0
  183. package/dist/types/src/internal/json-schema/json-schema.test.d.ts.map +1 -0
  184. package/dist/types/src/internal/object/clone.d.ts +8 -0
  185. package/dist/types/src/internal/object/clone.d.ts.map +1 -0
  186. package/dist/types/src/internal/object/common.d.ts.map +1 -1
  187. package/dist/types/src/internal/object/{create.d.ts → create-object.d.ts} +10 -11
  188. package/dist/types/src/internal/object/create-object.d.ts.map +1 -0
  189. package/dist/types/src/internal/object/create-object.test.d.ts +2 -0
  190. package/dist/types/src/internal/object/create-object.test.d.ts.map +1 -0
  191. package/dist/types/src/internal/object/deleted.d.ts +2 -2
  192. package/dist/types/src/internal/object/deleted.d.ts.map +1 -1
  193. package/dist/types/src/internal/object/ids.d.ts.map +1 -1
  194. package/dist/types/src/internal/object/index.d.ts +6 -11
  195. package/dist/types/src/internal/object/index.d.ts.map +1 -1
  196. package/dist/types/src/internal/object/json-serializer.d.ts +14 -9
  197. package/dist/types/src/internal/object/json-serializer.d.ts.map +1 -1
  198. package/dist/types/src/internal/object/schema-validator.d.ts +1 -14
  199. package/dist/types/src/internal/object/schema-validator.d.ts.map +1 -1
  200. package/dist/types/src/internal/object/set-value.d.ts +7 -0
  201. package/dist/types/src/internal/object/set-value.d.ts.map +1 -0
  202. package/dist/types/src/internal/object/set-value.test.d.ts +2 -0
  203. package/dist/types/src/internal/object/set-value.test.d.ts.map +1 -0
  204. package/dist/types/src/internal/object/snapshot.d.ts +6 -0
  205. package/dist/types/src/internal/object/snapshot.d.ts.map +1 -0
  206. package/dist/types/src/internal/object/typed-object.d.ts +8 -14
  207. package/dist/types/src/internal/object/typed-object.d.ts.map +1 -1
  208. package/dist/types/src/internal/proxy/change-context.d.ts +55 -0
  209. package/dist/types/src/internal/proxy/change-context.d.ts.map +1 -0
  210. package/dist/types/src/internal/proxy/change.test.d.ts +2 -0
  211. package/dist/types/src/internal/proxy/change.test.d.ts.map +1 -0
  212. package/dist/types/src/internal/proxy/define-hidden-property.d.ts +5 -0
  213. package/dist/types/src/internal/proxy/define-hidden-property.d.ts.map +1 -0
  214. package/dist/types/src/internal/proxy/errors.d.ts +19 -0
  215. package/dist/types/src/internal/proxy/errors.d.ts.map +1 -0
  216. package/dist/types/src/internal/proxy/event-batch.d.ts +10 -0
  217. package/dist/types/src/internal/proxy/event-batch.d.ts.map +1 -0
  218. package/dist/types/src/internal/proxy/index.d.ts +14 -0
  219. package/dist/types/src/internal/proxy/index.d.ts.map +1 -0
  220. package/dist/types/src/internal/proxy/json-serializer.d.ts +6 -0
  221. package/dist/types/src/internal/proxy/json-serializer.d.ts.map +1 -0
  222. package/dist/types/src/internal/proxy/make-object.d.ts +14 -0
  223. package/dist/types/src/internal/proxy/make-object.d.ts.map +1 -0
  224. package/dist/types/src/internal/proxy/ownership.d.ts +57 -0
  225. package/dist/types/src/internal/proxy/ownership.d.ts.map +1 -0
  226. package/dist/types/src/internal/proxy/proxy-types.d.ts +18 -0
  227. package/dist/types/src/internal/proxy/proxy-types.d.ts.map +1 -0
  228. package/dist/types/src/internal/proxy/proxy-utils.d.ts +47 -0
  229. package/dist/types/src/internal/proxy/proxy-utils.d.ts.map +1 -0
  230. package/dist/types/src/internal/proxy/reactive-array.d.ts +8 -0
  231. package/dist/types/src/internal/proxy/reactive-array.d.ts.map +1 -0
  232. package/dist/types/src/internal/proxy/reactive.d.ts +39 -0
  233. package/dist/types/src/internal/proxy/reactive.d.ts.map +1 -0
  234. package/dist/types/src/internal/proxy/schema-validator.d.ts +15 -0
  235. package/dist/types/src/internal/proxy/schema-validator.d.ts.map +1 -0
  236. package/dist/types/src/internal/proxy/symbols.d.ts +3 -0
  237. package/dist/types/src/internal/proxy/symbols.d.ts.map +1 -0
  238. package/dist/types/src/internal/proxy/typed-handler.d.ts +16 -12
  239. package/dist/types/src/internal/proxy/typed-handler.d.ts.map +1 -1
  240. package/dist/types/src/internal/ref/ref-array.d.ts +4 -4
  241. package/dist/types/src/internal/ref/ref-array.d.ts.map +1 -1
  242. package/dist/types/src/internal/ref/ref.d.ts +43 -18
  243. package/dist/types/src/internal/ref/ref.d.ts.map +1 -1
  244. package/dist/types/src/internal/schema/compose.d.ts +7 -0
  245. package/dist/types/src/internal/schema/compose.d.ts.map +1 -0
  246. package/dist/types/src/internal/schema/compose.test.d.ts.map +1 -0
  247. package/dist/types/src/internal/schema/echo-schema.d.ts +25 -12
  248. package/dist/types/src/internal/schema/echo-schema.d.ts.map +1 -1
  249. package/dist/types/src/internal/schema/index.d.ts +1 -4
  250. package/dist/types/src/internal/schema/index.d.ts.map +1 -1
  251. package/dist/types/src/internal/schema/persistent-schema.d.ts +20 -0
  252. package/dist/types/src/internal/schema/persistent-schema.d.ts.map +1 -0
  253. package/dist/types/src/internal/types/base.d.ts +26 -0
  254. package/dist/types/src/internal/types/base.d.ts.map +1 -0
  255. package/dist/types/src/internal/types/entity.d.ts +37 -0
  256. package/dist/types/src/internal/types/entity.d.ts.map +1 -0
  257. package/dist/types/src/internal/types/index.d.ts +5 -2
  258. package/dist/types/src/internal/types/index.d.ts.map +1 -1
  259. package/dist/types/src/internal/{object → types}/meta.d.ts +17 -16
  260. package/dist/types/src/internal/types/meta.d.ts.map +1 -0
  261. package/dist/types/src/internal/types/typename.d.ts +21 -0
  262. package/dist/types/src/internal/types/typename.d.ts.map +1 -0
  263. package/dist/types/src/internal/{object → types}/version.d.ts +3 -2
  264. package/dist/types/src/internal/types/version.d.ts.map +1 -0
  265. package/dist/types/src/{test → testing}/api.test.d.ts.map +1 -1
  266. package/dist/types/src/testing/index.d.ts +3 -3
  267. package/dist/types/src/testing/index.d.ts.map +1 -1
  268. package/dist/types/src/testing/test-data.d.ts +18 -0
  269. package/dist/types/src/testing/test-data.d.ts.map +1 -0
  270. package/dist/types/src/testing/test-schema.d.ts +303 -0
  271. package/dist/types/src/testing/test-schema.d.ts.map +1 -0
  272. package/dist/types/src/testing/util.d.ts +21 -0
  273. package/dist/types/src/testing/util.d.ts.map +1 -0
  274. package/dist/types/tsconfig.tsbuildinfo +1 -1
  275. package/package.json +101 -65
  276. package/src/Annotation.ts +45 -0
  277. package/src/Database.ts +353 -0
  278. package/src/Entity.test.ts +22 -0
  279. package/src/Entity.ts +217 -0
  280. package/src/{errors.ts → Err.ts} +2 -2
  281. package/src/Filter.ts +376 -0
  282. package/src/Format.ts +9 -0
  283. package/src/Hypergraph.ts +74 -0
  284. package/src/JsonSchema.ts +16 -0
  285. package/src/Key.ts +3 -0
  286. package/src/Obj.test.ts +412 -0
  287. package/src/Obj.ts +492 -273
  288. package/src/Order.ts +44 -0
  289. package/src/Query.test.ts +465 -0
  290. package/src/Query.ts +324 -0
  291. package/src/QueryResult.ts +106 -0
  292. package/src/Ref.ts +26 -9
  293. package/src/Relation.test.ts +82 -0
  294. package/src/Relation.ts +414 -61
  295. package/src/SchemaRegistry.ts +105 -0
  296. package/src/{query/tag.ts → Tag.ts} +10 -7
  297. package/src/Type.test.ts +52 -0
  298. package/src/Type.ts +361 -114
  299. package/src/hierarchy.test.ts +33 -0
  300. package/src/index.ts +16 -6
  301. package/src/internal/README.md +102 -0
  302. package/src/internal/{ast → annotations}/annotations.test.ts +18 -20
  303. package/src/internal/annotations/annotations.ts +487 -0
  304. package/src/internal/annotations/index.ts +6 -0
  305. package/src/internal/annotations/util.ts +85 -0
  306. package/src/internal/api/annotations.ts +60 -0
  307. package/src/internal/api/entity.ts +29 -0
  308. package/src/internal/api/index.ts +19 -0
  309. package/src/internal/api/meta.ts +88 -0
  310. package/src/internal/api/sorting.ts +53 -0
  311. package/src/internal/api/version.ts +96 -0
  312. package/src/internal/entities/entity.ts +126 -0
  313. package/src/internal/entities/index.ts +9 -0
  314. package/src/internal/entities/model.ts +138 -0
  315. package/src/internal/entities/object.ts +58 -0
  316. package/src/internal/entities/relation.ts +171 -0
  317. package/src/internal/entities/util.ts +33 -0
  318. package/src/internal/formats/date.test.ts +1 -1
  319. package/src/internal/formats/date.ts +5 -5
  320. package/src/internal/formats/format.test.ts +6 -6
  321. package/src/internal/formats/format.ts +8 -6
  322. package/src/internal/formats/number.ts +5 -5
  323. package/src/internal/formats/object.ts +4 -4
  324. package/src/internal/formats/select.ts +6 -4
  325. package/src/internal/formats/string.ts +14 -9
  326. package/src/internal/formats/types.ts +53 -42
  327. package/src/internal/index.ts +30 -13
  328. package/src/internal/{json → json-schema}/annotations.ts +1 -1
  329. package/src/internal/json-schema/index.ts +2 -0
  330. package/src/internal/json-schema/json-schema-normalize.ts +4 -2
  331. package/src/internal/json-schema/json-schema-type.ts +35 -35
  332. package/src/internal/{json → json-schema}/json-schema.test.ts +73 -69
  333. package/src/internal/{json → json-schema}/json-schema.ts +27 -14
  334. package/src/internal/object/clone.ts +48 -0
  335. package/src/internal/object/common.ts +3 -4
  336. package/src/internal/object/{create.test.ts → create-object.test.ts} +31 -33
  337. package/src/internal/object/{create.ts → create-object.ts} +36 -37
  338. package/src/internal/object/deleted.ts +6 -6
  339. package/src/internal/object/ids.ts +1 -1
  340. package/src/internal/object/index.ts +6 -11
  341. package/src/internal/object/inspect.ts +5 -7
  342. package/src/internal/object/json-serializer.test.ts +36 -37
  343. package/src/internal/object/json-serializer.ts +74 -102
  344. package/src/internal/object/schema-validator.test.ts +3 -7
  345. package/src/internal/object/schema-validator.ts +2 -237
  346. package/src/internal/object/set-value.test.ts +281 -0
  347. package/src/internal/object/set-value.ts +165 -0
  348. package/src/internal/object/snapshot.ts +93 -0
  349. package/src/internal/object/typed-object.test.ts +11 -11
  350. package/src/internal/object/typed-object.ts +8 -66
  351. package/src/internal/proxy/change-context.ts +138 -0
  352. package/src/internal/proxy/change.test.ts +519 -0
  353. package/src/internal/proxy/define-hidden-property.ts +14 -0
  354. package/src/internal/proxy/errors.ts +42 -0
  355. package/src/internal/proxy/event-batch.ts +44 -0
  356. package/src/internal/proxy/handler.test.ts +51 -91
  357. package/src/internal/proxy/index.ts +17 -0
  358. package/src/internal/proxy/json-serializer.ts +87 -0
  359. package/src/internal/proxy/make-object.ts +106 -0
  360. package/src/internal/proxy/ownership.ts +253 -0
  361. package/src/internal/proxy/proxy-types.ts +23 -0
  362. package/src/internal/proxy/proxy-utils.ts +150 -0
  363. package/src/internal/proxy/reactive-array.ts +71 -0
  364. package/src/internal/proxy/reactive.ts +69 -0
  365. package/src/internal/proxy/schema-validator.ts +244 -0
  366. package/src/internal/proxy/schema.test.ts +27 -18
  367. package/src/internal/proxy/symbols.ts +7 -0
  368. package/src/internal/proxy/typed-handler.test.ts +260 -48
  369. package/src/internal/proxy/typed-handler.ts +283 -61
  370. package/src/internal/proxy/typed-object.test.ts +54 -38
  371. package/src/internal/ref/ref-array.ts +4 -4
  372. package/src/internal/ref/ref.test.ts +10 -9
  373. package/src/internal/ref/ref.ts +107 -56
  374. package/src/internal/{projection → schema}/compose.test.ts +8 -9
  375. package/src/internal/{projection → schema}/compose.ts +13 -8
  376. package/src/internal/schema/echo-schema.ts +74 -33
  377. package/src/internal/schema/index.ts +1 -4
  378. package/src/internal/schema/manipulation.ts +1 -1
  379. package/src/internal/schema/persistent-schema.ts +28 -0
  380. package/src/internal/types/base.ts +43 -0
  381. package/src/internal/types/entity.ts +54 -0
  382. package/src/internal/types/index.ts +5 -2
  383. package/src/internal/types/meta.ts +65 -0
  384. package/src/internal/types/typename.ts +55 -0
  385. package/src/internal/types/version.ts +20 -0
  386. package/src/testing/api.test.ts +126 -0
  387. package/src/testing/index.ts +3 -3
  388. package/src/testing/test-data.ts +130 -0
  389. package/src/testing/test-schema.ts +238 -0
  390. package/src/testing/util.ts +85 -0
  391. package/dist/lib/browser/chunk-HKFCK2GL.mjs +0 -175
  392. package/dist/lib/browser/chunk-HKFCK2GL.mjs.map +0 -7
  393. package/dist/lib/browser/chunk-MAAYELT7.mjs +0 -830
  394. package/dist/lib/browser/chunk-MAAYELT7.mjs.map +0 -7
  395. package/dist/lib/browser/chunk-MB6MMNFP.mjs +0 -3857
  396. package/dist/lib/browser/chunk-MB6MMNFP.mjs.map +0 -7
  397. package/dist/lib/browser/index.mjs +0 -35
  398. package/dist/lib/browser/internal/index.mjs +0 -332
  399. package/dist/lib/browser/meta.json +0 -1
  400. package/dist/lib/browser/query/index.mjs +0 -15
  401. package/dist/lib/browser/testing/index.mjs +0 -298
  402. package/dist/lib/browser/testing/index.mjs.map +0 -7
  403. package/dist/lib/node-esm/chunk-5NWDGIBT.mjs +0 -830
  404. package/dist/lib/node-esm/chunk-5NWDGIBT.mjs.map +0 -7
  405. package/dist/lib/node-esm/chunk-AUAH4E2J.mjs +0 -175
  406. package/dist/lib/node-esm/chunk-AUAH4E2J.mjs.map +0 -7
  407. package/dist/lib/node-esm/chunk-BQRA4VLX.mjs +0 -3857
  408. package/dist/lib/node-esm/chunk-BQRA4VLX.mjs.map +0 -7
  409. package/dist/lib/node-esm/index.mjs +0 -35
  410. package/dist/lib/node-esm/meta.json +0 -1
  411. package/dist/lib/node-esm/query/index.mjs +0 -15
  412. package/dist/lib/node-esm/testing/index.mjs +0 -298
  413. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  414. package/dist/types/src/errors.d.ts.map +0 -1
  415. package/dist/types/src/internal/ast/annotation-helper.d.ts +0 -8
  416. package/dist/types/src/internal/ast/annotation-helper.d.ts.map +0 -1
  417. package/dist/types/src/internal/ast/annotations.d.ts +0 -125
  418. package/dist/types/src/internal/ast/annotations.d.ts.map +0 -1
  419. package/dist/types/src/internal/ast/annotations.test.d.ts.map +0 -1
  420. package/dist/types/src/internal/ast/entity-kind.d.ts +0 -10
  421. package/dist/types/src/internal/ast/entity-kind.d.ts.map +0 -1
  422. package/dist/types/src/internal/ast/index.d.ts +0 -5
  423. package/dist/types/src/internal/ast/index.d.ts.map +0 -1
  424. package/dist/types/src/internal/ast/types.d.ts +0 -6
  425. package/dist/types/src/internal/ast/types.d.ts.map +0 -1
  426. package/dist/types/src/internal/json/annotations.d.ts.map +0 -1
  427. package/dist/types/src/internal/json/effect-schema.test.d.ts.map +0 -1
  428. package/dist/types/src/internal/json/index.d.ts +0 -2
  429. package/dist/types/src/internal/json/index.d.ts.map +0 -1
  430. package/dist/types/src/internal/json/json-schema.d.ts.map +0 -1
  431. package/dist/types/src/internal/json/json-schema.test.d.ts.map +0 -1
  432. package/dist/types/src/internal/object/accessors.d.ts +0 -37
  433. package/dist/types/src/internal/object/accessors.d.ts.map +0 -1
  434. package/dist/types/src/internal/object/create.d.ts.map +0 -1
  435. package/dist/types/src/internal/object/create.test.d.ts +0 -2
  436. package/dist/types/src/internal/object/create.test.d.ts.map +0 -1
  437. package/dist/types/src/internal/object/entity.d.ts +0 -33
  438. package/dist/types/src/internal/object/entity.d.ts.map +0 -1
  439. package/dist/types/src/internal/object/expando.d.ts +0 -14
  440. package/dist/types/src/internal/object/expando.d.ts.map +0 -1
  441. package/dist/types/src/internal/object/meta.d.ts.map +0 -1
  442. package/dist/types/src/internal/object/model.d.ts +0 -117
  443. package/dist/types/src/internal/object/model.d.ts.map +0 -1
  444. package/dist/types/src/internal/object/relation.d.ts +0 -17
  445. package/dist/types/src/internal/object/relation.d.ts.map +0 -1
  446. package/dist/types/src/internal/object/typename.d.ts +0 -15
  447. package/dist/types/src/internal/object/typename.d.ts.map +0 -1
  448. package/dist/types/src/internal/object/version.d.ts.map +0 -1
  449. package/dist/types/src/internal/projection/compose.d.ts +0 -6
  450. package/dist/types/src/internal/projection/compose.d.ts.map +0 -1
  451. package/dist/types/src/internal/projection/compose.test.d.ts.map +0 -1
  452. package/dist/types/src/internal/projection/index.d.ts +0 -2
  453. package/dist/types/src/internal/projection/index.d.ts.map +0 -1
  454. package/dist/types/src/internal/proxy/reactive-object.d.ts +0 -15
  455. package/dist/types/src/internal/proxy/reactive-object.d.ts.map +0 -1
  456. package/dist/types/src/internal/query/index.d.ts +0 -2
  457. package/dist/types/src/internal/query/index.d.ts.map +0 -1
  458. package/dist/types/src/internal/query/query.d.ts +0 -17
  459. package/dist/types/src/internal/query/query.d.ts.map +0 -1
  460. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts +0 -18
  461. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts.map +0 -1
  462. package/dist/types/src/internal/schema/snapshot.d.ts +0 -6
  463. package/dist/types/src/internal/schema/snapshot.d.ts.map +0 -1
  464. package/dist/types/src/internal/schema/stored-schema.d.ts +0 -13
  465. package/dist/types/src/internal/schema/stored-schema.d.ts.map +0 -1
  466. package/dist/types/src/internal/testing/index.d.ts +0 -3
  467. package/dist/types/src/internal/testing/index.d.ts.map +0 -1
  468. package/dist/types/src/internal/testing/types.d.ts +0 -455
  469. package/dist/types/src/internal/testing/types.d.ts.map +0 -1
  470. package/dist/types/src/internal/testing/utils.d.ts +0 -10
  471. package/dist/types/src/internal/testing/utils.d.ts.map +0 -1
  472. package/dist/types/src/internal/types/types.d.ts +0 -79
  473. package/dist/types/src/internal/types/types.d.ts.map +0 -1
  474. package/dist/types/src/internal/types/types.test.d.ts +0 -2
  475. package/dist/types/src/internal/types/types.test.d.ts.map +0 -1
  476. package/dist/types/src/internal/types/util.d.ts +0 -5
  477. package/dist/types/src/internal/types/util.d.ts.map +0 -1
  478. package/dist/types/src/query/index.d.ts +0 -3
  479. package/dist/types/src/query/index.d.ts.map +0 -1
  480. package/dist/types/src/query/query.d.ts +0 -248
  481. package/dist/types/src/query/query.d.ts.map +0 -1
  482. package/dist/types/src/query/query.test.d.ts +0 -2
  483. package/dist/types/src/query/query.test.d.ts.map +0 -1
  484. package/dist/types/src/query/tag.d.ts +0 -17
  485. package/dist/types/src/query/tag.d.ts.map +0 -1
  486. package/dist/types/src/testing/echo-schema.d.ts +0 -7
  487. package/dist/types/src/testing/echo-schema.d.ts.map +0 -1
  488. package/dist/types/src/testing/types.d.ts +0 -113
  489. package/dist/types/src/testing/types.d.ts.map +0 -1
  490. package/src/internal/ast/annotation-helper.ts +0 -22
  491. package/src/internal/ast/annotations.ts +0 -219
  492. package/src/internal/ast/entity-kind.ts +0 -15
  493. package/src/internal/ast/index.ts +0 -8
  494. package/src/internal/ast/types.ts +0 -17
  495. package/src/internal/json/index.ts +0 -5
  496. package/src/internal/object/accessors.ts +0 -153
  497. package/src/internal/object/entity.ts +0 -248
  498. package/src/internal/object/expando.ts +0 -21
  499. package/src/internal/object/meta.ts +0 -61
  500. package/src/internal/object/model.ts +0 -170
  501. package/src/internal/object/relation.ts +0 -24
  502. package/src/internal/object/typename.ts +0 -61
  503. package/src/internal/object/version.ts +0 -22
  504. package/src/internal/projection/index.ts +0 -5
  505. package/src/internal/proxy/reactive-object.ts +0 -108
  506. package/src/internal/query/index.ts +0 -5
  507. package/src/internal/query/query.ts +0 -23
  508. package/src/internal/schema/runtime-schema-registry.ts +0 -78
  509. package/src/internal/schema/snapshot.ts +0 -25
  510. package/src/internal/schema/stored-schema.ts +0 -26
  511. package/src/internal/testing/index.ts +0 -6
  512. package/src/internal/testing/types.ts +0 -211
  513. package/src/internal/testing/utils.ts +0 -54
  514. package/src/internal/types/types.test.ts +0 -48
  515. package/src/internal/types/types.ts +0 -176
  516. package/src/internal/types/util.ts +0 -9
  517. package/src/query/index.ts +0 -6
  518. package/src/query/query.test.ts +0 -401
  519. package/src/query/query.ts +0 -789
  520. package/src/test/api.test.ts +0 -180
  521. package/src/testing/echo-schema.ts +0 -39
  522. package/src/testing/types.ts +0 -91
  523. /package/dist/lib/{browser/index.mjs.map → neutral/Annotation.mjs.map} +0 -0
  524. /package/dist/lib/{browser/internal/index.mjs.map → neutral/Database.mjs.map} +0 -0
  525. /package/dist/lib/{browser/query/index.mjs.map → neutral/Entity.mjs.map} +0 -0
  526. /package/dist/lib/{node-esm/index.mjs.map → neutral/Err.mjs.map} +0 -0
  527. /package/dist/lib/{node-esm/internal/index.mjs.map → neutral/Filter.mjs.map} +0 -0
  528. /package/dist/lib/{node-esm/query/index.mjs.map → neutral/Format.mjs.map} +0 -0
  529. /package/dist/types/src/internal/{ast → annotations}/annotations.test.d.ts +0 -0
  530. /package/dist/types/src/internal/{json → json-schema}/annotations.d.ts +0 -0
  531. /package/dist/types/src/internal/{json → json-schema}/effect-schema.test.d.ts +0 -0
  532. /package/dist/types/src/internal/{json → json-schema}/json-schema.test.d.ts +0 -0
  533. /package/dist/types/src/internal/{projection → schema}/compose.test.d.ts +0 -0
  534. /package/dist/types/src/{test → testing}/api.test.d.ts +0 -0
  535. /package/src/internal/{json → json-schema}/effect-schema.test.ts +0 -0
@@ -7,24 +7,35 @@ import { type InspectOptionsStylized } from 'node:util';
7
7
  import * as Schema from 'effect/Schema';
8
8
  import * as SchemaAST from 'effect/SchemaAST';
9
9
 
10
+ import { Event } from '@dxos/async';
10
11
  import { inspectCustom } from '@dxos/debug';
11
- import { type GenericSignal, compositeRuntime } from '@dxos/echo-signals/runtime';
12
12
  import { invariant } from '@dxos/invariant';
13
- import {
14
- ReactiveArray,
15
- type ReactiveHandler,
16
- createProxy,
17
- defineHiddenProperty,
18
- isValidProxyTarget,
19
- objectData,
20
- symbolIsProxy,
21
- } from '@dxos/live-object';
22
13
 
23
- import { getSchemaDXN } from '../ast';
24
- import { DeletedId, SchemaId, SchemaValidator, TypeId } from '../object';
14
+ import { getSchemaDXN } from '../annotations';
15
+ import { ObjectDeletedId } from '../entities';
16
+ import { ParentId, SchemaId, TypeId } from '../types';
25
17
 
26
- const symbolSignal = Symbol('signal');
27
- const symbolPropertySignal = Symbol('property-signal');
18
+ import { executeChange, isInChangeContext, queueNotification } from './change-context';
19
+ import { defineHiddenProperty } from './define-hidden-property';
20
+ import { createPropertyDeleteError } from './errors';
21
+ import { batchEvents } from './event-batch';
22
+ import {
23
+ getEchoRoot,
24
+ getOwner,
25
+ getRawTarget,
26
+ hasForeignOwner,
27
+ notifyOwnerChain,
28
+ setOwnerRecursive,
29
+ wouldCreateCycle,
30
+ } from './ownership';
31
+ import { type ReactiveHandler, objectData } from './proxy-types';
32
+ import { createProxy, isProxy, isValidProxyTarget, symbolIsProxy } from './proxy-utils';
33
+ import { ReactiveArray } from './reactive-array';
34
+ import { SchemaValidator } from './schema-validator';
35
+ import { ChangeId, EventId } from './symbols';
36
+
37
+ // Re-export for external consumers.
38
+ export { getEchoRoot, setMetaOwner } from './ownership';
28
39
 
29
40
  type ProxyTarget = {
30
41
  /**
@@ -36,26 +47,100 @@ type ProxyTarget = {
36
47
  * Schema for the root.
37
48
  */
38
49
  [SchemaId]: Schema.Schema.AnyNoContext;
50
+ [ParentId]?: any;
39
51
 
40
52
  /**
41
- * For get and set operations on value properties.
42
- */
43
- // TODO(dmaretskyi): Turn into a map of signals per-field.
44
- [symbolSignal]: GenericSignal;
45
-
46
- /**
47
- * For modifying the structure of the object.
53
+ * For modifications.
48
54
  */
49
- [symbolPropertySignal]: GenericSignal;
55
+ [EventId]: Event<void>;
50
56
  } & ({ [key: keyof any]: any } | any[]);
51
57
 
58
+ /**
59
+ * Deep copy a value, handling arrays and nested objects.
60
+ * Preserves ReactiveArray type and hidden properties (SchemaId, TypeId).
61
+ * Does not copy class instances or functions (except ReactiveArray).
62
+ *
63
+ * Note: Cannot use structuredClone because we need to:
64
+ * - Unwrap proxies
65
+ * - Preserve ReactiveArray instances
66
+ * - Copy Symbol-keyed hidden properties (SchemaId, TypeId)
67
+ * - Convert plain arrays to ReactiveArray
68
+ *
69
+ * Performance: O(n) where n is the total number of nested objects/arrays.
70
+ * For large structures, consider using Refs for frequently reassigned subtrees.
71
+ */
72
+ const deepCopy = <T>(value: T, visited = new Map<object, object>()): T => {
73
+ if (value == null || typeof value !== 'object') {
74
+ return value;
75
+ }
76
+
77
+ // Handle proxies - get the underlying target.
78
+ const actualValue = getRawTarget(value);
79
+
80
+ // Check for circular references in the copy.
81
+ if (visited.has(actualValue)) {
82
+ return visited.get(actualValue) as T;
83
+ }
84
+
85
+ // Handle ReactiveArray specially to preserve reactivity.
86
+ if (actualValue instanceof ReactiveArray) {
87
+ const copy = new ReactiveArray<any>();
88
+ visited.set(actualValue, copy);
89
+ for (const item of actualValue) {
90
+ copy.push(deepCopy(item, visited));
91
+ }
92
+ // Copy hidden properties.
93
+ copyHiddenProperties(actualValue, copy);
94
+ return copy as T;
95
+ }
96
+
97
+ // Don't copy other class instances (objects with non-Object prototype).
98
+ const proto = Object.getPrototypeOf(actualValue);
99
+ if (proto !== Object.prototype && proto !== Array.prototype && proto !== null) {
100
+ return value; // Return as-is, don't copy class instances.
101
+ }
102
+
103
+ if (Array.isArray(actualValue)) {
104
+ // Plain arrays become ReactiveArrays.
105
+ const copy = new ReactiveArray<any>();
106
+ visited.set(actualValue, copy);
107
+ for (const item of actualValue) {
108
+ copy.push(deepCopy(item, visited));
109
+ }
110
+ return copy as T;
111
+ }
112
+
113
+ const copy: Record<string, any> = {};
114
+ visited.set(actualValue, copy);
115
+ for (const key of Object.keys(actualValue)) {
116
+ copy[key] = deepCopy((actualValue as any)[key], visited);
117
+ }
118
+ // Copy hidden properties (SchemaId, TypeId).
119
+ copyHiddenProperties(actualValue, copy);
120
+ return copy as T;
121
+ };
122
+
123
+ /**
124
+ * Copy hidden properties (SchemaId, TypeId) from source to target.
125
+ */
126
+ const copyHiddenProperties = (source: any, target: any): void => {
127
+ if (SchemaId in source) {
128
+ defineHiddenProperty(target, SchemaId, source[SchemaId]);
129
+ }
130
+ if (TypeId in source) {
131
+ defineHiddenProperty(target, TypeId, source[TypeId]);
132
+ }
133
+ };
134
+
52
135
  /**
53
136
  * Typed in-memory reactive store (with Schema).
137
+ * Reactivity is based on Event subscriptions, not signals.
54
138
  */
55
139
  export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
56
140
  public static readonly instance: ReactiveHandler<any> = new TypedReactiveHandler();
57
141
 
58
142
  readonly _proxyMap = new WeakMap<object, any>();
143
+ private _inSet = false;
59
144
 
60
145
  private constructor() {}
61
146
 
@@ -63,21 +148,44 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
63
148
  invariant(typeof target === 'object' && target !== null);
64
149
  invariant(SchemaId in target, 'Schema is not defined for the target');
65
150
 
66
- if (!(symbolSignal in target)) {
67
- defineHiddenProperty(target, symbolSignal, compositeRuntime.createSignal());
68
- defineHiddenProperty(target, symbolPropertySignal, compositeRuntime.createSignal());
151
+ // Only set EventId on root objects (those without an owner).
152
+ // Nested objects share their root's EventId for centralized reactivity.
153
+ const hasOwner = !!getOwner(target);
154
+ if (!(EventId in target) && !hasOwner) {
155
+ defineHiddenProperty(target, EventId, new Event());
69
156
  }
70
157
 
71
- defineHiddenProperty(target, DeletedId, false);
158
+ defineHiddenProperty(target, ObjectDeletedId, false);
72
159
 
73
- for (const key of Object.getOwnPropertyNames(target)) {
74
- const descriptor = Object.getOwnPropertyDescriptor(target, key)!;
75
- if (descriptor.get) {
76
- // Ignore getters.
77
- continue;
78
- }
160
+ // Mark root objects as having a change handler.
161
+ // The actual handler is returned dynamically in get() to have access to the proxy.
162
+ if (!hasOwner && !(ChangeId in target)) {
163
+ defineHiddenProperty(target, ChangeId, true);
164
+ }
79
165
 
80
- // Array reactivity is already handled by the schema validator.
166
+ // Only set owners if this is a root object (no existing owner).
167
+ // Nested objects already have owners set by their root's initialization.
168
+ // If we re-set owners here for nested objects, we'd incorrectly point
169
+ // array elements to the array instead of the true root ECHO object.
170
+ if (!hasOwner) {
171
+ // Set owner on all nested objects to this root ECHO object.
172
+ // All nested records point directly to this root for centralized reactivity.
173
+ for (const key in target) {
174
+ if ((target as any)[symbolIsProxy]) {
175
+ continue;
176
+ }
177
+ let value = (target as any)[key];
178
+ if (isValidProxyTarget(value) || isProxy(value)) {
179
+ // Deep copy values that have foreign owners (owned by a different object,
180
+ // or are root ECHO objects whose nested structures would be owned by them).
181
+ // This recursively checks all nested objects.
182
+ if (hasForeignOwner(value, target)) {
183
+ value = deepCopy(value);
184
+ (target as any)[key] = value;
185
+ }
186
+ setOwnerRecursive(value, target);
187
+ }
188
+ }
81
189
  }
82
190
 
83
191
  // Maybe have been set by `create`.
@@ -90,23 +198,26 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
90
198
 
91
199
  get(target: ProxyTarget, prop: string | symbol, receiver: any): any {
92
200
  switch (prop) {
201
+ // TODO(burdon): Remove?
93
202
  case objectData: {
94
- target[symbolSignal].notifyRead();
95
203
  return toJSON(target);
96
204
  }
205
+ case ChangeId: {
206
+ // Return change handler only for root objects that have been marked with ChangeId.
207
+ if ((target as any)[ChangeId] !== true) {
208
+ return undefined;
209
+ }
210
+ // Return a function that allows mutations within a controlled context.
211
+ // Uses target as both the context key and event target for non-database objects.
212
+ return (callback: (obj: any) => void) => executeChange(target, target, receiver, callback);
213
+ }
97
214
  }
98
215
 
99
- // Handle getter properties. Will not subscribe the value signal.
216
+ // Handle getter properties.
100
217
  if (Object.getOwnPropertyDescriptor(target, prop)?.get) {
101
- target[symbolPropertySignal].notifyRead();
102
-
103
- // TODO(dmaretskyi): Turn getters into computed fields.
104
218
  return Reflect.get(target, prop, receiver);
105
219
  }
106
220
 
107
- target[symbolSignal].notifyRead();
108
- target[symbolPropertySignal].notifyRead();
109
-
110
221
  const value = Reflect.get(target, prop, receiver);
111
222
  if (isValidProxyTarget(value)) {
112
223
  return createProxy(value, this);
@@ -116,43 +227,152 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
116
227
  }
117
228
 
118
229
  set(target: ProxyTarget, prop: string | symbol, value: any, receiver: any): boolean {
119
- // Convert arrays to reactive arrays on write.
120
- if (Array.isArray(value)) {
121
- value = ReactiveArray.from(value);
230
+ const echoRoot = getEchoRoot(target);
231
+
232
+ // Check readonly enforcement - mutations only allowed within Obj.change().
233
+ // Skip check if the object is still being initialized (no ChangeId handler yet).
234
+ // Also skip for non-initialized root objects (those without EventId).
235
+ // Skip for symbol properties (internal infrastructure, not user data).
236
+ const isInitialized = ChangeId in echoRoot || EventId in echoRoot;
237
+ const isSymbolProp = typeof prop === 'symbol';
238
+ if (isInitialized && !isSymbolProp && !isInChangeContext(echoRoot)) {
239
+ throw new Error(
240
+ `Cannot modify object property "${String(prop)}" outside of Obj.change(). ` +
241
+ 'Use Obj.change(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
242
+ );
122
243
  }
123
244
 
124
245
  let result: boolean = false;
125
- compositeRuntime.batch(() => {
126
- const validatedValue = this._validateValue(target, prop, value);
127
- result = Reflect.set(target, prop, validatedValue, receiver);
128
- target[symbolSignal].notifyWrite();
129
- });
246
+ this._inSet = true;
247
+ try {
248
+ batchEvents(() => {
249
+ const { echoRoot: _, preparedValue } = this._prepareValueForAssignment(target, prop, value);
250
+ result = Reflect.set(target, prop, preparedValue, receiver);
251
+ // Queue notification instead of emitting immediately (batched).
252
+ if (isInitialized) {
253
+ queueNotification(echoRoot);
254
+ // Also notify the owner chain so parent objects are updated when nested objects change.
255
+ notifyOwnerChain(target);
256
+ }
257
+ });
258
+ } finally {
259
+ this._inSet = false;
260
+ }
130
261
  return result;
131
262
  }
132
263
 
133
264
  ownKeys(target: ProxyTarget): ArrayLike<string | symbol> {
134
- // Touch both signals since `set` and `delete` operations may create or remove properties.
135
- target[symbolSignal].notifyRead();
136
- target[symbolPropertySignal].notifyRead();
137
265
  return Reflect.ownKeys(target);
138
266
  }
139
267
 
268
+ deleteProperty(target: ProxyTarget, property: string | symbol): boolean {
269
+ const echoRoot = getEchoRoot(target);
270
+
271
+ // Check readonly enforcement - mutations only allowed within Obj.change().
272
+ // Skip for symbol properties (internal infrastructure, not user data).
273
+ const isInitialized = (echoRoot as any)[ChangeId] === true || EventId in echoRoot;
274
+ const isSymbolProp = typeof property === 'symbol';
275
+ if (isInitialized && !isSymbolProp && !isInChangeContext(echoRoot)) {
276
+ throw createPropertyDeleteError(property);
277
+ }
278
+
279
+ const result = Reflect.deleteProperty(target, property);
280
+ if (isInitialized) {
281
+ queueNotification(echoRoot);
282
+ }
283
+ return result;
284
+ }
285
+
140
286
  defineProperty(target: ProxyTarget, property: string | symbol, attributes: PropertyDescriptor): boolean {
141
- const validatedValue = this._validateValue(target, property, attributes.value);
287
+ const echoRoot = getEchoRoot(target);
288
+
289
+ // Check readonly enforcement - mutations only allowed within Obj.change().
290
+ // Skip check if the object is still being initialized (no ChangeId handler yet).
291
+ // Skip for symbol properties (internal infrastructure, not user data).
292
+ const isInitialized = ChangeId in echoRoot || EventId in echoRoot;
293
+ const isSymbolProp = typeof property === 'symbol';
294
+ if (isInitialized && !isSymbolProp && !isInChangeContext(echoRoot)) {
295
+ throw new Error(
296
+ `Cannot modify object property "${String(property)}" outside of Obj.change(). ` +
297
+ 'Use Obj.change(obj, (mutableObj) => { mutableObj.property = value; }) instead.',
298
+ );
299
+ }
300
+
301
+ const { echoRoot: _, preparedValue } = this._prepareValueForAssignment(target, property, attributes.value);
142
302
  const result = Reflect.defineProperty(target, property, {
143
303
  ...attributes,
144
- value: validatedValue,
304
+ value: preparedValue,
145
305
  });
146
- target[symbolPropertySignal].notifyWrite();
306
+ if (!this._inSet && isInitialized) {
307
+ // Queue notification instead of emitting immediately (batched).
308
+ queueNotification(echoRoot);
309
+ }
147
310
  return result;
148
311
  }
149
312
 
313
+ /**
314
+ * Prepare a value for assignment to a typed object property.
315
+ * Handles cycle detection, copy-on-assign, array conversion, validation, and ownership.
316
+ */
317
+ private _prepareValueForAssignment(
318
+ target: ProxyTarget,
319
+ prop: string | symbol,
320
+ value: any,
321
+ ): { echoRoot: object; preparedValue: any } {
322
+ const echoRoot = getEchoRoot(target);
323
+
324
+ if (prop === ParentId) {
325
+ return { echoRoot, preparedValue: value }; // Short-circuit for parent assignment.
326
+ }
327
+
328
+ // Check for cycles before assignment.
329
+ if (isValidProxyTarget(value) || isProxy(value)) {
330
+ if (wouldCreateCycle(echoRoot, value)) {
331
+ throw new Error('Cannot create cycles in typed object graph. Consider using Ref for circular references.');
332
+ }
333
+ }
334
+
335
+ // Prevent direct assignment of root ECHO objects (those created with Obj.make/Relation.make).
336
+ // These must be wrapped with Ref.make for proper reference handling.
337
+ // This matches database object behavior for consistency.
338
+ if (isValidProxyTarget(value) || isProxy(value)) {
339
+ const actualValue = getRawTarget(value);
340
+ const isRootEchoObject = EventId in actualValue;
341
+ if (isRootEchoObject) {
342
+ throw new Error('Object references must be wrapped with `Ref.make`');
343
+ }
344
+ }
345
+
346
+ // Copy-on-assign: If the value is a nested record owned by a different ECHO object, deep copy it.
347
+ if (isValidProxyTarget(value) || isProxy(value)) {
348
+ const actualValue = getRawTarget(value);
349
+ const existingOwner = getOwner(actualValue);
350
+ if (existingOwner != null && existingOwner !== echoRoot) {
351
+ value = deepCopy(value);
352
+ }
353
+ }
354
+
355
+ // Convert arrays to reactive arrays.
356
+ if (Array.isArray(value) && !(value instanceof ReactiveArray)) {
357
+ value = ReactiveArray.from(value);
358
+ }
359
+
360
+ const validatedValue = this._validateValue(target, prop, value);
361
+
362
+ // Set owner on new value to the root ECHO object.
363
+ if (isValidProxyTarget(validatedValue) || isProxy(validatedValue)) {
364
+ setOwnerRecursive(validatedValue, echoRoot);
365
+ }
366
+
367
+ return { echoRoot, preparedValue: validatedValue };
368
+ }
369
+
150
370
  private _validateValue(target: any, prop: string | symbol, value: any) {
371
+ if (prop === ParentId) {
372
+ return value;
373
+ }
151
374
  const schema = SchemaValidator.getTargetPropertySchema(target, prop);
152
375
  const _ = Schema.asserts(schema)(value);
153
- if (Array.isArray(value)) {
154
- value = new ReactiveArray(...value);
155
- }
156
376
  if (isValidProxyTarget(value)) {
157
377
  setSchemaProperties(value, schema);
158
378
  }
@@ -165,18 +385,20 @@ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
165
385
  options: InspectOptionsStylized,
166
386
  inspectFn: (value: any, options?: InspectOptionsStylized) => string,
167
387
  ): string {
168
- return `Typed ${inspectFn(this, {
388
+ const inspected = inspectFn(this, {
169
389
  ...options,
170
- compact: true,
171
390
  showHidden: false,
172
391
  customInspect: false,
173
- })}`;
392
+ });
393
+
394
+ return `Typed ${inspected}`;
174
395
  }
175
396
  }
176
397
 
177
398
  /**
178
399
  * @deprecated Use `Obj.toJSON` instead.
179
400
  */
401
+ // TODO(burdon): Remove?
180
402
  const toJSON = (target: ProxyTarget): any => {
181
403
  return { '@type': 'TypedReactiveObject', ...target };
182
404
  };
@@ -3,16 +3,19 @@
3
3
  //
4
4
 
5
5
  import * as Schema from 'effect/Schema';
6
+ import type * as Types from 'effect/Types';
6
7
  import { describe, expect, test } from 'vitest';
7
8
 
8
- import { EchoObject, TypedObject, getSchema } from '..';
9
+ import { EchoObjectSchema } from '../entities';
10
+ import { getSchema } from '../types';
9
11
 
10
- import { live } from './reactive-object';
12
+ import { makeObject } from './make-object';
13
+ import { change } from './reactive';
11
14
 
12
15
  const Organization = Schema.Struct({
13
16
  name: Schema.String,
14
17
  }).pipe(
15
- EchoObject({
18
+ EchoObjectSchema({
16
19
  typename: 'example.com/type/Organization',
17
20
  version: '0.1.0',
18
21
  }),
@@ -24,11 +27,14 @@ const Contact = Schema.Struct(
24
27
  {
25
28
  name: Schema.String,
26
29
  },
27
- { key: Schema.String, value: Schema.Any },
30
+ {
31
+ key: Schema.String,
32
+ value: Schema.Any,
33
+ },
28
34
  ).pipe(
29
35
  Schema.partial,
30
- EchoObject({
31
- typename: 'example.com/type/Contact',
36
+ EchoObjectSchema({
37
+ typename: 'example.com/type/Person',
32
38
  version: '0.1.0',
33
39
  }),
34
40
  );
@@ -37,64 +43,74 @@ interface Contact extends Schema.Schema.Type<typeof Contact> {}
37
43
 
38
44
  const TEST_ORG: Omit<Organization, 'id'> = { name: 'Test' };
39
45
 
40
- describe('EchoObject class DSL', () => {
46
+ describe('EchoObjectSchema class DSL', () => {
41
47
  test('can get object schema', async () => {
42
- const obj = live(Organization, TEST_ORG);
48
+ const obj = makeObject(Organization, TEST_ORG);
43
49
  expect(getSchema(obj)).to.deep.eq(Organization);
44
50
  });
45
51
 
46
52
  describe('class options', () => {
47
53
  test('can assign undefined to partial fields', async () => {
48
- const person = live(Contact, { name: 'John' });
49
- person.name = undefined;
50
- person.recordField = 'hello';
54
+ const person = makeObject(Contact, { name: 'John' });
55
+ change(person, (p) => {
56
+ p.name = undefined;
57
+ p.recordField = 'hello';
58
+ });
51
59
  expect(person.name).to.be.undefined;
52
60
  expect(person.recordField).to.eq('hello');
53
61
  });
54
62
  });
55
63
 
56
64
  test('record', () => {
57
- const schema = Schema.mutable(
58
- Schema.Struct({
59
- meta: Schema.optional(Schema.mutable(Schema.Any)),
60
- // NOTE: Schema.Record only supports shallow values.
61
- // https://www.npmjs.com/package/@effect/schema#mutable-records
62
- // meta: Schema.optional(Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any }))),
63
- // meta: Schema.optional(Schema.mutable(Schema.object)),
64
- }),
65
- );
65
+ const schema = Schema.Struct({
66
+ meta: Schema.optional(Schema.Any),
67
+ // NOTE: Schema.Record only supports shallow values.
68
+ // https://www.npmjs.com/package/@effect/schema#mutable-records
69
+ // meta: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
70
+ // meta: Schema.optional(Schema.object),
71
+ });
66
72
 
67
73
  {
68
- const object = live(schema, {});
69
- (object.meta ??= {}).test = 100;
70
- expect(object.meta.test).to.eq(100);
74
+ const object = makeObject(schema, {});
75
+ change(object, (o) => {
76
+ (o.meta ??= {}).test = 100;
77
+ });
78
+ expect(object.meta!.test).to.eq(100);
71
79
  }
72
80
 
73
81
  {
74
- const object = live(schema, {});
75
- object.meta = { test: { value: 300 } };
76
- expect(object.meta.test.value).to.eq(300);
82
+ const object = makeObject(schema, {});
83
+ change(object, (o) => {
84
+ o.meta = { test: { value: 300 } };
85
+ });
86
+ expect(object.meta!.test.value).to.eq(300);
77
87
  }
78
88
 
79
89
  {
80
- type Test1 = Schema.Schema.Type<typeof schema>;
90
+ // Plain object (not a reactive proxy) - doesn't need Obj.change.
91
+ // Note: Schema.Schema.Type generates readonly types, so we cast to mutable for plain objects.
92
+ type Test1 = Types.Mutable<Schema.Schema.Type<typeof schema>>;
81
93
 
82
94
  const object: Test1 = {};
83
95
  (object.meta ??= {}).test = 100;
84
- expect(object.meta.test).to.eq(100);
96
+ expect(object.meta!.test).to.eq(100);
85
97
  }
86
98
 
87
99
  {
88
- class Test2 extends TypedObject({
89
- typename: 'dxos.org/type/FunctionTrigger',
90
- version: '0.1.0',
91
- })({
92
- meta: Schema.optional(Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any }))),
93
- }) {}
94
-
95
- const object = live(Test2, {});
96
- (object.meta ??= {}).test = 100;
97
- expect(object.meta.test).to.eq(100);
100
+ const Test2 = Schema.Struct({
101
+ meta: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
102
+ }).pipe(
103
+ EchoObjectSchema({
104
+ typename: 'dxos.org/type/FunctionTrigger',
105
+ version: '0.1.0',
106
+ }),
107
+ );
108
+
109
+ const object = makeObject(Test2, {});
110
+ change(object, (o) => {
111
+ (o.meta ??= {}).test = 100;
112
+ });
113
+ expect(object.meta!.test).to.eq(100);
98
114
  }
99
115
  });
100
116
  });
@@ -5,7 +5,7 @@
5
5
  import { type ObjectId } from '@dxos/keys';
6
6
  import { isNonNullable } from '@dxos/util';
7
7
 
8
- import { type AnyEchoObject } from '../types';
8
+ import { type AnyEntity } from '../types';
9
9
 
10
10
  import { Ref } from './ref';
11
11
 
@@ -16,21 +16,21 @@ export const RefArray = Object.freeze({
16
16
  /**
17
17
  * @returns all resolved targets.
18
18
  */
19
- targets: <T extends AnyEchoObject>(refs: readonly Ref<T>[]): T[] => {
19
+ targets: <T extends AnyEntity>(refs: readonly Ref<T>[]): T[] => {
20
20
  return refs.map((ref) => ref.target).filter(isNonNullable);
21
21
  },
22
22
 
23
23
  /**
24
24
  * Load all referenced objects.
25
25
  */
26
- loadAll: <T extends AnyEchoObject>(refs: readonly Ref<T>[]): Promise<T[]> => {
26
+ loadAll: <T extends AnyEntity>(refs: readonly Ref<T>[]): Promise<T[]> => {
27
27
  return Promise.all(refs.map((ref) => ref.load()));
28
28
  },
29
29
 
30
30
  /**
31
31
  * Removes the ref with the given id.
32
32
  */
33
- removeById: (refs: Ref<AnyEchoObject>[], id: ObjectId) => {
33
+ removeById: (refs: Ref<AnyEntity>[], id: ObjectId) => {
34
34
  const index = refs.findIndex(Ref.hasObjectId(id));
35
35
  if (index >= 0) {
36
36
  refs.splice(index, 1);
@@ -7,14 +7,15 @@ import { describe, expect, test } from 'vitest';
7
7
 
8
8
  import { DXN, ObjectId } from '@dxos/keys';
9
9
 
10
- import { EchoObject, create, getObjectDXN } from '../object';
10
+ import { EchoObjectSchema, getObjectDXN } from '../entities';
11
+ import { createObject } from '../object';
11
12
 
12
13
  import { Ref, getReferenceAst } from './ref';
13
14
 
14
15
  const Task = Schema.Struct({
15
16
  title: Schema.optional(Schema.String),
16
17
  }).pipe(
17
- EchoObject({
18
+ EchoObjectSchema({
18
19
  typename: 'example.com/type/Task',
19
20
  version: '0.1.0',
20
21
  }),
@@ -25,10 +26,10 @@ type Task = Schema.Schema.Type<typeof Task>;
25
26
  const Contact = Schema.Struct({
26
27
  name: Schema.String,
27
28
  email: Schema.optional(Schema.String),
28
- tasks: Schema.mutable(Schema.Array(Ref(Task))),
29
+ tasks: Schema.Array(Ref(Task)),
29
30
  }).pipe(
30
- EchoObject({
31
- typename: 'example.com/type/Contact',
31
+ EchoObjectSchema({
32
+ typename: 'example.com/type/Person',
32
33
  version: '0.1.0',
33
34
  }),
34
35
  );
@@ -49,8 +50,8 @@ describe('Ref', () => {
49
50
 
50
51
  // TODO(dmaretskyi): Figure out how to expose this in the API.
51
52
  test.skip('encode with inlined target', () => {
52
- const task = create(Task, { title: 'Fix bugs' });
53
- const contact = create(Contact, { name: 'John Doe', tasks: [Ref.make(task)] });
53
+ const task = createObject(Task, { title: 'Fix bugs' });
54
+ const contact = createObject(Contact, { name: 'John Doe', tasks: [Ref.make(task)] });
54
55
 
55
56
  const json = JSON.parse(JSON.stringify(contact));
56
57
  expect(json).toEqual({
@@ -70,8 +71,8 @@ describe('Ref', () => {
70
71
  });
71
72
 
72
73
  test('encode without inlining target', () => {
73
- const task = create(Task, { title: 'Fix bugs' });
74
- const contact = create(Contact, { name: 'John Doe', tasks: [Ref.make(task).noInline()] });
74
+ const task = createObject(Task, { title: 'Fix bugs' });
75
+ const contact = createObject(Contact, { name: 'John Doe', tasks: [Ref.make(task).noInline()] });
75
76
 
76
77
  const json = JSON.parse(JSON.stringify(contact));
77
78
  expect(json).toEqual({