@dxos/echo 0.8.4-main.e098934 → 0.8.4-main.e8ec1fe

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 (311) hide show
  1. package/dist/lib/browser/chunk-BIDAASFK.mjs +3727 -0
  2. package/dist/lib/browser/chunk-BIDAASFK.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-ZDLCWGEW.mjs +410 -0
  4. package/dist/lib/browser/chunk-ZDLCWGEW.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-ZFRJKT4A.mjs +585 -0
  6. package/dist/lib/browser/chunk-ZFRJKT4A.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +10 -5
  8. package/dist/lib/browser/internal/index.mjs +336 -0
  9. package/dist/lib/browser/internal/index.mjs.map +7 -0
  10. package/dist/lib/browser/meta.json +1 -1
  11. package/dist/lib/browser/query/index.mjs +13 -0
  12. package/dist/lib/browser/query/index.mjs.map +7 -0
  13. package/dist/lib/browser/testing/index.mjs +231 -34
  14. package/dist/lib/browser/testing/index.mjs.map +4 -4
  15. package/dist/lib/node-esm/chunk-3SVRRCUU.mjs +3727 -0
  16. package/dist/lib/node-esm/chunk-3SVRRCUU.mjs.map +7 -0
  17. package/dist/lib/node-esm/chunk-CGDHRZWH.mjs +585 -0
  18. package/dist/lib/node-esm/chunk-CGDHRZWH.mjs.map +7 -0
  19. package/dist/lib/node-esm/chunk-HWS6VBQC.mjs +410 -0
  20. package/dist/lib/node-esm/chunk-HWS6VBQC.mjs.map +7 -0
  21. package/dist/lib/node-esm/index.mjs +10 -5
  22. package/dist/lib/node-esm/internal/index.mjs +336 -0
  23. package/dist/lib/node-esm/internal/index.mjs.map +7 -0
  24. package/dist/lib/node-esm/meta.json +1 -1
  25. package/dist/lib/node-esm/query/index.mjs +13 -0
  26. package/dist/lib/node-esm/query/index.mjs.map +7 -0
  27. package/dist/lib/node-esm/testing/index.mjs +231 -34
  28. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  29. package/dist/types/src/Obj.d.ts +26 -7
  30. package/dist/types/src/Obj.d.ts.map +1 -1
  31. package/dist/types/src/Ref.d.ts +1 -1
  32. package/dist/types/src/Ref.d.ts.map +1 -1
  33. package/dist/types/src/Relation.d.ts +5 -4
  34. package/dist/types/src/Relation.d.ts.map +1 -1
  35. package/dist/types/src/Tag.d.ts +17 -0
  36. package/dist/types/src/Tag.d.ts.map +1 -0
  37. package/dist/types/src/Type.d.ts +16 -17
  38. package/dist/types/src/Type.d.ts.map +1 -1
  39. package/dist/types/src/errors.d.ts +14 -18
  40. package/dist/types/src/errors.d.ts.map +1 -1
  41. package/dist/types/src/index.d.ts +3 -2
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/internal/ast/annotation-helper.d.ts +8 -0
  44. package/dist/types/src/internal/ast/annotation-helper.d.ts.map +1 -0
  45. package/dist/types/src/internal/ast/annotations.d.ts +131 -0
  46. package/dist/types/src/internal/ast/annotations.d.ts.map +1 -0
  47. package/dist/types/src/internal/ast/annotations.test.d.ts +2 -0
  48. package/dist/types/src/internal/ast/annotations.test.d.ts.map +1 -0
  49. package/dist/types/src/internal/ast/entity-kind.d.ts +10 -0
  50. package/dist/types/src/internal/ast/entity-kind.d.ts.map +1 -0
  51. package/dist/types/src/internal/ast/index.d.ts +5 -0
  52. package/dist/types/src/internal/ast/index.d.ts.map +1 -0
  53. package/dist/types/src/internal/ast/types.d.ts +6 -0
  54. package/dist/types/src/internal/ast/types.d.ts.map +1 -0
  55. package/dist/types/src/internal/formats/date.d.ts +63 -0
  56. package/dist/types/src/internal/formats/date.d.ts.map +1 -0
  57. package/dist/types/src/internal/formats/date.test.d.ts +2 -0
  58. package/dist/types/src/internal/formats/date.test.d.ts.map +1 -0
  59. package/dist/types/src/internal/formats/format.d.ts +30 -0
  60. package/dist/types/src/internal/formats/format.d.ts.map +1 -0
  61. package/dist/types/src/internal/formats/format.test.d.ts +2 -0
  62. package/dist/types/src/internal/formats/format.test.d.ts.map +1 -0
  63. package/dist/types/src/internal/formats/index.d.ts +8 -0
  64. package/dist/types/src/internal/formats/index.d.ts.map +1 -0
  65. package/dist/types/src/internal/formats/number.d.ts +31 -0
  66. package/dist/types/src/internal/formats/number.d.ts.map +1 -0
  67. package/dist/types/src/internal/formats/object.d.ts +35 -0
  68. package/dist/types/src/internal/formats/object.d.ts.map +1 -0
  69. package/dist/types/src/internal/formats/select.d.ts +11 -0
  70. package/dist/types/src/internal/formats/select.d.ts.map +1 -0
  71. package/dist/types/src/internal/formats/string.d.ts +38 -0
  72. package/dist/types/src/internal/formats/string.d.ts.map +1 -0
  73. package/dist/types/src/internal/formats/types.d.ts +68 -0
  74. package/dist/types/src/internal/formats/types.d.ts.map +1 -0
  75. package/dist/types/src/internal/index.d.ts +15 -0
  76. package/dist/types/src/internal/index.d.ts.map +1 -0
  77. package/dist/types/src/internal/json/annotations.d.ts +19 -0
  78. package/dist/types/src/internal/json/annotations.d.ts.map +1 -0
  79. package/dist/types/src/internal/json/effect-schema.test.d.ts +2 -0
  80. package/dist/types/src/internal/json/effect-schema.test.d.ts.map +1 -0
  81. package/dist/types/src/internal/json/index.d.ts +2 -0
  82. package/dist/types/src/internal/json/index.d.ts.map +1 -0
  83. package/dist/types/src/internal/json/json-schema.d.ts +28 -0
  84. package/dist/types/src/internal/json/json-schema.d.ts.map +1 -0
  85. package/dist/types/src/internal/json/json-schema.test.d.ts +2 -0
  86. package/dist/types/src/internal/json/json-schema.test.d.ts.map +1 -0
  87. package/dist/types/src/internal/json-schema/index.d.ts +3 -0
  88. package/dist/types/src/internal/json-schema/index.d.ts.map +1 -0
  89. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts +7 -0
  90. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +1 -0
  91. package/dist/types/src/internal/json-schema/json-schema-type.d.ts +250 -0
  92. package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +1 -0
  93. package/dist/types/src/internal/object/accessors.d.ts +37 -0
  94. package/dist/types/src/internal/object/accessors.d.ts.map +1 -0
  95. package/dist/types/src/internal/object/common.d.ts +18 -0
  96. package/dist/types/src/internal/object/common.d.ts.map +1 -0
  97. package/dist/types/src/internal/object/create.d.ts +40 -0
  98. package/dist/types/src/internal/object/create.d.ts.map +1 -0
  99. package/dist/types/src/internal/object/create.test.d.ts +2 -0
  100. package/dist/types/src/internal/object/create.test.d.ts.map +1 -0
  101. package/dist/types/src/internal/object/deleted.d.ts +6 -0
  102. package/dist/types/src/internal/object/deleted.d.ts.map +1 -0
  103. package/dist/types/src/internal/object/entity.d.ts +33 -0
  104. package/dist/types/src/internal/object/entity.d.ts.map +1 -0
  105. package/dist/types/src/internal/object/expando.d.ts +14 -0
  106. package/dist/types/src/internal/object/expando.d.ts.map +1 -0
  107. package/dist/types/src/internal/object/ids.d.ts +6 -0
  108. package/dist/types/src/internal/object/ids.d.ts.map +1 -0
  109. package/dist/types/src/internal/object/index.d.ts +16 -0
  110. package/dist/types/src/internal/object/index.d.ts.map +1 -0
  111. package/dist/types/src/internal/object/inspect.d.ts +2 -0
  112. package/dist/types/src/internal/object/inspect.d.ts.map +1 -0
  113. package/dist/types/src/internal/object/json-serializer.d.ts +32 -0
  114. package/dist/types/src/internal/object/json-serializer.d.ts.map +1 -0
  115. package/dist/types/src/internal/object/json-serializer.test.d.ts +2 -0
  116. package/dist/types/src/internal/object/json-serializer.test.d.ts.map +1 -0
  117. package/dist/types/src/internal/object/meta.d.ts +31 -0
  118. package/dist/types/src/internal/object/meta.d.ts.map +1 -0
  119. package/dist/types/src/internal/object/model.d.ts +117 -0
  120. package/dist/types/src/internal/object/model.d.ts.map +1 -0
  121. package/dist/types/src/internal/object/relation.d.ts +17 -0
  122. package/dist/types/src/internal/object/relation.d.ts.map +1 -0
  123. package/dist/types/src/internal/object/schema-validator.d.ts +15 -0
  124. package/dist/types/src/internal/object/schema-validator.d.ts.map +1 -0
  125. package/dist/types/src/internal/object/schema-validator.test.d.ts +2 -0
  126. package/dist/types/src/internal/object/schema-validator.test.d.ts.map +1 -0
  127. package/dist/types/src/internal/object/typed-object.d.ts +31 -0
  128. package/dist/types/src/internal/object/typed-object.d.ts.map +1 -0
  129. package/dist/types/src/internal/object/typed-object.test.d.ts +2 -0
  130. package/dist/types/src/internal/object/typed-object.test.d.ts.map +1 -0
  131. package/dist/types/src/internal/object/typename.d.ts +15 -0
  132. package/dist/types/src/internal/object/typename.d.ts.map +1 -0
  133. package/dist/types/src/internal/object/version.d.ts +14 -0
  134. package/dist/types/src/internal/object/version.d.ts.map +1 -0
  135. package/dist/types/src/internal/projection/compose.d.ts +6 -0
  136. package/dist/types/src/internal/projection/compose.d.ts.map +1 -0
  137. package/dist/types/src/internal/projection/compose.test.d.ts +2 -0
  138. package/dist/types/src/internal/projection/compose.test.d.ts.map +1 -0
  139. package/dist/types/src/internal/projection/index.d.ts +2 -0
  140. package/dist/types/src/internal/projection/index.d.ts.map +1 -0
  141. package/dist/types/src/internal/proxy/handler.test.d.ts +2 -0
  142. package/dist/types/src/internal/proxy/handler.test.d.ts.map +1 -0
  143. package/dist/types/src/internal/proxy/reactive-object.d.ts +15 -0
  144. package/dist/types/src/internal/proxy/reactive-object.d.ts.map +1 -0
  145. package/dist/types/src/internal/proxy/schema.test.d.ts +2 -0
  146. package/dist/types/src/internal/proxy/schema.test.d.ts.map +1 -0
  147. package/dist/types/src/internal/proxy/typed-handler.d.ts +44 -0
  148. package/dist/types/src/internal/proxy/typed-handler.d.ts.map +1 -0
  149. package/dist/types/src/internal/proxy/typed-handler.test.d.ts +2 -0
  150. package/dist/types/src/internal/proxy/typed-handler.test.d.ts.map +1 -0
  151. package/dist/types/src/internal/proxy/typed-object.test.d.ts +2 -0
  152. package/dist/types/src/internal/proxy/typed-object.test.d.ts.map +1 -0
  153. package/dist/types/src/internal/query/index.d.ts +2 -0
  154. package/dist/types/src/internal/query/index.d.ts.map +1 -0
  155. package/dist/types/src/internal/query/query.d.ts +17 -0
  156. package/dist/types/src/internal/query/query.d.ts.map +1 -0
  157. package/dist/types/src/internal/ref/index.d.ts +3 -0
  158. package/dist/types/src/internal/ref/index.d.ts.map +1 -0
  159. package/dist/types/src/internal/ref/ref-array.d.ts +21 -0
  160. package/dist/types/src/internal/ref/ref-array.d.ts.map +1 -0
  161. package/dist/types/src/internal/ref/ref.d.ts +206 -0
  162. package/dist/types/src/internal/ref/ref.d.ts.map +1 -0
  163. package/dist/types/src/internal/ref/ref.test.d.ts +2 -0
  164. package/dist/types/src/internal/ref/ref.test.d.ts.map +1 -0
  165. package/dist/types/src/internal/schema/echo-schema.d.ts +168 -0
  166. package/dist/types/src/internal/schema/echo-schema.d.ts.map +1 -0
  167. package/dist/types/src/internal/schema/index.d.ts +7 -0
  168. package/dist/types/src/internal/schema/index.d.ts.map +1 -0
  169. package/dist/types/src/internal/schema/manipulation.d.ts +10 -0
  170. package/dist/types/src/internal/schema/manipulation.d.ts.map +1 -0
  171. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts +18 -0
  172. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts.map +1 -0
  173. package/dist/types/src/internal/schema/snapshot.d.ts +6 -0
  174. package/dist/types/src/internal/schema/snapshot.d.ts.map +1 -0
  175. package/dist/types/src/internal/schema/stored-schema.d.ts +13 -0
  176. package/dist/types/src/internal/schema/stored-schema.d.ts.map +1 -0
  177. package/dist/types/src/internal/testing/index.d.ts +3 -0
  178. package/dist/types/src/internal/testing/index.d.ts.map +1 -0
  179. package/dist/types/src/internal/testing/types.d.ts +381 -0
  180. package/dist/types/src/internal/testing/types.d.ts.map +1 -0
  181. package/dist/types/src/internal/testing/utils.d.ts +10 -0
  182. package/dist/types/src/internal/testing/utils.d.ts.map +1 -0
  183. package/dist/types/src/internal/types/index.d.ts +3 -0
  184. package/dist/types/src/internal/types/index.d.ts.map +1 -0
  185. package/dist/types/src/internal/types/types.d.ts +79 -0
  186. package/dist/types/src/internal/types/types.d.ts.map +1 -0
  187. package/dist/types/src/internal/types/types.test.d.ts +2 -0
  188. package/dist/types/src/internal/types/types.test.d.ts.map +1 -0
  189. package/dist/types/src/internal/types/util.d.ts +5 -0
  190. package/dist/types/src/internal/types/util.d.ts.map +1 -0
  191. package/dist/types/src/query/index.d.ts +1 -1
  192. package/dist/types/src/query/index.d.ts.map +1 -1
  193. package/dist/types/src/query/{dsl.d.ts → query.d.ts} +28 -23
  194. package/dist/types/src/query/query.d.ts.map +1 -0
  195. package/dist/types/src/query/query.test.d.ts +2 -0
  196. package/dist/types/src/query/query.test.d.ts.map +1 -0
  197. package/dist/types/src/testing/echo-schema.d.ts +7 -0
  198. package/dist/types/src/testing/echo-schema.d.ts.map +1 -0
  199. package/dist/types/src/testing/index.d.ts +2 -0
  200. package/dist/types/src/testing/index.d.ts.map +1 -1
  201. package/dist/types/src/testing/types.d.ts +170 -55
  202. package/dist/types/src/testing/types.d.ts.map +1 -1
  203. package/dist/types/tsconfig.tsbuildinfo +1 -1
  204. package/package.json +29 -18
  205. package/src/Obj.ts +98 -14
  206. package/src/Ref.ts +1 -2
  207. package/src/Relation.ts +15 -5
  208. package/src/Tag.ts +39 -0
  209. package/src/Type.ts +29 -30
  210. package/src/index.ts +3 -2
  211. package/src/internal/ast/annotation-helper.ts +22 -0
  212. package/src/internal/ast/annotations.test.ts +98 -0
  213. package/src/internal/ast/annotations.ts +226 -0
  214. package/src/internal/ast/entity-kind.ts +15 -0
  215. package/src/internal/ast/index.ts +8 -0
  216. package/src/internal/ast/types.ts +17 -0
  217. package/src/internal/formats/date.test.ts +56 -0
  218. package/src/internal/formats/date.ts +217 -0
  219. package/src/internal/formats/format.test.ts +77 -0
  220. package/src/internal/formats/format.ts +52 -0
  221. package/src/internal/formats/index.ts +12 -0
  222. package/src/internal/formats/number.ts +89 -0
  223. package/src/internal/formats/object.ts +80 -0
  224. package/src/internal/formats/select.ts +16 -0
  225. package/src/internal/formats/string.ts +76 -0
  226. package/src/internal/formats/types.ts +175 -0
  227. package/src/internal/index.ts +22 -0
  228. package/src/internal/json/annotations.ts +50 -0
  229. package/src/internal/json/effect-schema.test.ts +143 -0
  230. package/src/internal/json/index.ts +5 -0
  231. package/src/internal/json/json-schema.test.ts +849 -0
  232. package/src/internal/json/json-schema.ts +519 -0
  233. package/src/internal/json-schema/index.ts +6 -0
  234. package/src/internal/json-schema/json-schema-normalize.ts +109 -0
  235. package/src/internal/json-schema/json-schema-type.ts +403 -0
  236. package/src/internal/object/accessors.ts +153 -0
  237. package/src/internal/object/common.ts +76 -0
  238. package/src/internal/object/create.test.ts +118 -0
  239. package/src/internal/object/create.ts +96 -0
  240. package/src/internal/object/deleted.ts +19 -0
  241. package/src/internal/object/entity.ts +248 -0
  242. package/src/internal/object/expando.ts +21 -0
  243. package/src/internal/object/ids.ts +12 -0
  244. package/src/internal/object/index.ts +19 -0
  245. package/src/internal/object/inspect.ts +48 -0
  246. package/src/internal/object/json-serializer.test.ts +99 -0
  247. package/src/internal/object/json-serializer.ts +225 -0
  248. package/src/internal/object/meta.ts +61 -0
  249. package/src/internal/object/model.ts +170 -0
  250. package/src/internal/object/relation.ts +24 -0
  251. package/src/internal/object/schema-validator.test.ts +186 -0
  252. package/src/internal/object/schema-validator.ts +241 -0
  253. package/src/internal/object/typed-object.test.ts +34 -0
  254. package/src/internal/object/typed-object.ts +88 -0
  255. package/src/internal/object/typename.ts +61 -0
  256. package/src/internal/object/version.ts +22 -0
  257. package/src/internal/projection/compose.test.ts +43 -0
  258. package/src/internal/projection/compose.ts +36 -0
  259. package/src/internal/projection/index.ts +5 -0
  260. package/src/internal/proxy/handler.test.ts +163 -0
  261. package/src/internal/proxy/reactive-object.ts +108 -0
  262. package/src/internal/proxy/schema.test.ts +136 -0
  263. package/src/internal/proxy/typed-handler.test.ts +102 -0
  264. package/src/internal/proxy/typed-handler.ts +228 -0
  265. package/src/internal/proxy/typed-object.test.ts +100 -0
  266. package/src/internal/query/index.ts +5 -0
  267. package/src/internal/query/query.ts +23 -0
  268. package/src/internal/ref/index.ts +6 -0
  269. package/src/internal/ref/ref-array.ts +39 -0
  270. package/src/internal/ref/ref.test.ts +100 -0
  271. package/src/internal/ref/ref.ts +521 -0
  272. package/src/internal/schema/echo-schema.ts +383 -0
  273. package/src/internal/schema/index.ts +10 -0
  274. package/src/internal/schema/manipulation.ts +92 -0
  275. package/src/internal/schema/runtime-schema-registry.ts +78 -0
  276. package/src/internal/schema/snapshot.ts +25 -0
  277. package/src/internal/schema/stored-schema.ts +26 -0
  278. package/src/internal/testing/index.ts +6 -0
  279. package/src/internal/testing/types.ts +144 -0
  280. package/src/internal/testing/utils.ts +54 -0
  281. package/src/internal/types/index.ts +6 -0
  282. package/src/internal/types/types.test.ts +48 -0
  283. package/src/internal/types/types.ts +176 -0
  284. package/src/internal/types/util.ts +9 -0
  285. package/src/query/index.ts +2 -1
  286. package/src/query/query.test.ts +401 -0
  287. package/src/query/{dsl.ts → query.ts} +82 -45
  288. package/src/test/api.test.ts +9 -9
  289. package/src/testing/echo-schema.ts +39 -0
  290. package/src/testing/index.ts +2 -0
  291. package/src/testing/types.ts +40 -23
  292. package/dist/lib/browser/chunk-EIXXFUN5.mjs +0 -839
  293. package/dist/lib/browser/chunk-EIXXFUN5.mjs.map +0 -7
  294. package/dist/lib/node-esm/chunk-TCY7IVTS.mjs +0 -839
  295. package/dist/lib/node-esm/chunk-TCY7IVTS.mjs.map +0 -7
  296. package/dist/types/src/experimental/database.d.ts +0 -8
  297. package/dist/types/src/experimental/database.d.ts.map +0 -1
  298. package/dist/types/src/experimental/index.d.ts +0 -1
  299. package/dist/types/src/experimental/index.d.ts.map +0 -1
  300. package/dist/types/src/experimental/queue.d.ts +0 -8
  301. package/dist/types/src/experimental/queue.d.ts.map +0 -1
  302. package/dist/types/src/experimental/space.d.ts +0 -8
  303. package/dist/types/src/experimental/space.d.ts.map +0 -1
  304. package/dist/types/src/query/dsl.d.ts.map +0 -1
  305. package/dist/types/src/query/dsl.test.d.ts +0 -2
  306. package/dist/types/src/query/dsl.test.d.ts.map +0 -1
  307. package/src/experimental/database.ts +0 -11
  308. package/src/experimental/index.ts +0 -7
  309. package/src/experimental/queue.ts +0 -11
  310. package/src/experimental/space.ts +0 -11
  311. package/src/query/dsl.test.ts +0 -362
