@dxos/echo 0.8.4-main.66e292d → 0.8.4-main.69d29f4

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 (459) hide show
  1. package/README.md +1 -2
  2. package/dist/lib/browser/Annotation.mjs +33 -0
  3. package/dist/lib/browser/Annotation.mjs.map +7 -0
  4. package/dist/lib/browser/Database.mjs +18 -0
  5. package/dist/lib/browser/Database.mjs.map +7 -0
  6. package/dist/lib/browser/Entity.mjs +52 -0
  7. package/dist/lib/browser/Entity.mjs.map +7 -0
  8. package/dist/lib/browser/Err.mjs +11 -0
  9. package/dist/lib/browser/Err.mjs.map +7 -0
  10. package/dist/lib/browser/Filter.mjs +62 -0
  11. package/dist/lib/browser/Filter.mjs.map +7 -0
  12. package/dist/lib/browser/Format.mjs +67 -0
  13. package/dist/lib/browser/Format.mjs.map +7 -0
  14. package/dist/lib/browser/JsonSchema.mjs +20 -0
  15. package/dist/lib/browser/JsonSchema.mjs.map +7 -0
  16. package/dist/lib/browser/Key.mjs +13 -0
  17. package/dist/lib/browser/Key.mjs.map +7 -0
  18. package/dist/lib/browser/Obj.mjs +91 -0
  19. package/dist/lib/browser/Obj.mjs.map +7 -0
  20. package/dist/lib/browser/Order.mjs +13 -0
  21. package/dist/lib/browser/Order.mjs.map +7 -0
  22. package/dist/lib/browser/Query.mjs +27 -0
  23. package/dist/lib/browser/Query.mjs.map +7 -0
  24. package/dist/lib/browser/QueryResult.mjs +3 -0
  25. package/dist/lib/browser/QueryResult.mjs.map +7 -0
  26. package/dist/lib/browser/Ref.mjs +23 -0
  27. package/dist/lib/browser/Ref.mjs.map +7 -0
  28. package/dist/lib/browser/Relation.mjs +85 -0
  29. package/dist/lib/browser/Relation.mjs.map +7 -0
  30. package/dist/lib/browser/SchemaRegistry.mjs +3 -0
  31. package/dist/lib/browser/SchemaRegistry.mjs.map +7 -0
  32. package/dist/lib/browser/Tag.mjs +26 -0
  33. package/dist/lib/browser/Tag.mjs.map +7 -0
  34. package/dist/lib/browser/Type.mjs +48 -0
  35. package/dist/lib/browser/Type.mjs.map +7 -0
  36. package/dist/lib/browser/chunk-2RMVRVOB.mjs +250 -0
  37. package/dist/lib/browser/chunk-2RMVRVOB.mjs.map +7 -0
  38. package/dist/lib/browser/chunk-5RDNDPMX.mjs +74 -0
  39. package/dist/lib/browser/chunk-5RDNDPMX.mjs.map +7 -0
  40. package/dist/lib/browser/chunk-73M2G455.mjs +98 -0
  41. package/dist/lib/browser/chunk-73M2G455.mjs.map +7 -0
  42. package/dist/lib/browser/chunk-7STIBCP7.mjs +133 -0
  43. package/dist/lib/browser/chunk-7STIBCP7.mjs.map +7 -0
  44. package/dist/lib/browser/chunk-AFGYYVVQ.mjs +57 -0
  45. package/dist/lib/browser/chunk-AFGYYVVQ.mjs.map +7 -0
  46. package/dist/lib/browser/chunk-BC6R4CAF.mjs +24 -0
  47. package/dist/lib/browser/chunk-BC6R4CAF.mjs.map +7 -0
  48. package/dist/lib/browser/chunk-BPYFLHWO.mjs +158 -0
  49. package/dist/lib/browser/chunk-BPYFLHWO.mjs.map +7 -0
  50. package/dist/lib/browser/chunk-CBPFF3ZO.mjs +204 -0
  51. package/dist/lib/browser/chunk-CBPFF3ZO.mjs.map +7 -0
  52. package/dist/lib/browser/chunk-CGS2ULMK.mjs +11 -0
  53. package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +7 -0
  54. package/dist/lib/browser/chunk-CJ5YELTO.mjs +39 -0
  55. package/dist/lib/browser/chunk-CJ5YELTO.mjs.map +7 -0
  56. package/dist/lib/browser/chunk-FPOISFQK.mjs +40 -0
  57. package/dist/lib/browser/chunk-FPOISFQK.mjs.map +7 -0
  58. package/dist/lib/browser/chunk-INHXFXY5.mjs +22 -0
  59. package/dist/lib/browser/chunk-INHXFXY5.mjs.map +7 -0
  60. package/dist/lib/browser/chunk-IXVWLTG7.mjs +9 -0
  61. package/dist/lib/browser/chunk-IXVWLTG7.mjs.map +7 -0
  62. package/dist/lib/browser/chunk-JMKVF2YQ.mjs +43 -0
  63. package/dist/lib/browser/chunk-JMKVF2YQ.mjs.map +7 -0
  64. package/dist/lib/browser/chunk-L4RXUJHJ.mjs +143 -0
  65. package/dist/lib/browser/chunk-L4RXUJHJ.mjs.map +7 -0
  66. package/dist/lib/browser/chunk-MYCCGG2T.mjs +15 -0
  67. package/dist/lib/browser/chunk-MYCCGG2T.mjs.map +7 -0
  68. package/dist/lib/browser/{chunk-7GH6RXJ3.mjs → chunk-PAM4KEXE.mjs} +2005 -1841
  69. package/dist/lib/browser/chunk-PAM4KEXE.mjs.map +7 -0
  70. package/dist/lib/browser/chunk-QIWDIPLR.mjs +41 -0
  71. package/dist/lib/browser/chunk-QIWDIPLR.mjs.map +7 -0
  72. package/dist/lib/browser/chunk-R3S54KRI.mjs +403 -0
  73. package/dist/lib/browser/chunk-R3S54KRI.mjs.map +7 -0
  74. package/dist/lib/browser/chunk-RK4Z4JUZ.mjs +283 -0
  75. package/dist/lib/browser/chunk-RK4Z4JUZ.mjs.map +7 -0
  76. package/dist/lib/browser/chunk-TPIL3G6Y.mjs +288 -0
  77. package/dist/lib/browser/chunk-TPIL3G6Y.mjs.map +7 -0
  78. package/dist/lib/browser/chunk-YKTSSMDS.mjs +69 -0
  79. package/dist/lib/browser/chunk-YKTSSMDS.mjs.map +7 -0
  80. package/dist/lib/browser/chunk-ZHXZGIXD.mjs +9 -0
  81. package/dist/lib/browser/chunk-ZHXZGIXD.mjs.map +7 -0
  82. package/dist/lib/browser/index.mjs +65 -25
  83. package/dist/lib/browser/internal/index.mjs +213 -92
  84. package/dist/lib/browser/meta.json +1 -1
  85. package/dist/lib/browser/testing/index.mjs +80 -41
  86. package/dist/lib/browser/testing/index.mjs.map +3 -3
  87. package/dist/lib/node-esm/Annotation.mjs +33 -0
  88. package/dist/lib/node-esm/Annotation.mjs.map +7 -0
  89. package/dist/lib/node-esm/Database.mjs +18 -0
  90. package/dist/lib/node-esm/Database.mjs.map +7 -0
  91. package/dist/lib/node-esm/Entity.mjs +52 -0
  92. package/dist/lib/node-esm/Entity.mjs.map +7 -0
  93. package/dist/lib/node-esm/Err.mjs +11 -0
  94. package/dist/lib/node-esm/Err.mjs.map +7 -0
  95. package/dist/lib/node-esm/Filter.mjs +62 -0
  96. package/dist/lib/node-esm/Filter.mjs.map +7 -0
  97. package/dist/lib/node-esm/Format.mjs +67 -0
  98. package/dist/lib/node-esm/Format.mjs.map +7 -0
  99. package/dist/lib/node-esm/JsonSchema.mjs +20 -0
  100. package/dist/lib/node-esm/JsonSchema.mjs.map +7 -0
  101. package/dist/lib/node-esm/Key.mjs +13 -0
  102. package/dist/lib/node-esm/Key.mjs.map +7 -0
  103. package/dist/lib/node-esm/Obj.mjs +91 -0
  104. package/dist/lib/node-esm/Obj.mjs.map +7 -0
  105. package/dist/lib/node-esm/Order.mjs +13 -0
  106. package/dist/lib/node-esm/Order.mjs.map +7 -0
  107. package/dist/lib/node-esm/Query.mjs +27 -0
  108. package/dist/lib/node-esm/Query.mjs.map +7 -0
  109. package/dist/lib/node-esm/QueryResult.mjs +3 -0
  110. package/dist/lib/node-esm/QueryResult.mjs.map +7 -0
  111. package/dist/lib/node-esm/Ref.mjs +23 -0
  112. package/dist/lib/node-esm/Ref.mjs.map +7 -0
  113. package/dist/lib/node-esm/Relation.mjs +85 -0
  114. package/dist/lib/node-esm/Relation.mjs.map +7 -0
  115. package/dist/lib/node-esm/SchemaRegistry.mjs +3 -0
  116. package/dist/lib/node-esm/SchemaRegistry.mjs.map +7 -0
  117. package/dist/lib/node-esm/Tag.mjs +26 -0
  118. package/dist/lib/node-esm/Tag.mjs.map +7 -0
  119. package/dist/lib/node-esm/Type.mjs +48 -0
  120. package/dist/lib/node-esm/Type.mjs.map +7 -0
  121. package/dist/lib/node-esm/chunk-2RIFBW3A.mjs +250 -0
  122. package/dist/lib/node-esm/chunk-2RIFBW3A.mjs.map +7 -0
  123. package/dist/lib/node-esm/chunk-5CB2ZW74.mjs +57 -0
  124. package/dist/lib/node-esm/chunk-5CB2ZW74.mjs.map +7 -0
  125. package/dist/lib/node-esm/{chunk-M4B6BMD2.mjs → chunk-5U5F4AWK.mjs} +2005 -1841
  126. package/dist/lib/node-esm/chunk-5U5F4AWK.mjs.map +7 -0
  127. package/dist/lib/node-esm/chunk-AJEMYSIR.mjs +22 -0
  128. package/dist/lib/node-esm/chunk-AJEMYSIR.mjs.map +7 -0
  129. package/dist/lib/node-esm/chunk-BKYE5IW6.mjs +158 -0
  130. package/dist/lib/node-esm/chunk-BKYE5IW6.mjs.map +7 -0
  131. package/dist/lib/node-esm/chunk-BYOD7EVP.mjs +98 -0
  132. package/dist/lib/node-esm/chunk-BYOD7EVP.mjs.map +7 -0
  133. package/dist/lib/node-esm/chunk-FWTSPIFF.mjs +133 -0
  134. package/dist/lib/node-esm/chunk-FWTSPIFF.mjs.map +7 -0
  135. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  136. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  137. package/dist/lib/node-esm/chunk-K37NA7PO.mjs +43 -0
  138. package/dist/lib/node-esm/chunk-K37NA7PO.mjs.map +7 -0
  139. package/dist/lib/node-esm/chunk-LIXUCQJM.mjs +41 -0
  140. package/dist/lib/node-esm/chunk-LIXUCQJM.mjs.map +7 -0
  141. package/dist/lib/node-esm/chunk-MOLNWFNL.mjs +9 -0
  142. package/dist/lib/node-esm/chunk-MOLNWFNL.mjs.map +7 -0
  143. package/dist/lib/node-esm/chunk-MOWUEW5P.mjs +15 -0
  144. package/dist/lib/node-esm/chunk-MOWUEW5P.mjs.map +7 -0
  145. package/dist/lib/node-esm/chunk-NBWL7UCZ.mjs +40 -0
  146. package/dist/lib/node-esm/chunk-NBWL7UCZ.mjs.map +7 -0
  147. package/dist/lib/node-esm/chunk-OZEDKT4R.mjs +204 -0
  148. package/dist/lib/node-esm/chunk-OZEDKT4R.mjs.map +7 -0
  149. package/dist/lib/node-esm/chunk-PW3VCWL5.mjs +24 -0
  150. package/dist/lib/node-esm/chunk-PW3VCWL5.mjs.map +7 -0
  151. package/dist/lib/node-esm/chunk-TSTKBFST.mjs +403 -0
  152. package/dist/lib/node-esm/chunk-TSTKBFST.mjs.map +7 -0
  153. package/dist/lib/node-esm/chunk-UKGVOINP.mjs +9 -0
  154. package/dist/lib/node-esm/chunk-UKGVOINP.mjs.map +7 -0
  155. package/dist/lib/node-esm/chunk-UV63HEHQ.mjs +143 -0
  156. package/dist/lib/node-esm/chunk-UV63HEHQ.mjs.map +7 -0
  157. package/dist/lib/node-esm/chunk-WXLVPCRJ.mjs +288 -0
  158. package/dist/lib/node-esm/chunk-WXLVPCRJ.mjs.map +7 -0
  159. package/dist/lib/node-esm/chunk-WZ6YBELW.mjs +74 -0
  160. package/dist/lib/node-esm/chunk-WZ6YBELW.mjs.map +7 -0
  161. package/dist/lib/node-esm/chunk-XHJRMQZD.mjs +69 -0
  162. package/dist/lib/node-esm/chunk-XHJRMQZD.mjs.map +7 -0
  163. package/dist/lib/node-esm/chunk-YOLH5KS4.mjs +283 -0
  164. package/dist/lib/node-esm/chunk-YOLH5KS4.mjs.map +7 -0
  165. package/dist/lib/node-esm/chunk-YQ2NWGL5.mjs +39 -0
  166. package/dist/lib/node-esm/chunk-YQ2NWGL5.mjs.map +7 -0
  167. package/dist/lib/node-esm/index.mjs +65 -25
  168. package/dist/lib/node-esm/internal/index.mjs +213 -92
  169. package/dist/lib/node-esm/meta.json +1 -1
  170. package/dist/lib/node-esm/testing/index.mjs +80 -41
  171. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  172. package/dist/types/src/Annotation.d.ts +1 -1
  173. package/dist/types/src/Annotation.d.ts.map +1 -1
  174. package/dist/types/src/Database.d.ts +117 -60
  175. package/dist/types/src/Database.d.ts.map +1 -1
  176. package/dist/types/src/Entity.d.ts +111 -5
  177. package/dist/types/src/Entity.d.ts.map +1 -1
  178. package/dist/types/src/Entity.test.d.ts +2 -0
  179. package/dist/types/src/Entity.test.d.ts.map +1 -0
  180. package/dist/types/src/{errors.d.ts → Err.d.ts} +13 -17
  181. package/dist/types/src/Err.d.ts.map +1 -0
  182. package/dist/types/src/Filter.d.ts +120 -0
  183. package/dist/types/src/Filter.d.ts.map +1 -0
  184. package/dist/types/src/Format.d.ts.map +1 -1
  185. package/dist/types/src/Hypergraph.d.ts +60 -0
  186. package/dist/types/src/Hypergraph.d.ts.map +1 -0
  187. package/dist/types/src/Obj.d.ts +268 -76
  188. package/dist/types/src/Obj.d.ts.map +1 -1
  189. package/dist/types/src/Obj.test.d.ts +2 -0
  190. package/dist/types/src/Obj.test.d.ts.map +1 -0
  191. package/dist/types/src/Order.d.ts +16 -0
  192. package/dist/types/src/Order.d.ts.map +1 -0
  193. package/dist/types/src/{query/query.d.ts → Query.d.ts} +53 -50
  194. package/dist/types/src/Query.d.ts.map +1 -0
  195. package/dist/types/src/Query.test.d.ts +2 -0
  196. package/dist/types/src/Query.test.d.ts.map +1 -0
  197. package/dist/types/src/QueryResult.d.ts +80 -0
  198. package/dist/types/src/QueryResult.d.ts.map +1 -0
  199. package/dist/types/src/Ref.d.ts +9 -7
  200. package/dist/types/src/Ref.d.ts.map +1 -1
  201. package/dist/types/src/Relation.d.ts +235 -18
  202. package/dist/types/src/Relation.d.ts.map +1 -1
  203. package/dist/types/src/Relation.test.d.ts +2 -0
  204. package/dist/types/src/Relation.test.d.ts.map +1 -0
  205. package/dist/types/src/SchemaRegistry.d.ts +84 -0
  206. package/dist/types/src/SchemaRegistry.d.ts.map +1 -0
  207. package/dist/types/src/Tag.d.ts +6 -6
  208. package/dist/types/src/Tag.d.ts.map +1 -1
  209. package/dist/types/src/Type.d.ts +213 -50
  210. package/dist/types/src/Type.d.ts.map +1 -1
  211. package/dist/types/src/Type.test.d.ts +2 -0
  212. package/dist/types/src/Type.test.d.ts.map +1 -0
  213. package/dist/types/src/index.d.ts +8 -2
  214. package/dist/types/src/index.d.ts.map +1 -1
  215. package/dist/types/src/internal/annotations/annotations.d.ts +23 -27
  216. package/dist/types/src/internal/annotations/annotations.d.ts.map +1 -1
  217. package/dist/types/src/internal/annotations/util.d.ts +1 -0
  218. package/dist/types/src/internal/annotations/util.d.ts.map +1 -1
  219. package/dist/types/src/internal/api/annotations.d.ts +23 -0
  220. package/dist/types/src/internal/api/annotations.d.ts.map +1 -0
  221. package/dist/types/src/internal/api/entity.d.ts +13 -0
  222. package/dist/types/src/internal/api/entity.d.ts.map +1 -0
  223. package/dist/types/src/internal/api/index.d.ts +15 -0
  224. package/dist/types/src/internal/api/index.d.ts.map +1 -0
  225. package/dist/types/src/internal/api/meta.d.ts +42 -0
  226. package/dist/types/src/internal/api/meta.d.ts.map +1 -0
  227. package/dist/types/src/internal/api/sorting.d.ts +24 -0
  228. package/dist/types/src/internal/api/sorting.d.ts.map +1 -0
  229. package/dist/types/src/internal/api/version.d.ts +42 -0
  230. package/dist/types/src/internal/api/version.d.ts.map +1 -0
  231. package/dist/types/src/internal/entities/entity.d.ts +13 -3
  232. package/dist/types/src/internal/entities/entity.d.ts.map +1 -1
  233. package/dist/types/src/internal/entities/index.d.ts +1 -1
  234. package/dist/types/src/internal/entities/index.d.ts.map +1 -1
  235. package/dist/types/src/internal/entities/model.d.ts +14 -7
  236. package/dist/types/src/internal/entities/model.d.ts.map +1 -1
  237. package/dist/types/src/internal/entities/object.d.ts +8 -1
  238. package/dist/types/src/internal/entities/object.d.ts.map +1 -1
  239. package/dist/types/src/internal/entities/relation.d.ts +8 -1
  240. package/dist/types/src/internal/entities/relation.d.ts.map +1 -1
  241. package/dist/types/src/internal/formats/format.d.ts +4 -4
  242. package/dist/types/src/internal/formats/format.d.ts.map +1 -1
  243. package/dist/types/src/internal/formats/select.d.ts +6 -4
  244. package/dist/types/src/internal/formats/select.d.ts.map +1 -1
  245. package/dist/types/src/internal/formats/string.d.ts +4 -0
  246. package/dist/types/src/internal/formats/string.d.ts.map +1 -1
  247. package/dist/types/src/internal/formats/types.d.ts +6 -2
  248. package/dist/types/src/internal/formats/types.d.ts.map +1 -1
  249. package/dist/types/src/internal/index.d.ts +2 -1
  250. package/dist/types/src/internal/index.d.ts.map +1 -1
  251. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +1 -1
  252. package/dist/types/src/internal/json-schema/json-schema-type.d.ts +130 -29
  253. package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +1 -1
  254. package/dist/types/src/internal/json-schema/json-schema.d.ts +2 -1
  255. package/dist/types/src/internal/json-schema/json-schema.d.ts.map +1 -1
  256. package/dist/types/src/internal/object/clone.d.ts +8 -0
  257. package/dist/types/src/internal/object/clone.d.ts.map +1 -0
  258. package/dist/types/src/internal/object/create-object.d.ts +1 -1
  259. package/dist/types/src/internal/object/index.d.ts +3 -0
  260. package/dist/types/src/internal/object/index.d.ts.map +1 -1
  261. package/dist/types/src/internal/object/json-serializer.d.ts +13 -7
  262. package/dist/types/src/internal/object/json-serializer.d.ts.map +1 -1
  263. package/dist/types/src/internal/object/schema-validator.d.ts +1 -14
  264. package/dist/types/src/internal/object/schema-validator.d.ts.map +1 -1
  265. package/dist/types/src/internal/object/set-value.d.ts +7 -0
  266. package/dist/types/src/internal/object/set-value.d.ts.map +1 -0
  267. package/dist/types/src/internal/object/set-value.test.d.ts +2 -0
  268. package/dist/types/src/internal/object/set-value.test.d.ts.map +1 -0
  269. package/dist/types/src/internal/object/snapshot.d.ts +6 -0
  270. package/dist/types/src/internal/object/snapshot.d.ts.map +1 -0
  271. package/dist/types/src/internal/object/typed-object.d.ts +7 -13
  272. package/dist/types/src/internal/object/typed-object.d.ts.map +1 -1
  273. package/dist/types/src/internal/proxy/change-context.d.ts +55 -0
  274. package/dist/types/src/internal/proxy/change-context.d.ts.map +1 -0
  275. package/dist/types/src/internal/proxy/change.test.d.ts +2 -0
  276. package/dist/types/src/internal/proxy/change.test.d.ts.map +1 -0
  277. package/dist/types/src/internal/proxy/define-hidden-property.d.ts +5 -0
  278. package/dist/types/src/internal/proxy/define-hidden-property.d.ts.map +1 -0
  279. package/dist/types/src/internal/proxy/errors.d.ts +19 -0
  280. package/dist/types/src/internal/proxy/errors.d.ts.map +1 -0
  281. package/dist/types/src/internal/proxy/event-batch.d.ts +10 -0
  282. package/dist/types/src/internal/proxy/event-batch.d.ts.map +1 -0
  283. package/dist/types/src/internal/proxy/index.d.ts +11 -0
  284. package/dist/types/src/internal/proxy/index.d.ts.map +1 -1
  285. package/dist/types/src/internal/proxy/json-serializer.d.ts +6 -0
  286. package/dist/types/src/internal/proxy/json-serializer.d.ts.map +1 -0
  287. package/dist/types/src/internal/proxy/make-object.d.ts +2 -4
  288. package/dist/types/src/internal/proxy/make-object.d.ts.map +1 -1
  289. package/dist/types/src/internal/proxy/ownership.d.ts +57 -0
  290. package/dist/types/src/internal/proxy/ownership.d.ts.map +1 -0
  291. package/dist/types/src/internal/proxy/proxy-types.d.ts +18 -0
  292. package/dist/types/src/internal/proxy/proxy-types.d.ts.map +1 -0
  293. package/dist/types/src/internal/proxy/proxy-utils.d.ts +47 -0
  294. package/dist/types/src/internal/proxy/proxy-utils.d.ts.map +1 -0
  295. package/dist/types/src/internal/proxy/reactive-array.d.ts +8 -0
  296. package/dist/types/src/internal/proxy/reactive-array.d.ts.map +1 -0
  297. package/dist/types/src/internal/proxy/reactive.d.ts +39 -0
  298. package/dist/types/src/internal/proxy/reactive.d.ts.map +1 -0
  299. package/dist/types/src/internal/proxy/schema-validator.d.ts +15 -0
  300. package/dist/types/src/internal/proxy/schema-validator.d.ts.map +1 -0
  301. package/dist/types/src/internal/proxy/symbols.d.ts +3 -0
  302. package/dist/types/src/internal/proxy/symbols.d.ts.map +1 -0
  303. package/dist/types/src/internal/proxy/typed-handler.d.ts +14 -11
  304. package/dist/types/src/internal/proxy/typed-handler.d.ts.map +1 -1
  305. package/dist/types/src/internal/ref/ref-array.d.ts +4 -4
  306. package/dist/types/src/internal/ref/ref-array.d.ts.map +1 -1
  307. package/dist/types/src/internal/ref/ref.d.ts +16 -7
  308. package/dist/types/src/internal/ref/ref.d.ts.map +1 -1
  309. package/dist/types/src/internal/schema/compose.d.ts +2 -1
  310. package/dist/types/src/internal/schema/compose.d.ts.map +1 -1
  311. package/dist/types/src/internal/schema/echo-schema.d.ts +15 -3
  312. package/dist/types/src/internal/schema/echo-schema.d.ts.map +1 -1
  313. package/dist/types/src/internal/schema/index.d.ts +0 -2
  314. package/dist/types/src/internal/schema/index.d.ts.map +1 -1
  315. package/dist/types/src/internal/schema/persistent-schema.d.ts +9 -7
  316. package/dist/types/src/internal/schema/persistent-schema.d.ts.map +1 -1
  317. package/dist/types/src/internal/types/base.d.ts +5 -16
  318. package/dist/types/src/internal/types/base.d.ts.map +1 -1
  319. package/dist/types/src/internal/types/entity.d.ts +27 -2
  320. package/dist/types/src/internal/types/entity.d.ts.map +1 -1
  321. package/dist/types/src/internal/types/meta.d.ts +6 -14
  322. package/dist/types/src/internal/types/meta.d.ts.map +1 -1
  323. package/dist/types/src/testing/test-schema.d.ts +141 -175
  324. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  325. package/dist/types/src/testing/util.d.ts +6 -1
  326. package/dist/types/src/testing/util.d.ts.map +1 -1
  327. package/dist/types/tsconfig.tsbuildinfo +1 -1
  328. package/package.json +130 -23
  329. package/src/Annotation.ts +5 -4
  330. package/src/Database.ts +229 -82
  331. package/src/Entity.test.ts +22 -0
  332. package/src/Entity.ts +173 -7
  333. package/src/{errors.ts → Err.ts} +2 -2
  334. package/src/Filter.ts +376 -0
  335. package/src/Format.ts +0 -2
  336. package/src/Hypergraph.ts +74 -0
  337. package/src/Obj.test.ts +386 -0
  338. package/src/Obj.ts +338 -250
  339. package/src/{query/order.ts → Order.ts} +19 -9
  340. package/src/{query/query.test.ts → Query.test.ts} +180 -49
  341. package/src/{query/query.ts → Query.ts} +115 -122
  342. package/src/QueryResult.ts +106 -0
  343. package/src/Ref.ts +20 -3
  344. package/src/Relation.test.ts +82 -0
  345. package/src/Relation.ts +364 -27
  346. package/src/SchemaRegistry.ts +105 -0
  347. package/src/Tag.ts +1 -1
  348. package/src/Type.test.ts +52 -0
  349. package/src/Type.ts +322 -88
  350. package/src/index.ts +9 -5
  351. package/src/internal/README.md +36 -17
  352. package/src/internal/annotations/annotations.test.ts +6 -6
  353. package/src/internal/annotations/annotations.ts +73 -76
  354. package/src/internal/annotations/util.ts +2 -0
  355. package/src/internal/api/annotations.ts +60 -0
  356. package/src/internal/api/entity.ts +29 -0
  357. package/src/internal/api/index.ts +19 -0
  358. package/src/internal/api/meta.ts +88 -0
  359. package/src/internal/api/sorting.ts +53 -0
  360. package/src/internal/api/version.ts +96 -0
  361. package/src/internal/entities/entity.ts +36 -19
  362. package/src/internal/entities/index.ts +1 -1
  363. package/src/internal/entities/model.ts +17 -12
  364. package/src/internal/entities/object.ts +21 -8
  365. package/src/internal/entities/relation.ts +23 -7
  366. package/src/internal/formats/format.test.ts +1 -1
  367. package/src/internal/formats/format.ts +7 -8
  368. package/src/internal/formats/object.ts +2 -2
  369. package/src/internal/formats/select.ts +6 -4
  370. package/src/internal/formats/string.ts +5 -0
  371. package/src/internal/formats/types.ts +9 -3
  372. package/src/internal/index.ts +2 -1
  373. package/src/internal/json-schema/json-schema-normalize.ts +4 -2
  374. package/src/internal/json-schema/json-schema-type.ts +31 -32
  375. package/src/internal/json-schema/json-schema.test.ts +19 -17
  376. package/src/internal/json-schema/json-schema.ts +14 -10
  377. package/src/internal/object/clone.ts +48 -0
  378. package/src/internal/object/create-object.ts +2 -2
  379. package/src/internal/object/index.ts +3 -0
  380. package/src/internal/object/inspect.ts +3 -3
  381. package/src/internal/object/json-serializer.test.ts +6 -2
  382. package/src/internal/object/json-serializer.ts +28 -70
  383. package/src/internal/object/schema-validator.test.ts +3 -7
  384. package/src/internal/object/schema-validator.ts +2 -238
  385. package/src/internal/object/set-value.test.ts +281 -0
  386. package/src/internal/object/set-value.ts +165 -0
  387. package/src/internal/object/snapshot.ts +70 -0
  388. package/src/internal/object/typed-object.test.ts +11 -11
  389. package/src/internal/object/typed-object.ts +8 -72
  390. package/src/internal/proxy/change-context.ts +138 -0
  391. package/src/internal/proxy/change.test.ts +519 -0
  392. package/src/internal/proxy/define-hidden-property.ts +14 -0
  393. package/src/internal/proxy/errors.ts +42 -0
  394. package/src/internal/proxy/event-batch.ts +44 -0
  395. package/src/internal/proxy/handler.test.ts +30 -80
  396. package/src/internal/proxy/index.ts +11 -0
  397. package/src/internal/proxy/json-serializer.ts +87 -0
  398. package/src/internal/proxy/make-object.ts +33 -50
  399. package/src/internal/proxy/ownership.ts +253 -0
  400. package/src/internal/proxy/proxy-types.ts +23 -0
  401. package/src/internal/proxy/proxy-utils.ts +150 -0
  402. package/src/internal/proxy/reactive-array.ts +71 -0
  403. package/src/internal/proxy/reactive.ts +69 -0
  404. package/src/internal/proxy/schema-validator.ts +244 -0
  405. package/src/internal/proxy/schema.test.ts +23 -15
  406. package/src/internal/proxy/symbols.ts +7 -0
  407. package/src/internal/proxy/typed-handler.test.ts +247 -35
  408. package/src/internal/proxy/typed-handler.ts +265 -56
  409. package/src/internal/proxy/typed-object.test.ts +37 -26
  410. package/src/internal/ref/ref-array.ts +4 -4
  411. package/src/internal/ref/ref.test.ts +1 -1
  412. package/src/internal/ref/ref.ts +64 -40
  413. package/src/internal/schema/compose.test.ts +3 -3
  414. package/src/internal/schema/compose.ts +13 -9
  415. package/src/internal/schema/echo-schema.ts +49 -11
  416. package/src/internal/schema/index.ts +0 -2
  417. package/src/internal/schema/persistent-schema.ts +3 -4
  418. package/src/internal/types/base.ts +6 -21
  419. package/src/internal/types/entity.ts +35 -4
  420. package/src/internal/types/meta.ts +13 -24
  421. package/src/testing/api.test.ts +31 -5
  422. package/src/testing/test-schema.ts +55 -30
  423. package/src/testing/util.ts +22 -15
  424. package/dist/lib/browser/chunk-7GH6RXJ3.mjs.map +0 -7
  425. package/dist/lib/browser/chunk-E4UTVJNF.mjs +0 -1111
  426. package/dist/lib/browser/chunk-E4UTVJNF.mjs.map +0 -7
  427. package/dist/lib/node-esm/chunk-JE5RXM2I.mjs +0 -1111
  428. package/dist/lib/node-esm/chunk-JE5RXM2I.mjs.map +0 -7
  429. package/dist/lib/node-esm/chunk-M4B6BMD2.mjs.map +0 -7
  430. package/dist/types/src/errors.d.ts.map +0 -1
  431. package/dist/types/src/internal/entities/expando.d.ts +0 -16
  432. package/dist/types/src/internal/entities/expando.d.ts.map +0 -1
  433. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts +0 -18
  434. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts.map +0 -1
  435. package/dist/types/src/internal/schema/snapshot.d.ts +0 -6
  436. package/dist/types/src/internal/schema/snapshot.d.ts.map +0 -1
  437. package/dist/types/src/query/filter.d.ts +0 -167
  438. package/dist/types/src/query/filter.d.ts.map +0 -1
  439. package/dist/types/src/query/index.d.ts +0 -5
  440. package/dist/types/src/query/index.d.ts.map +0 -1
  441. package/dist/types/src/query/order.d.ts +0 -12
  442. package/dist/types/src/query/order.d.ts.map +0 -1
  443. package/dist/types/src/query/query.d.ts.map +0 -1
  444. package/dist/types/src/query/query.test.d.ts +0 -2
  445. package/dist/types/src/query/query.test.d.ts.map +0 -1
  446. package/dist/types/src/query/testing.d.ts +0 -51
  447. package/dist/types/src/query/testing.d.ts.map +0 -1
  448. package/dist/types/src/query/types.d.ts +0 -17
  449. package/dist/types/src/query/types.d.ts.map +0 -1
  450. package/dist/types/src/query/util.d.ts +0 -8
  451. package/dist/types/src/query/util.d.ts.map +0 -1
  452. package/src/internal/entities/expando.ts +0 -23
  453. package/src/internal/schema/runtime-schema-registry.ts +0 -78
  454. package/src/internal/schema/snapshot.ts +0 -25
  455. package/src/query/filter.ts +0 -455
  456. package/src/query/index.ts +0 -9
  457. package/src/query/testing.ts +0 -64
  458. package/src/query/types.ts +0 -23
  459. package/src/query/util.ts +0 -25