@@ -0,0 +1,108 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import type * as Schema from 'effect/Schema';
6
+
7
+ import { ObjectId } from '@dxos/keys';
8
+ import {
9
+ type Live,
10
+ UntypedReactiveHandler,
11
+ createProxy,
12
+ defineHiddenProperty,
13
+ isValidProxyTarget,
14
+ } from '@dxos/live-object';
15
+
16
+ import { getTypeAnnotation } from '../ast';
17
+ import { EntityKindId, Expando, MetaId, type ObjectMeta, ObjectMetaSchema, attachTypedJsonSerializer } from '../object';
18
+ import type { BaseObject, CreationProps } from '../types';
19
+
20
+ import { TypedReactiveHandler, prepareTypedTarget } from './typed-handler';
21
+
22
+ /**
23
+ * Creates a reactive object from a plain Javascript object.
24
+ * Optionally provides a TS-effect schema.
25
+ *
26
+ * @depreacted Use `Obj.make`.
27
+ */
28
+ // TODO(dmaretskyi): Deep mutability.
29
+ // TODO(dmaretskyi): Invert generics (generic over schema) to have better error messages.
30
+ // TODO(dmaretskyi): Could mutate original object making it unusable.
31
+ // TODO(burdon): Use Schema.make() to handle defaults?
32
+ export const live: {
33
+ <T extends BaseObject>(obj: T): Live<T>;
34
+ <T extends BaseObject>(
35
+ schema: Schema.Schema<T, any, never>,
36
+ obj: NoInfer<CreationProps<T>>,
37
+ meta?: ObjectMeta,
38
+ ): Live<T>;
39
+ } = <T extends BaseObject>(
40
+ objOrSchema: Schema.Schema<T, any> | T,
41
+ obj?: CreationProps<T>,
42
+ meta?: ObjectMeta,
43
+ ): Live<T> => {
44
+ // TODO(dmaretskyi): Remove Expando special case.
45
+ if (obj && (objOrSchema as any) !== Expando) {
46
+ return createReactiveObject<T>({ ...obj } as T, meta, objOrSchema as Schema.Schema<T, any>);
47
+ } else if (obj && (objOrSchema as any) === Expando) {
48
+ return createReactiveObject<T>({ ...obj } as T, meta, undefined, { expando: true });
49
+ } else {
50
+ return createReactiveObject<T>(objOrSchema as T, meta);
51
+ }
52
+ };
53
+
54
+ const createReactiveObject = <T extends BaseObject>(
55
+ obj: T,
56
+ meta?: ObjectMeta,
57
+ schema?: Schema.Schema<T>,
58
+ options?: { expando?: boolean },
59
+ ): Live<T> => {
60
+ if (!isValidProxyTarget(obj)) {
61
+ throw new Error('Value cannot be made into a reactive object.');
62
+ }
63
+
64
+ if (schema) {
65
+ const annotation = getTypeAnnotation(schema);
66
+ const shouldGenerateId = options?.expando || !!annotation;
67
+ if (shouldGenerateId) {
68
+ setIdOnTarget(obj);
69
+ }
70
+ if (annotation) {
71
+ defineHiddenProperty(obj, EntityKindId, annotation.kind);
72
+ }
73
+ initMeta(obj, meta);
74
+ prepareTypedTarget(obj, schema);
75
+ attachTypedJsonSerializer(obj);
76
+ return createProxy<T>(obj, TypedReactiveHandler.instance);
77
+ } else {
78
+ if (options?.expando) {
79
+ setIdOnTarget(obj);
80
+ }
81
+ initMeta(obj, meta);
82
+ return createProxy<T>(obj, UntypedReactiveHandler.instance);
83
+ }
84
+ };
85
+
86
+ /**
87
+ * Set ID on ECHO object targets during creation.
88
+ * Used for objects with schema and the ones explicitly marked as Expando.
89
+ */
90
+ const setIdOnTarget = (target: any) => {
91
+ // invariant(!('id' in target), 'Object already has an `id` field, which is reserved.');
92
+ if ('id' in target && target.id !== undefined && target.id !== null) {
93
+ if (!ObjectId.isValid(target.id)) {
94
+ throw new Error('Invalid object id format.');
95
+ }
96
+ } else {
97
+ target.id = ObjectId.random();
98
+ }
99
+ };
100
+
101
+ /**
102
+ * Set metadata on object.
103
+ */
104
+ // TODO(dmaretskyi): Move to echo-schema.
105
+ const initMeta = <T>(obj: T, meta: ObjectMeta = { keys: [] }) => {
106
+ prepareTypedTarget(meta, ObjectMetaSchema);
107
+ defineHiddenProperty(obj, MetaId, createProxy(meta, TypedReactiveHandler.instance as any));
108
+ };
@@ -0,0 +1,136 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import * as SchemaAST from 'effect/SchemaAST';
7
+ import { describe, expect, test } from 'vitest';
8
+
9
+ import { PropertyMeta, TypedObject, getPropertyMetaAnnotation, getTypeAnnotation } from '..';
10
+ import { createEchoSchema } from '../../testing/echo-schema';
11
+
12
+ // TODO(dmaretskyi): Comment.
13
+ class EmptySchemaType extends TypedObject({
14
+ typename: 'example.com/type/Empty',
15
+ version: '0.1.0',
16
+ })({}) {}
17
+
18
+ describe('dynamic schema', () => {
19
+ test('getProperties filters out id and unwraps optionality', async () => {
20
+ class TestSchema extends TypedObject({
21
+ typename: 'example.com/type/Test',
22
+ version: '0.1.0',
23
+ })({
24
+ field1: Schema.String,
25
+ field2: Schema.Boolean,
26
+ }) {}
27
+
28
+ const registered = createEchoSchema(TestSchema);
29
+ expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
30
+ ['field1', SchemaAST.stringKeyword],
31
+ ['field2', SchemaAST.booleanKeyword],
32
+ ]);
33
+ });
34
+
35
+ test('addColumns', async () => {
36
+ class TestSchema extends TypedObject({
37
+ typename: 'example.com/type/Test',
38
+ version: '0.1.0',
39
+ })({
40
+ field1: Schema.String,
41
+ }) {}
42
+
43
+ const registered = createEchoSchema(TestSchema);
44
+ registered.addFields({ field2: Schema.Boolean });
45
+ expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
46
+ ['field1', SchemaAST.stringKeyword],
47
+ ['field2', SchemaAST.booleanKeyword],
48
+ ]);
49
+ });
50
+
51
+ test('updateColumns preserves order of existing and appends new fields', async () => {
52
+ const registered = createEchoSchema(EmptySchemaType);
53
+ registered.addFields({ field1: Schema.String });
54
+ registered.addFields({ field2: Schema.Boolean });
55
+ registered.addFields({ field3: Schema.Number });
56
+ registered.updateFields({ field4: Schema.Boolean, field2: Schema.String });
57
+ expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
58
+ ['field1', SchemaAST.stringKeyword],
59
+ ['field2', SchemaAST.stringKeyword],
60
+ ['field3', SchemaAST.numberKeyword],
61
+ ['field4', SchemaAST.booleanKeyword],
62
+ ]);
63
+ });
64
+
65
+ test('removeColumns', async () => {
66
+ const registered = createEchoSchema(EmptySchemaType);
67
+ registered.addFields({ field1: Schema.String });
68
+ registered.addFields({ field2: Schema.Boolean });
69
+ registered.addFields({ field3: Schema.Number });
70
+ registered.removeFields(['field2']);
71
+ expect(registered.getProperties().map((p) => [p.name, p.type])).to.deep.eq([
72
+ ['field1', SchemaAST.stringKeyword],
73
+ ['field3', SchemaAST.numberKeyword],
74
+ ]);
75
+ });
76
+
77
+ test('schema manipulations preserve annotations', async () => {
78
+ const metaNamespace = 'dxos.test';
79
+ const metaInfo = { maxLength: 10 };
80
+ const registered = createEchoSchema(EmptySchemaType);
81
+ registered.addFields({
82
+ field1: Schema.String.pipe(PropertyMeta(metaNamespace, metaInfo)),
83
+ field2: Schema.String,
84
+ });
85
+ registered.addFields({ field3: Schema.String });
86
+ registered.updateFields({ field3: Schema.Boolean });
87
+ registered.removeFields(['field2']);
88
+ expect(getTypeAnnotation(registered)).to.deep.contain({
89
+ typename: 'example.com/type/Empty',
90
+ version: '0.1.0',
91
+ });
92
+ expect(getPropertyMetaAnnotation(registered.getProperties()[0], metaNamespace)).to.deep.eq(metaInfo);
93
+ });
94
+
95
+ test('updates typename', async ({ expect }) => {
96
+ // Create schema with some fields and annotations.
97
+ const registered = createEchoSchema(EmptySchemaType);
98
+ const originalVersion = registered.storedSchema.version;
99
+ registered.addFields({
100
+ name: Schema.String.pipe(PropertyMeta('test', { maxLength: 10 })),
101
+ age: Schema.Number,
102
+ });
103
+
104
+ // First update.
105
+ const newTypename1 = 'example.com/type/Individual';
106
+ registered.updateTypename(newTypename1);
107
+
108
+ // Basic typename update checks.
109
+ expect(registered.typename).toBe(newTypename1);
110
+ expect(registered.jsonSchema.$id).toBe(`dxn:type:${newTypename1}`);
111
+ expect(registered.jsonSchema.typename).toBe(newTypename1);
112
+
113
+ // Version preservation check.
114
+ expect(registered.storedSchema.version).toBe(originalVersion);
115
+
116
+ // Field preservation check.
117
+ const properties = registered.getProperties();
118
+ expect(properties).toHaveLength(2);
119
+ expect(properties[0].name).toBe('name');
120
+
121
+ // Annotation preservation check.
122
+ const nameMeta = getPropertyMetaAnnotation(properties[0], 'test');
123
+ expect(nameMeta).toEqual({ maxLength: 10 });
124
+
125
+ // Second update to ensure multiple updates work.
126
+ const newTypename2 = 'example.com/type/Person';
127
+ registered.updateTypename(newTypename2);
128
+ expect(registered.typename).toBe(newTypename2);
129
+ expect(registered.jsonSchema.$id).toBe(`dxn:type:${newTypename2}`);
130
+ expect(registered.jsonSchema.typename).toBe(newTypename2);
131
+ expect(getTypeAnnotation(registered)).to.deep.contain({
132
+ typename: 'example.com/type/Person',
133
+ version: '0.1.0',
134
+ });
135
+ });
136
+ });
@@ -0,0 +1,102 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, expect, test } from 'vitest';
7
+
8
+ import { Ref, TypedObject, create, foreignKey, getMeta, getSchema, isInstanceOf } from '..';
9
+ import { Testing } from '../testing';
10
+
11
+ import { live } from './reactive-object';
12
+
13
+ describe('complex schema validations', () => {
14
+ const setValue = (target: any, prop: string, value: any) => {
15
+ target[prop] = value;
16
+ };
17
+
18
+ test('any', () => {
19
+ const schema = Schema.Struct({ field: Schema.Any });
20
+ const object = live(schema, { field: { nested: { value: 100 } } });
21
+ expect(() => setValue(object, 'field', { any: 'value' })).not.to.throw();
22
+ });
23
+
24
+ test('meta', () => {
25
+ const source = 'test';
26
+ const schema = Schema.Struct({ field: Schema.Number });
27
+ const object = live(schema, { field: 42 }, { keys: [foreignKey(source, '123')] });
28
+ expect(getMeta(object).keys).to.deep.eq([foreignKey(source, '123')]);
29
+ });
30
+
31
+ test('object', () => {
32
+ const schema = Schema.Struct({ field: Schema.optional(Schema.Object) });
33
+ const object = live(schema, { field: { nested: { value: 100 } } });
34
+ expect(() => setValue(object, 'field', { any: 'value' })).not.to.throw();
35
+ });
36
+
37
+ test('references', () => {
38
+ class Foo extends TypedObject({ typename: 'example.com/type/Foo', version: '0.1.0' })({ field: Schema.String }) {}
39
+ class Bar extends TypedObject({ typename: 'example.com/type/Bar', version: '0.1.0' })({ fooRef: Ref(Foo) }) {}
40
+ const field = 'hello';
41
+ expect(() => live(Bar, { fooRef: { id: '1', field } as any })).to.throw();
42
+ expect(() => live(Bar, { fooRef: undefined as any })).to.throw(); // Unresolved reference.
43
+ const bar = live(Bar, { fooRef: Ref.make(live(Foo, { field })) });
44
+ expect(bar.fooRef.target?.field).to.eq(field);
45
+ });
46
+
47
+ test('index signatures', () => {
48
+ const schema = Schema.Struct({}, { key: Schema.String, value: Schema.Number });
49
+ const object = live(schema, { unknownField: 1 });
50
+ expect(() => setValue(object, 'field', '42')).to.throw();
51
+ expect(() => setValue(object, 'unknown_field', 42)).not.to.throw();
52
+ });
53
+
54
+ test('suspend', () => {
55
+ const schema = Schema.Struct({
56
+ array: Schema.optional(Schema.suspend(() => Schema.Array(Schema.Union(Schema.Null, Schema.Number)))),
57
+ object: Schema.optional(Schema.suspend(() => Schema.Union(Schema.Null, Schema.Struct({ field: Schema.Number })))),
58
+ });
59
+
60
+ const object = live(schema, { array: [1, 2, null], object: { field: 3 } });
61
+ expect(() => setValue(object, 'object', { field: 4 })).not.to.throw();
62
+ expect(() => setValue(object.object, 'field', 4)).not.to.throw();
63
+ expect(() => setValue(object.array, '0', 4)).not.to.throw();
64
+ expect(() => setValue(object.array, '0', '4')).to.throw();
65
+ });
66
+
67
+ test('nesting static objects with schema in the live object', () => {
68
+ const contact1 = create(Testing.Person, {
69
+ name: 'Robert Smith',
70
+ email: 'robert@example.com',
71
+ } as any);
72
+ const contact2 = create(Testing.Person, {
73
+ name: 'Katy Perry',
74
+ email: 'katy@example.com',
75
+ } as any);
76
+
77
+ const contactBook = live({
78
+ contacts: [contact1],
79
+ });
80
+
81
+ expect(isInstanceOf(Testing.Person, contactBook.contacts[0])).to.eq(true);
82
+ expect(getSchema(contactBook.contacts[0])).to.eq(Testing.Person);
83
+
84
+ contactBook.contacts.push(contact2);
85
+ expect(isInstanceOf(Testing.Person, contactBook.contacts[1])).to.eq(true);
86
+ expect(getSchema(contactBook.contacts[1])).to.eq(Testing.Person);
87
+ });
88
+
89
+ test('creating an object with data from another object', () => {
90
+ const contact = live(Testing.Person, {
91
+ name: 'Robert Smith',
92
+ email: 'robert@example.com',
93
+ });
94
+ const TestSchema = Schema.Struct({
95
+ value: Schema.Unknown,
96
+ });
97
+ const data = live(TestSchema, {
98
+ value: contact,
99
+ });
100
+ expect((data.value as any).name).to.eq('Robert Smith');
101
+ });
102
+ });
@@ -0,0 +1,228 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type InspectOptionsStylized } from 'node:util';
6
+
7
+ import * as Schema from 'effect/Schema';
8
+ import * as SchemaAST from 'effect/SchemaAST';
9
+
10
+ import { inspectCustom } from '@dxos/debug';
11
+ import { type GenericSignal, compositeRuntime } from '@dxos/echo-signals/runtime';
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
+
23
+ import { getSchemaDXN } from '../ast';
24
+ import { DeletedId, SchemaId, SchemaValidator, TypeId } from '../object';
25
+
26
+ const symbolSignal = Symbol('signal');
27
+ const symbolPropertySignal = Symbol('property-signal');
28
+
29
+ type ProxyTarget = {
30
+ /**
31
+ * Typename or type DXN.
32
+ */
33
+ [TypeId]: string;
34
+
35
+ /**
36
+ * Schema for the root.
37
+ */
38
+ [SchemaId]: Schema.Schema.AnyNoContext;
39
+
40
+ /**
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.
48
+ */
49
+ [symbolPropertySignal]: GenericSignal;
50
+ } & ({ [key: keyof any]: any } | any[]);
51
+
52
+ /**
53
+ * Typed in-memory reactive store (with Schema).
54
+ */
55
+ export class TypedReactiveHandler implements ReactiveHandler<ProxyTarget> {
56
+ public static readonly instance: ReactiveHandler<any> = new TypedReactiveHandler();
57
+
58
+ readonly _proxyMap = new WeakMap<object, any>();
59
+
60
+ private constructor() {}
61
+
62
+ init(target: ProxyTarget): void {
63
+ invariant(typeof target === 'object' && target !== null);
64
+ invariant(SchemaId in target, 'Schema is not defined for the target');
65
+
66
+ if (!(symbolSignal in target)) {
67
+ defineHiddenProperty(target, symbolSignal, compositeRuntime.createSignal());
68
+ defineHiddenProperty(target, symbolPropertySignal, compositeRuntime.createSignal());
69
+ }
70
+
71
+ defineHiddenProperty(target, DeletedId, false);
72
+
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
+ }
79
+
80
+ // Array reactivity is already handled by the schema validator.
81
+ }
82
+
83
+ // Maybe have been set by `create`.
84
+ Object.defineProperty(target, inspectCustom, {
85
+ enumerable: false,
86
+ configurable: true,
87
+ value: this._inspect.bind(target),
88
+ });
89
+ }
90
+
91
+ get(target: ProxyTarget, prop: string | symbol, receiver: any): any {
92
+ switch (prop) {
93
+ case objectData: {
94
+ target[symbolSignal].notifyRead();
95
+ return toJSON(target);
96
+ }
97
+ }
98
+
99
+ // Handle getter properties. Will not subscribe the value signal.
100
+ if (Object.getOwnPropertyDescriptor(target, prop)?.get) {
101
+ target[symbolPropertySignal].notifyRead();
102
+
103
+ // TODO(dmaretskyi): Turn getters into computed fields.
104
+ return Reflect.get(target, prop, receiver);
105
+ }
106
+
107
+ target[symbolSignal].notifyRead();
108
+ target[symbolPropertySignal].notifyRead();
109
+
110
+ const value = Reflect.get(target, prop, receiver);
111
+ if (isValidProxyTarget(value)) {
112
+ return createProxy(value, this);
113
+ }
114
+
115
+ return value;
116
+ }
117
+
118
+ 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);
122
+ }
123
+
124
+ 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
+ });
130
+ return result;
131
+ }
132
+
133
+ 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
+ return Reflect.ownKeys(target);
138
+ }
139
+
140
+ defineProperty(target: ProxyTarget, property: string | symbol, attributes: PropertyDescriptor): boolean {
141
+ const validatedValue = this._validateValue(target, property, attributes.value);
142
+ const result = Reflect.defineProperty(target, property, {
143
+ ...attributes,
144
+ value: validatedValue,
145
+ });
146
+ target[symbolPropertySignal].notifyWrite();
147
+ return result;
148
+ }
149
+
150
+ private _validateValue(target: any, prop: string | symbol, value: any) {
151
+ const schema = SchemaValidator.getTargetPropertySchema(target, prop);
152
+ const _ = Schema.asserts(schema)(value);
153
+ if (Array.isArray(value)) {
154
+ value = new ReactiveArray(...value);
155
+ }
156
+ if (isValidProxyTarget(value)) {
157
+ setSchemaProperties(value, schema);
158
+ }
159
+
160
+ return value;
161
+ }
162
+
163
+ private _inspect(
164
+ _: number,
165
+ options: InspectOptionsStylized,
166
+ inspectFn: (value: any, options?: InspectOptionsStylized) => string,
167
+ ): string {
168
+ const inspected = inspectFn(this, {
169
+ ...options,
170
+ showHidden: false,
171
+ customInspect: false,
172
+ });
173
+ return `Typed ${inspected}`;
174
+ }
175
+ }
176
+
177
+ /**
178
+ * @deprecated Use `Obj.toJSON` instead.
179
+ */
180
+ const toJSON = (target: ProxyTarget): any => {
181
+ return { '@type': 'TypedReactiveObject', ...target };
182
+ };
183
+
184
+ /**
185
+ * Recursively set AST on all potential proxy targets.
186
+ */
187
+ const setSchemaProperties = (obj: any, schema: Schema.Schema.AnyNoContext) => {
188
+ const schemaType = getSchemaDXN(schema);
189
+ if (schemaType != null) {
190
+ defineHiddenProperty(obj, TypeId, schemaType);
191
+ }
192
+
193
+ defineHiddenProperty(obj, SchemaId, schema);
194
+ for (const key in obj) {
195
+ if (isValidProxyTarget(obj[key])) {
196
+ const elementSchema = SchemaValidator.getTargetPropertySchema(obj, key);
197
+ if (elementSchema != null) {
198
+ setSchemaProperties(obj[key], elementSchema);
199
+ }
200
+ }
201
+ }
202
+ };
203
+
204
+ export const prepareTypedTarget = <T>(target: T, schema: Schema.Schema<T>) => {
205
+ // log.info('prepareTypedTarget', { target, schema });
206
+ if (!SchemaAST.isTypeLiteral(schema.ast)) {
207
+ throw new Error('schema has to describe an object type');
208
+ }
209
+
210
+ SchemaValidator.validateSchema(schema);
211
+ const _ = Schema.asserts(schema)(target);
212
+ makeArraysReactive(target);
213
+ setSchemaProperties(target, schema);
214
+ };
215
+
216
+ const makeArraysReactive = (target: any) => {
217
+ for (const key in target) {
218
+ if (target[symbolIsProxy]) {
219
+ continue;
220
+ }
221
+ if (Array.isArray(target[key])) {
222
+ target[key] = ReactiveArray.from(target[key]);
223
+ }
224
+ if (typeof target[key] === 'object') {
225
+ makeArraysReactive(target[key]);
226
+ }
227
+ }
228
+ };
@@ -0,0 +1,100 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+ import { describe, expect, test } from 'vitest';
7
+
8
+ import { EchoObject, TypedObject, getSchema } from '..';
9
+
10
+ import { live } from './reactive-object';
11
+
12
+ const Organization = Schema.Struct({
13
+ name: Schema.String,
14
+ }).pipe(
15
+ EchoObject({
16
+ typename: 'example.com/type/Organization',
17
+ version: '0.1.0',
18
+ }),
19
+ );
20
+
21
+ interface Organization extends Schema.Schema.Type<typeof Organization> {}
22
+
23
+ const Contact = Schema.Struct(
24
+ {
25
+ name: Schema.String,
26
+ },
27
+ { key: Schema.String, value: Schema.Any },
28
+ ).pipe(
29
+ Schema.partial,
30
+ EchoObject({
31
+ typename: 'example.com/type/Person',
32
+ version: '0.1.0',
33
+ }),
34
+ );
35
+
36
+ interface Contact extends Schema.Schema.Type<typeof Contact> {}
37
+
38
+ const TEST_ORG: Omit<Organization, 'id'> = { name: 'Test' };
39
+
40
+ describe('EchoObject class DSL', () => {
41
+ test('can get object schema', async () => {
42
+ const obj = live(Organization, TEST_ORG);
43
+ expect(getSchema(obj)).to.deep.eq(Organization);
44
+ });
45
+
46
+ describe('class options', () => {
47
+ test('can assign undefined to partial fields', async () => {
48
+ const person = live(Contact, { name: 'John' });
49
+ person.name = undefined;
50
+ person.recordField = 'hello';
51
+ expect(person.name).to.be.undefined;
52
+ expect(person.recordField).to.eq('hello');
53
+ });
54
+ });
55
+
56
+ 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
+ );
66
+
67
+ {
68
+ const object = live(schema, {});
69
+ (object.meta ??= {}).test = 100;
70
+ expect(object.meta.test).to.eq(100);
71
+ }
72
+
73
+ {
74
+ const object = live(schema, {});
75
+ object.meta = { test: { value: 300 } };
76
+ expect(object.meta.test.value).to.eq(300);
77
+ }
78
+
79
+ {
80
+ type Test1 = Schema.Schema.Type<typeof schema>;
81
+
82
+ const object: Test1 = {};
83
+ (object.meta ??= {}).test = 100;
84
+ expect(object.meta.test).to.eq(100);
85
+ }
86
+
87
+ {
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);
98
+ }
99
+ });
100
+ });
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './query';