@@ -2,241 +2,5 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import * as Schema from 'effect/Schema';
6
- import * as SchemaAST from 'effect/SchemaAST';
7
-
8
- import { invariant } from '@dxos/invariant';
9
-
10
- import { SchemaId } from '../types';
11
-
12
- // TODO(burdon): Reconcile with @dxos/effect visit().
13
-
14
- export class SchemaValidator {
15
- /**
16
- * Recursively check that schema specifies constructions we can handle.
17
- * Validates there are no ambiguous discriminated union types.
18
- */
19
- public static validateSchema(schema: Schema.Schema.AnyNoContext): void {
20
- const visitAll = (nodes: SchemaAST.AST[]) => nodes.forEach((node) => this.validateSchema(Schema.make(node)));
21
- if (SchemaAST.isUnion(schema.ast)) {
22
- const typeAstList = schema.ast.types.filter((type) => SchemaAST.isTypeLiteral(type)) as SchemaAST.TypeLiteral[];
23
- // Check we can handle a discriminated union.
24
- if (typeAstList.length > 1) {
25
- getTypeDiscriminators(typeAstList);
26
- }
27
- visitAll(typeAstList);
28
- } else if (SchemaAST.isTupleType(schema.ast)) {
29
- const positionalTypes = schema.ast.elements.map((t) => t.type);
30
- const allTypes = positionalTypes.concat(schema.ast.rest.map((t) => t.type));
31
- visitAll(allTypes);
32
- } else if (SchemaAST.isTypeLiteral(schema.ast)) {
33
- visitAll(SchemaAST.getPropertySignatures(schema.ast).map((p) => p.type));
34
- }
35
- }
36
-
37
- public static hasTypeAnnotation(
38
- rootObjectSchema: Schema.Schema.AnyNoContext,
39
- property: string,
40
- annotation: symbol,
41
- ): boolean {
42
- try {
43
- let type = this.getPropertySchema(rootObjectSchema, [property]);
44
- if (SchemaAST.isTupleType(type.ast)) {
45
- type = this.getPropertySchema(rootObjectSchema, [property, '0']);
46
- }
47
-
48
- return type.ast.annotations[annotation] != null;
49
- } catch {
50
- return false;
51
- }
52
- }
53
-
54
- public static getPropertySchema(
55
- rootObjectSchema: Schema.Schema.AnyNoContext,
56
- propertyPath: KeyPath,
57
- getProperty: (path: KeyPath) => any = () => null,
58
- ): Schema.Schema.AnyNoContext {
59
- let schema: Schema.Schema.AnyNoContext = rootObjectSchema;
60
- for (let i = 0; i < propertyPath.length; i++) {
61
- const propertyName = propertyPath[i];
62
- const tupleAst = unwrapArray(schema.ast);
63
- if (tupleAst != null) {
64
- schema = getArrayElementSchema(tupleAst, propertyName);
65
- } else {
66
- const propertyType = getPropertyType(schema.ast, propertyName.toString(), (propertyName) =>
67
- getProperty([...propertyPath.slice(0, i), propertyName]),
68
- );
69
- if (propertyType == null) {
70
- throw new TypeError(`unknown property: ${String(propertyName)} on object. Path: ${propertyPath}`);
71
- }
72
-
73
- schema = Schema.make(propertyType).annotations(propertyType.annotations);
74
- }
75
- }
76
-
77
- return schema;
78
- }
79
-
80
- public static getTargetPropertySchema(target: any, prop: string | symbol): Schema.Schema.AnyNoContext {
81
- const schema: Schema.Schema.AnyNoContext | undefined = (target as any)[SchemaId];
82
- invariant(schema, 'target has no schema');
83
- const arrayAst = unwrapArray(schema.ast);
84
- if (arrayAst != null) {
85
- return getArrayElementSchema(arrayAst, prop);
86
- }
87
-
88
- const propertyType = getPropertyType(schema.ast, prop.toString(), (prop) => target[prop]);
89
- if (propertyType == null) {
90
- return Schema.Any; // TODO(burdon): HACK.
91
- }
92
-
93
- invariant(propertyType, `invalid property: ${prop.toString()}`);
94
- return Schema.make(propertyType);
95
- }
96
- }
97
-
98
- /**
99
- * Tuple AST is used both for:
100
- * fixed-length tuples ([string, number]) in which case AST will be { elements: [Schema.String, Schema.Number] }
101
- * variable-length arrays (Array<string | number>) in which case AST will be { rest: [Schema.Union(Schema.String, Schema.Number)] }
102
- */
103
- const getArrayElementSchema = (
104
- tupleAst: SchemaAST.TupleType,
105
- property: string | symbol | number,
106
- ): Schema.Schema.AnyNoContext => {
107
- const elementIndex = typeof property === 'string' ? parseInt(property, 10) : Number.NaN;
108
- if (Number.isNaN(elementIndex)) {
109
- invariant(property === 'length', `invalid array property: ${String(property)}`);
110
- return Schema.Number;
111
- }
112
- if (elementIndex < tupleAst.elements.length) {
113
- const elementType = tupleAst.elements[elementIndex].type;
114
- return Schema.make(elementType).annotations(elementType.annotations);
115
- }
116
-
117
- const restType = tupleAst.rest;
118
- return Schema.make(restType[0].type).annotations(restType[0].annotations);
119
- };
120
-
121
- const flattenUnion = (typeAst: SchemaAST.AST): SchemaAST.AST[] =>
122
- SchemaAST.isUnion(typeAst) ? typeAst.types.flatMap(flattenUnion) : [typeAst];
123
-
124
- const getProperties = (
125
- typeAst: SchemaAST.AST,
126
- getTargetPropertyFn: (propertyName: string) => any,
127
- ): SchemaAST.PropertySignature[] => {
128
- const astCandidates = flattenUnion(typeAst);
129
- const typeAstList = astCandidates.filter((type) => SchemaAST.isTypeLiteral(type)) as SchemaAST.TypeLiteral[];
130
- if (typeAstList.length === 0) {
131
- return [];
132
- }
133
- if (typeAstList.length === 1) {
134
- return SchemaAST.getPropertySignatures(typeAstList[0]);
135
- }
136
-
137
- const typeDiscriminators = getTypeDiscriminators(typeAstList);
138
- const targetPropertyValue = getTargetPropertyFn(String(typeDiscriminators[0].name));
139
- const typeIndex = typeDiscriminators.findIndex((p) => targetPropertyValue === (p.type as SchemaAST.Literal).literal);
140
- invariant(typeIndex !== -1, 'discriminator field not set on target');
141
- return SchemaAST.getPropertySignatures(typeAstList[typeIndex]);
142
- };
143
-
144
- const getPropertyType = (
145
- ast: SchemaAST.AST,
146
- propertyName: string,
147
- getTargetPropertyFn: (propertyName: string) => any,
148
- ): SchemaAST.AST | null => {
149
- const anyOrObject = unwrapAst(
150
- ast,
151
- (candidate) => SchemaAST.isAnyKeyword(candidate) || SchemaAST.isObjectKeyword(candidate),
152
- );
153
- if (anyOrObject != null) {
154
- return ast;
155
- }
156
-
157
- const typeOrDiscriminatedUnion = unwrapAst(ast, (t) => {
158
- return SchemaAST.isTypeLiteral(t) || (SchemaAST.isUnion(t) && t.types.some((t) => SchemaAST.isTypeLiteral(t)));
159
- });
160
- if (typeOrDiscriminatedUnion == null) {
161
- return null;
162
- }
163
-
164
- const targetProperty = getProperties(typeOrDiscriminatedUnion, getTargetPropertyFn).find(
165
- (p) => p.name === propertyName,
166
- );
167
- if (targetProperty != null) {
168
- return unwrapAst(targetProperty.type);
169
- }
170
-
171
- const indexSignatureType = unwrapAst(ast, SchemaAST.isTypeLiteral);
172
- if (
173
- indexSignatureType &&
174
- SchemaAST.isTypeLiteral(indexSignatureType) &&
175
- indexSignatureType.indexSignatures.length > 0
176
- ) {
177
- return unwrapAst(indexSignatureType.indexSignatures[0].type);
178
- }
179
-
180
- return null;
181
- };
182
-
183
- const getTypeDiscriminators = (typeAstList: SchemaAST.TypeLiteral[]): SchemaAST.PropertySignature[] => {
184
- const discriminatorPropCandidates = typeAstList
185
- .flatMap(SchemaAST.getPropertySignatures)
186
- .filter((p) => SchemaAST.isLiteral(p.type));
187
- const propertyName = discriminatorPropCandidates[0].name;
188
- const isValidDiscriminator = discriminatorPropCandidates.every((p) => p.name === propertyName && !p.isOptional);
189
- const everyTypeHasDiscriminator = discriminatorPropCandidates.length === typeAstList.length;
190
- const isDiscriminatedUnion = isValidDiscriminator && everyTypeHasDiscriminator;
191
- invariant(isDiscriminatedUnion, 'type ambiguity: every type in a union must have a single unique-literal field');
192
- return discriminatorPropCandidates;
193
- };
194
-
195
- /**
196
- * Used to check that rootAst is for a type matching the provided predicate.
197
- * That's not always straightforward because types of optionality and recursive types.
198
- * const Task = Schema.Struct({
199
- * ...,
200
- * previous?: Schema.optional(Schema.suspend(() => Task)),
201
- * });
202
- * Here the AST for `previous` field is going to be Union(Suspend(Type), Undefined).
203
- * SchemaAST.isTypeLiteral(field) will return false, but unwrapAst(field, (ast) => SchemaAST.isTypeLiteral(ast))
204
- * will return true.
205
- */
206
- const unwrapAst = (rootAst: SchemaAST.AST, predicate?: (ast: SchemaAST.AST) => boolean): SchemaAST.AST | null => {
207
- let ast: SchemaAST.AST | undefined = rootAst;
208
- while (ast != null) {
209
- if (predicate?.(ast)) {
210
- return ast;
211
- }
212
-
213
- if (SchemaAST.isUnion(ast)) {
214
- const next: any = ast.types.find((t) => (predicate != null && predicate(t)) || SchemaAST.isSuspend(t));
215
- if (next != null) {
216
- ast = next;
217
- continue;
218
- }
219
- }
220
-
221
- if (SchemaAST.isSuspend(ast)) {
222
- ast = ast.f();
223
- } else {
224
- return predicate == null ? ast : null;
225
- }
226
- }
227
-
228
- return null;
229
- };
230
-
231
- const unwrapArray = (ast: SchemaAST.AST) => unwrapAst(ast, SchemaAST.isTupleType) as SchemaAST.TupleType | null;
232
-
233
- export const checkIdNotPresentOnSchema = (schema: Schema.Schema<any, any, any>) => {
234
- invariant(SchemaAST.isTypeLiteral(schema.ast));
235
- const idProperty = SchemaAST.getPropertySignatures(schema.ast).find((prop) => prop.name === 'id');
236
- if (idProperty != null) {
237
- throw new Error('"id" property name is reserved');
238
- }
239
- };
240
-
241
- // TODO(burdon): Reconcile with JsonPath.
242
- type KeyPath = readonly (string | number)[];
5
+ // Re-export from proxy for backward compatibility.
6
+ export { SchemaValidator, checkIdNotPresentOnSchema } from '../proxy';
@@ -0,0 +1,281 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import * as Obj from '../../Obj';
9
+ import { TestSchema } from '../../testing';
10
+ import * as Type from '../../Type';
11
+
12
+ describe('Obj.setValue', () => {
13
+ test('sets simple nested object property', ({ expect }) => {
14
+ const person = Obj.make(TestSchema.Person, {
15
+ name: 'John',
16
+ username: 'john',
17
+ email: 'john@example.com',
18
+ });
19
+
20
+ Obj.change(person, (p) => Obj.setValue(p, ['address', 'city'], 'NYC'));
21
+
22
+ expect(person.address).toBeDefined();
23
+ expect(person.address?.city).toBe('NYC');
24
+ });
25
+
26
+ test('sets array element by initializing array', ({ expect }) => {
27
+ const person = Obj.make(TestSchema.Person, {
28
+ name: 'John',
29
+ username: 'john',
30
+ email: 'john@example.com',
31
+ });
32
+
33
+ Obj.change(person, (p) => Obj.setValue(p, ['fields', 0, 'label'], 'Phone'));
34
+
35
+ expect(Array.isArray(person.fields)).toBe(true);
36
+ expect(person.fields?.[0].label).toBe('Phone');
37
+ // The 'value' field is required, so it should be initialized with default.
38
+ expect(person.fields?.[0].value).toBe('');
39
+ });
40
+
41
+ test('sets deeply nested array in object', ({ expect }) => {
42
+ const person = Obj.make(TestSchema.Person, {
43
+ name: 'John',
44
+ username: 'john',
45
+ email: 'john@example.com',
46
+ });
47
+
48
+ Obj.change(person, (p) => Obj.setValue(p, ['address', 'coordinates', 'lat'], 40.7128));
49
+
50
+ expect(person.address).toBeDefined();
51
+ expect(person.address?.coordinates).toBeDefined();
52
+ expect(person.address?.coordinates?.lat).toBe(40.7128);
53
+ });
54
+
55
+ test('sets multiple nested array elements', ({ expect }) => {
56
+ const Item = Schema.Struct({
57
+ value: Schema.optional(Schema.Number),
58
+ });
59
+
60
+ const Container = Schema.Struct({
61
+ name: Schema.String,
62
+ items: Schema.optional(Schema.Array(Item)),
63
+ }).pipe(
64
+ Type.object({
65
+ typename: 'test.com/Container',
66
+ version: '0.1.0',
67
+ }),
68
+ );
69
+
70
+ const container = Obj.make(Container, { name: 'box' });
71
+
72
+ Obj.change(container, (c) => {
73
+ Obj.setValue(c, ['items', 0, 'value'], 10);
74
+ Obj.setValue(c, ['items', 1, 'value'], 20);
75
+ Obj.setValue(c, ['items', 2, 'value'], 30);
76
+ });
77
+
78
+ expect(container.items).toHaveLength(3);
79
+ expect(container.items?.[0].value).toBe(10);
80
+ expect(container.items?.[1].value).toBe(20);
81
+ expect(container.items?.[2].value).toBe(30);
82
+ });
83
+
84
+ test('handles optional fields', ({ expect }) => {
85
+ const person = Obj.make(TestSchema.Person, {
86
+ name: 'John',
87
+ username: 'john',
88
+ email: 'john@example.com',
89
+ });
90
+
91
+ Obj.change(person, (p) => Obj.setValue(p, ['age'], 25));
92
+
93
+ expect(person.age).toBe(25);
94
+ });
95
+
96
+ test('handles nested optional objects', ({ expect }) => {
97
+ const person = Obj.make(TestSchema.Person, {
98
+ name: 'John',
99
+ username: 'john',
100
+ email: 'john@example.com',
101
+ });
102
+
103
+ Obj.change(person, (p) => Obj.setValue(p, ['address', 'city'], 'NYC'));
104
+
105
+ expect(person.address).toBeDefined();
106
+ expect(person.address?.city).toBe('NYC');
107
+ });
108
+
109
+ test('returns the set value', ({ expect }) => {
110
+ const person = Obj.make(TestSchema.Person, {
111
+ name: 'John',
112
+ username: 'john',
113
+ email: 'john@example.com',
114
+ });
115
+
116
+ let result: any;
117
+ Obj.change(person, (p) => {
118
+ result = Obj.setValue(p, ['age'], 30);
119
+ });
120
+
121
+ expect(result).toBe(30);
122
+ });
123
+
124
+ test('overwrites existing values', ({ expect }) => {
125
+ const person = Obj.make(TestSchema.Person, {
126
+ name: 'John',
127
+ username: 'john',
128
+ email: 'john@example.com',
129
+ age: 25,
130
+ });
131
+
132
+ Obj.change(person, (p) => Obj.setValue(p, ['age'], 30));
133
+
134
+ expect(person.age).toBe(30);
135
+ });
136
+
137
+ test('sets nested value in existing object', ({ expect }) => {
138
+ const person = Obj.make(TestSchema.Person, {
139
+ name: 'John',
140
+ username: 'john',
141
+ email: 'john@example.com',
142
+ address: { city: 'Boston', state: 'MA', coordinates: {} },
143
+ });
144
+
145
+ Obj.change(person, (p) => Obj.setValue(p, ['address', 'city'], 'NYC'));
146
+
147
+ expect(person.address?.city).toBe('NYC');
148
+ expect(person.address?.state).toBe('MA');
149
+ });
150
+
151
+ test('handles two-dimensional arrays', ({ expect }) => {
152
+ const Matrix = Schema.Struct({
153
+ values: Schema.optional(Schema.Array(Schema.Array(Schema.Number))),
154
+ }).pipe(
155
+ Type.object({
156
+ typename: 'test.com/Matrix',
157
+ version: '0.1.0',
158
+ }),
159
+ );
160
+
161
+ const matrix = Obj.make(Matrix, {});
162
+
163
+ Obj.change(matrix, (m) => {
164
+ Obj.setValue(m, ['values', 0, 0], 1);
165
+ Obj.setValue(m, ['values', 0, 1], 2);
166
+ Obj.setValue(m, ['values', 1, 0], 3);
167
+ Obj.setValue(m, ['values', 1, 1], 4);
168
+ });
169
+
170
+ expect(matrix.values?.[0][0]).toBe(1);
171
+ expect(matrix.values?.[0][1]).toBe(2);
172
+ expect(matrix.values?.[1][0]).toBe(3);
173
+ expect(matrix.values?.[1][1]).toBe(4);
174
+ });
175
+
176
+ test('throws error for empty path', ({ expect }) => {
177
+ const person = Obj.make(TestSchema.Person, {
178
+ name: 'John',
179
+ username: 'john',
180
+ email: 'john@example.com',
181
+ });
182
+
183
+ Obj.change(person, (p) => {
184
+ expect(() => Obj.setValue(p, [], 'value')).toThrow('Path must not be empty');
185
+ });
186
+ });
187
+
188
+ test('sets value with single-element path', ({ expect }) => {
189
+ const person = Obj.make(TestSchema.Person, {
190
+ name: 'John',
191
+ username: 'john',
192
+ email: 'john@example.com',
193
+ });
194
+
195
+ Obj.change(person, (p) => Obj.setValue(p, ['age'], 30));
196
+
197
+ expect(person.age).toBe(30);
198
+ });
199
+
200
+ test('handles numeric keys as strings', ({ expect }) => {
201
+ const Item = Schema.Struct({
202
+ value: Schema.optional(Schema.Number),
203
+ });
204
+
205
+ const Container = Schema.Struct({
206
+ name: Schema.String,
207
+ items: Schema.optional(Schema.Array(Item)),
208
+ }).pipe(
209
+ Type.object({
210
+ typename: 'test.com/Container',
211
+ version: '0.1.0',
212
+ }),
213
+ );
214
+
215
+ const container = Obj.make(Container, { name: 'box' });
216
+
217
+ // Using string '0' for array index.
218
+ Obj.change(container, (c) => Obj.setValue(c, ['items', '0', 'value'], 42));
219
+
220
+ expect(container.items?.[0].value).toBe(42);
221
+ });
222
+
223
+ test('handles array with object with required field', ({ expect }) => {
224
+ // This test demonstrates the problematic scenario:
225
+ // An array containing objects that have required fields.
226
+ const Task = Schema.Struct({
227
+ id: Schema.String, // Required field.
228
+ title: Schema.optional(Schema.String),
229
+ completed: Schema.optional(Schema.Boolean),
230
+ });
231
+
232
+ const TodoList = Schema.Struct({
233
+ name: Schema.String,
234
+ tasks: Schema.optional(Schema.Array(Task)),
235
+ }).pipe(
236
+ Type.object({
237
+ typename: 'test.com/TodoList',
238
+ version: '0.1.0',
239
+ }),
240
+ );
241
+
242
+ const todoList = Obj.make(TodoList, { name: 'My Tasks' });
243
+
244
+ // This should work: setting a nested property on an array element.
245
+ // The required 'id' field should be initialized with a default value.
246
+ Obj.change(todoList, (t) => Obj.setValue(t, ['tasks', 0, 'title'], 'Buy groceries'));
247
+
248
+ expect(todoList.tasks?.[0].id).toBe(''); // Default value for required String
249
+ expect(todoList.tasks?.[0].title).toBe('Buy groceries');
250
+ expect(todoList.tasks?.[0].completed).toBeUndefined(); // Optional field not set
251
+ });
252
+
253
+ test('initializes multiple required primitive fields with defaults', ({ expect }) => {
254
+ const Item = Schema.Struct({
255
+ id: Schema.String, // Required - should default to ""
256
+ count: Schema.Number, // Required - should default to 0
257
+ active: Schema.Boolean, // Required - should default to false
258
+ label: Schema.optional(Schema.String), // Optional - should not be initialized
259
+ });
260
+
261
+ const Container = Schema.Struct({
262
+ name: Schema.String,
263
+ items: Schema.optional(Schema.Array(Item)),
264
+ }).pipe(
265
+ Type.object({
266
+ typename: 'test.com/Container',
267
+ version: '0.1.0',
268
+ }),
269
+ );
270
+
271
+ const container = Obj.make(Container, { name: 'box' });
272
+
273
+ Obj.change(container, (c) => Obj.setValue(c, ['items', 0, 'label'], 'First Item'));
274
+
275
+ // All required primitive fields should have default values.
276
+ expect(container.items?.[0].id).toBe('');
277
+ expect(container.items?.[0].count).toBe(0);
278
+ expect(container.items?.[0].active).toBe(false);
279
+ expect(container.items?.[0].label).toBe('First Item');
280
+ });
281
+ });
@@ -0,0 +1,165 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Match from 'effect/Match';
6
+ import * as Option from 'effect/Option';
7
+ import * as SchemaAST from 'effect/SchemaAST';
8
+
9
+ import {
10
+ type SchemaProperty,
11
+ getArrayElementType,
12
+ getBaseType,
13
+ getProperties,
14
+ isArrayType,
15
+ isNestedType,
16
+ } from '@dxos/effect';
17
+ import { invariant } from '@dxos/invariant';
18
+
19
+ import { type Mutable } from '../proxy';
20
+ import { getSchema } from '../types';
21
+
22
+ /**
23
+ * Set a deeply nested property on an object.
24
+ * Must be called within an Obj.change or Relation.change callback.
25
+ */
26
+ export const setValue = (obj: Mutable<any>, path: readonly (string | number)[], value: any): void => {
27
+ invariant(path.length > 0, 'Path must not be empty');
28
+
29
+ const schema = getSchema(obj);
30
+ invariant(schema != null, 'Object must have a schema');
31
+
32
+ let parent = obj;
33
+ let currentAST: SchemaAST.AST | undefined = schema.ast;
34
+
35
+ // Navigate to the parent of the target property.
36
+ for (let i = 0; i < path.length - 1; i++) {
37
+ const part = path[i];
38
+ const key = typeof part === 'number' ? part : String(part);
39
+ if (parent[key] === undefined) {
40
+ const propertyAST = getPropertyAST(currentAST, String(part));
41
+ const shouldBeArray = propertyAST ? isArrayType(propertyAST) : false;
42
+
43
+ if (shouldBeArray) {
44
+ // Create array.
45
+ parent[key] = [];
46
+ } else {
47
+ // TODO(wittjosiah): Is there a better way to handle this than creating an object with defaults?
48
+ // Perhaps properties on objects should be optional by default?
49
+ // Create object with defaults for required fields.
50
+ const objWithDefaults = createObjectWithDefaults(propertyAST);
51
+ parent[key] = objWithDefaults;
52
+ }
53
+ }
54
+
55
+ parent = parent[key];
56
+ currentAST = getPropertyAST(currentAST, String(part));
57
+ }
58
+
59
+ const finalKey = path[path.length - 1];
60
+ parent[finalKey] = value;
61
+
62
+ return value;
63
+ };
64
+
65
+ /**
66
+ * Helper to get the AST of a nested property.
67
+ * @param ast - Current schema AST.
68
+ * @param propertyName - Name of the property to get.
69
+ * @returns The AST of the nested property, or undefined if not found.
70
+ */
71
+ const getPropertyAST = (ast: SchemaAST.AST | undefined, propertyName: string): SchemaAST.AST | undefined => {
72
+ if (!ast) {
73
+ return undefined;
74
+ }
75
+
76
+ if (isNestedType(ast)) {
77
+ const properties = getProperties(ast);
78
+ const property = properties.find((p) => p.name.toString() === propertyName);
79
+ if (property) {
80
+ return getBaseType(property).type;
81
+ }
82
+ }
83
+
84
+ if (isArrayType(ast)) {
85
+ const elementType = getArrayElementType(ast);
86
+ return elementType;
87
+ }
88
+
89
+ return undefined;
90
+ };
91
+
92
+ /**
93
+ * Get all required properties from a schema AST.
94
+ * A property is required if it's not optional.
95
+ *
96
+ * @param ast - Schema AST to inspect.
97
+ * @returns Array of required properties with their types.
98
+ */
99
+ const getRequiredProperties = (ast: SchemaAST.AST | undefined): SchemaProperty[] => {
100
+ if (!ast) {
101
+ return [];
102
+ }
103
+
104
+ // Only objects/structs have properties with optional/required distinction.
105
+ if (!isNestedType(ast)) {
106
+ return [];
107
+ }
108
+
109
+ const properties = getProperties(ast);
110
+
111
+ // Filter to only required properties (where isOptional === false).
112
+ return properties.filter((p) => !p.isOptional);
113
+ };
114
+
115
+ /**
116
+ * Get the default value for a primitive type.
117
+ * Returns undefined for non-primitive or unsupported types.
118
+ *
119
+ * @param ast - Type AST.
120
+ * @returns Default value for the type, or undefined.
121
+ */
122
+ const getDefaultValueForType = (ast: SchemaAST.AST | undefined): any => {
123
+ if (!ast) {
124
+ return undefined;
125
+ }
126
+
127
+ const defaultValue = SchemaAST.getDefaultAnnotation(ast);
128
+ if (Option.isSome(defaultValue)) {
129
+ return defaultValue.value;
130
+ }
131
+
132
+ return Match.value(ast).pipe(
133
+ Match.when({ _tag: 'StringKeyword' }, () => ''),
134
+ Match.when({ _tag: 'NumberKeyword' }, () => 0),
135
+ Match.when({ _tag: 'BooleanKeyword' }, () => false),
136
+ Match.orElse(() => undefined),
137
+ );
138
+ };
139
+
140
+ /**
141
+ * Create an object with default values for all required properties.
142
+ * Handles primitive types (String, Number, Boolean) and recursively initializes required nested objects.
143
+ *
144
+ * @param ast - Schema AST describing the object structure.
145
+ * @returns Object with required fields populated with defaults.
146
+ */
147
+ const createObjectWithDefaults = (ast: SchemaAST.AST | undefined): any => {
148
+ if (!ast) {
149
+ return {};
150
+ }
151
+
152
+ const requiredProps = getRequiredProperties(ast);
153
+ const obj: any = {};
154
+
155
+ for (const prop of requiredProps) {
156
+ const defaultValue = getDefaultValueForType(prop.type);
157
+ if (defaultValue !== undefined) {
158
+ obj[prop.name] = defaultValue;
159
+ } else if (isNestedType(prop.type)) {
160
+ obj[prop.name] = createObjectWithDefaults(prop.type);
161
+ }
162
+ }
163
+
164
+ return obj;
165
+ };