@dxos/echo 0.8.4-main.5ea62a8 → 0.8.4-main.66e292d

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 (328) hide show
  1. package/dist/lib/browser/chunk-7GH6RXJ3.mjs +3683 -0
  2. package/dist/lib/browser/chunk-7GH6RXJ3.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-E4UTVJNF.mjs +1111 -0
  4. package/dist/lib/browser/chunk-E4UTVJNF.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +24 -1
  6. package/dist/lib/browser/internal/index.mjs +336 -0
  7. package/dist/lib/browser/internal/index.mjs.map +7 -0
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/testing/index.mjs +289 -31
  10. package/dist/lib/browser/testing/index.mjs.map +4 -4
  11. package/dist/lib/node-esm/chunk-JE5RXM2I.mjs +1111 -0
  12. package/dist/lib/node-esm/chunk-JE5RXM2I.mjs.map +7 -0
  13. package/dist/lib/node-esm/chunk-M4B6BMD2.mjs +3683 -0
  14. package/dist/lib/node-esm/chunk-M4B6BMD2.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +24 -1
  16. package/dist/lib/node-esm/internal/index.mjs +336 -0
  17. package/dist/lib/node-esm/internal/index.mjs.map +7 -0
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/testing/index.mjs +289 -31
  20. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  21. package/dist/types/src/Annotation.d.ts +2 -0
  22. package/dist/types/src/Annotation.d.ts.map +1 -0
  23. package/dist/types/src/Database.d.ts +137 -0
  24. package/dist/types/src/Database.d.ts.map +1 -0
  25. package/dist/types/src/Entity.d.ts +36 -0
  26. package/dist/types/src/Entity.d.ts.map +1 -0
  27. package/dist/types/src/Format.d.ts +4 -0
  28. package/dist/types/src/Format.d.ts.map +1 -0
  29. package/dist/types/src/JsonSchema.d.ts +9 -0
  30. package/dist/types/src/JsonSchema.d.ts.map +1 -0
  31. package/dist/types/src/Key.d.ts +1 -0
  32. package/dist/types/src/Key.d.ts.map +1 -1
  33. package/dist/types/src/Obj.d.ts +121 -50
  34. package/dist/types/src/Obj.d.ts.map +1 -1
  35. package/dist/types/src/Ref.d.ts +10 -10
  36. package/dist/types/src/Ref.d.ts.map +1 -1
  37. package/dist/types/src/Relation.d.ts +18 -14
  38. package/dist/types/src/Relation.d.ts.map +1 -1
  39. package/dist/types/src/Tag.d.ts +17 -0
  40. package/dist/types/src/Tag.d.ts.map +1 -0
  41. package/dist/types/src/Type.d.ts +39 -50
  42. package/dist/types/src/Type.d.ts.map +1 -1
  43. package/dist/types/src/errors.d.ts +68 -0
  44. package/dist/types/src/errors.d.ts.map +1 -0
  45. package/dist/types/src/index.d.ts +9 -3
  46. package/dist/types/src/index.d.ts.map +1 -1
  47. package/dist/types/src/internal/annotations/annotations.d.ts +174 -0
  48. package/dist/types/src/internal/annotations/annotations.d.ts.map +1 -0
  49. package/dist/types/src/internal/annotations/annotations.test.d.ts +2 -0
  50. package/dist/types/src/internal/annotations/annotations.test.d.ts.map +1 -0
  51. package/dist/types/src/internal/annotations/index.d.ts +3 -0
  52. package/dist/types/src/internal/annotations/index.d.ts.map +1 -0
  53. package/dist/types/src/internal/annotations/util.d.ts +26 -0
  54. package/dist/types/src/internal/annotations/util.d.ts.map +1 -0
  55. package/dist/types/src/internal/entities/entity.d.ts +10 -0
  56. package/dist/types/src/internal/entities/entity.d.ts.map +1 -0
  57. package/dist/types/src/internal/entities/expando.d.ts +16 -0
  58. package/dist/types/src/internal/entities/expando.d.ts.map +1 -0
  59. package/dist/types/src/internal/entities/index.d.ts +6 -0
  60. package/dist/types/src/internal/entities/index.d.ts.map +1 -0
  61. package/dist/types/src/internal/entities/model.d.ts +70 -0
  62. package/dist/types/src/internal/entities/model.d.ts.map +1 -0
  63. package/dist/types/src/internal/entities/object.d.ts +11 -0
  64. package/dist/types/src/internal/entities/object.d.ts.map +1 -0
  65. package/dist/types/src/internal/entities/relation.d.ts +55 -0
  66. package/dist/types/src/internal/entities/relation.d.ts.map +1 -0
  67. package/dist/types/src/internal/entities/util.d.ts +2 -0
  68. package/dist/types/src/internal/entities/util.d.ts.map +1 -0
  69. package/dist/types/src/internal/formats/date.d.ts +63 -0
  70. package/dist/types/src/internal/formats/date.d.ts.map +1 -0
  71. package/dist/types/src/internal/formats/date.test.d.ts +2 -0
  72. package/dist/types/src/internal/formats/date.test.d.ts.map +1 -0
  73. package/dist/types/src/internal/formats/format.d.ts +32 -0
  74. package/dist/types/src/internal/formats/format.d.ts.map +1 -0
  75. package/dist/types/src/internal/formats/format.test.d.ts +2 -0
  76. package/dist/types/src/internal/formats/format.test.d.ts.map +1 -0
  77. package/dist/types/src/internal/formats/index.d.ts +8 -0
  78. package/dist/types/src/internal/formats/index.d.ts.map +1 -0
  79. package/dist/types/src/internal/formats/number.d.ts +31 -0
  80. package/dist/types/src/internal/formats/number.d.ts.map +1 -0
  81. package/dist/types/src/internal/formats/object.d.ts +35 -0
  82. package/dist/types/src/internal/formats/object.d.ts.map +1 -0
  83. package/dist/types/src/internal/formats/select.d.ts +11 -0
  84. package/dist/types/src/internal/formats/select.d.ts.map +1 -0
  85. package/dist/types/src/internal/formats/string.d.ts +38 -0
  86. package/dist/types/src/internal/formats/string.d.ts.map +1 -0
  87. package/dist/types/src/internal/formats/types.d.ts +68 -0
  88. package/dist/types/src/internal/formats/types.d.ts.map +1 -0
  89. package/dist/types/src/internal/index.d.ts +11 -0
  90. package/dist/types/src/internal/index.d.ts.map +1 -0
  91. package/dist/types/src/internal/json-schema/annotations.d.ts +19 -0
  92. package/dist/types/src/internal/json-schema/annotations.d.ts.map +1 -0
  93. package/dist/types/src/internal/json-schema/effect-schema.test.d.ts +2 -0
  94. package/dist/types/src/internal/json-schema/effect-schema.test.d.ts.map +1 -0
  95. package/dist/types/src/internal/json-schema/index.d.ts +5 -0
  96. package/dist/types/src/internal/json-schema/index.d.ts.map +1 -0
  97. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts +7 -0
  98. package/dist/types/src/internal/json-schema/json-schema-normalize.d.ts.map +1 -0
  99. package/dist/types/src/internal/json-schema/json-schema-type.d.ts +250 -0
  100. package/dist/types/src/internal/json-schema/json-schema-type.d.ts.map +1 -0
  101. package/dist/types/src/internal/json-schema/json-schema.d.ts +29 -0
  102. package/dist/types/src/internal/json-schema/json-schema.d.ts.map +1 -0
  103. package/dist/types/src/internal/json-schema/json-schema.test.d.ts +2 -0
  104. package/dist/types/src/internal/json-schema/json-schema.test.d.ts.map +1 -0
  105. package/dist/types/src/internal/object/common.d.ts +18 -0
  106. package/dist/types/src/internal/object/common.d.ts.map +1 -0
  107. package/dist/types/src/internal/object/create-object.d.ts +39 -0
  108. package/dist/types/src/internal/object/create-object.d.ts.map +1 -0
  109. package/dist/types/src/internal/object/create-object.test.d.ts +2 -0
  110. package/dist/types/src/internal/object/create-object.test.d.ts.map +1 -0
  111. package/dist/types/src/internal/object/deleted.d.ts +6 -0
  112. package/dist/types/src/internal/object/deleted.d.ts.map +1 -0
  113. package/dist/types/src/internal/object/ids.d.ts +6 -0
  114. package/dist/types/src/internal/object/ids.d.ts.map +1 -0
  115. package/dist/types/src/internal/object/index.d.ts +8 -0
  116. package/dist/types/src/internal/object/index.d.ts.map +1 -0
  117. package/dist/types/src/internal/object/inspect.d.ts +2 -0
  118. package/dist/types/src/internal/object/inspect.d.ts.map +1 -0
  119. package/dist/types/src/internal/object/json-serializer.d.ts +31 -0
  120. package/dist/types/src/internal/object/json-serializer.d.ts.map +1 -0
  121. package/dist/types/src/internal/object/json-serializer.test.d.ts +2 -0
  122. package/dist/types/src/internal/object/json-serializer.test.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/proxy/handler.test.d.ts +2 -0
  132. package/dist/types/src/internal/proxy/handler.test.d.ts.map +1 -0
  133. package/dist/types/src/internal/proxy/index.d.ts +3 -0
  134. package/dist/types/src/internal/proxy/index.d.ts.map +1 -0
  135. package/dist/types/src/internal/proxy/make-object.d.ts +16 -0
  136. package/dist/types/src/internal/proxy/make-object.d.ts.map +1 -0
  137. package/dist/types/src/internal/proxy/schema.test.d.ts +2 -0
  138. package/dist/types/src/internal/proxy/schema.test.d.ts.map +1 -0
  139. package/dist/types/src/internal/proxy/typed-handler.d.ts +44 -0
  140. package/dist/types/src/internal/proxy/typed-handler.d.ts.map +1 -0
  141. package/dist/types/src/internal/proxy/typed-handler.test.d.ts +2 -0
  142. package/dist/types/src/internal/proxy/typed-handler.test.d.ts.map +1 -0
  143. package/dist/types/src/internal/proxy/typed-object.test.d.ts +2 -0
  144. package/dist/types/src/internal/proxy/typed-object.test.d.ts.map +1 -0
  145. package/dist/types/src/internal/ref/index.d.ts +3 -0
  146. package/dist/types/src/internal/ref/index.d.ts.map +1 -0
  147. package/dist/types/src/internal/ref/ref-array.d.ts +21 -0
  148. package/dist/types/src/internal/ref/ref-array.d.ts.map +1 -0
  149. package/dist/types/src/internal/ref/ref.d.ts +209 -0
  150. package/dist/types/src/internal/ref/ref.d.ts.map +1 -0
  151. package/dist/types/src/internal/ref/ref.test.d.ts +2 -0
  152. package/dist/types/src/internal/ref/ref.test.d.ts.map +1 -0
  153. package/dist/types/src/internal/schema/compose.d.ts +6 -0
  154. package/dist/types/src/internal/schema/compose.d.ts.map +1 -0
  155. package/dist/types/src/internal/schema/compose.test.d.ts +2 -0
  156. package/dist/types/src/internal/schema/compose.test.d.ts.map +1 -0
  157. package/dist/types/src/internal/schema/echo-schema.d.ts +168 -0
  158. package/dist/types/src/internal/schema/echo-schema.d.ts.map +1 -0
  159. package/dist/types/src/internal/schema/index.d.ts +6 -0
  160. package/dist/types/src/internal/schema/index.d.ts.map +1 -0
  161. package/dist/types/src/internal/schema/manipulation.d.ts +10 -0
  162. package/dist/types/src/internal/schema/manipulation.d.ts.map +1 -0
  163. package/dist/types/src/internal/schema/persistent-schema.d.ts +18 -0
  164. package/dist/types/src/internal/schema/persistent-schema.d.ts.map +1 -0
  165. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts +18 -0
  166. package/dist/types/src/internal/schema/runtime-schema-registry.d.ts.map +1 -0
  167. package/dist/types/src/internal/schema/snapshot.d.ts +6 -0
  168. package/dist/types/src/internal/schema/snapshot.d.ts.map +1 -0
  169. package/dist/types/src/internal/types/base.d.ts +37 -0
  170. package/dist/types/src/internal/types/base.d.ts.map +1 -0
  171. package/dist/types/src/internal/types/entity.d.ts +12 -0
  172. package/dist/types/src/internal/types/entity.d.ts.map +1 -0
  173. package/dist/types/src/internal/types/index.d.ts +6 -0
  174. package/dist/types/src/internal/types/index.d.ts.map +1 -0
  175. package/dist/types/src/internal/types/meta.d.ts +40 -0
  176. package/dist/types/src/internal/types/meta.d.ts.map +1 -0
  177. package/dist/types/src/internal/types/typename.d.ts +13 -0
  178. package/dist/types/src/internal/types/typename.d.ts.map +1 -0
  179. package/dist/types/src/internal/types/version.d.ts +15 -0
  180. package/dist/types/src/internal/types/version.d.ts.map +1 -0
  181. package/dist/types/src/query/filter.d.ts +167 -0
  182. package/dist/types/src/query/filter.d.ts.map +1 -0
  183. package/dist/types/src/query/index.d.ts +4 -1
  184. package/dist/types/src/query/index.d.ts.map +1 -1
  185. package/dist/types/src/query/order.d.ts +12 -0
  186. package/dist/types/src/query/order.d.ts.map +1 -0
  187. package/dist/types/src/query/query.d.ts +112 -0
  188. package/dist/types/src/query/query.d.ts.map +1 -0
  189. package/dist/types/src/query/query.test.d.ts +2 -0
  190. package/dist/types/src/query/query.test.d.ts.map +1 -0
  191. package/dist/types/src/query/testing.d.ts +51 -0
  192. package/dist/types/src/query/testing.d.ts.map +1 -0
  193. package/dist/types/src/query/types.d.ts +17 -0
  194. package/dist/types/src/query/types.d.ts.map +1 -0
  195. package/dist/types/src/query/util.d.ts +8 -0
  196. package/dist/types/src/query/util.d.ts.map +1 -0
  197. package/dist/types/src/{test → testing}/api.test.d.ts.map +1 -1
  198. package/dist/types/src/testing/index.d.ts +3 -1
  199. package/dist/types/src/testing/index.d.ts.map +1 -1
  200. package/dist/types/src/testing/test-data.d.ts +18 -0
  201. package/dist/types/src/testing/test-data.d.ts.map +1 -0
  202. package/dist/types/src/testing/test-schema.d.ts +337 -0
  203. package/dist/types/src/testing/test-schema.d.ts.map +1 -0
  204. package/dist/types/src/testing/util.d.ts +16 -0
  205. package/dist/types/src/testing/util.d.ts.map +1 -0
  206. package/dist/types/tsconfig.tsbuildinfo +1 -1
  207. package/package.json +49 -29
  208. package/src/Annotation.ts +17 -0
  209. package/src/Database.ts +189 -0
  210. package/src/Entity.ts +51 -0
  211. package/src/Format.ts +11 -0
  212. package/src/JsonSchema.ts +16 -0
  213. package/src/Key.ts +3 -0
  214. package/src/Obj.ts +353 -107
  215. package/src/Ref.ts +9 -10
  216. package/src/Relation.ts +68 -43
  217. package/src/Tag.ts +40 -0
  218. package/src/Type.ts +97 -85
  219. package/src/errors.ts +18 -0
  220. package/src/index.ts +13 -4
  221. package/src/internal/README.md +83 -0
  222. package/src/internal/annotations/annotations.test.ts +96 -0
  223. package/src/internal/annotations/annotations.ts +463 -0
  224. package/src/internal/annotations/index.ts +6 -0
  225. package/src/internal/annotations/util.ts +70 -0
  226. package/src/internal/entities/entity.ts +109 -0
  227. package/src/internal/entities/expando.ts +23 -0
  228. package/src/internal/entities/index.ts +9 -0
  229. package/src/internal/entities/model.ts +129 -0
  230. package/src/internal/entities/object.ts +45 -0
  231. package/src/internal/entities/relation.ts +155 -0
  232. package/src/internal/entities/util.ts +33 -0
  233. package/src/internal/formats/date.test.ts +56 -0
  234. package/src/internal/formats/date.ts +217 -0
  235. package/src/internal/formats/format.test.ts +77 -0
  236. package/src/internal/formats/format.ts +55 -0
  237. package/src/internal/formats/index.ts +12 -0
  238. package/src/internal/formats/number.ts +89 -0
  239. package/src/internal/formats/object.ts +80 -0
  240. package/src/internal/formats/select.ts +16 -0
  241. package/src/internal/formats/string.ts +76 -0
  242. package/src/internal/formats/types.ts +180 -0
  243. package/src/internal/index.ts +38 -0
  244. package/src/internal/json-schema/annotations.ts +50 -0
  245. package/src/internal/json-schema/effect-schema.test.ts +143 -0
  246. package/src/internal/json-schema/index.ts +8 -0
  247. package/src/internal/json-schema/json-schema-normalize.ts +109 -0
  248. package/src/internal/json-schema/json-schema-type.ts +404 -0
  249. package/src/internal/json-schema/json-schema.test.ts +859 -0
  250. package/src/internal/json-schema/json-schema.ts +528 -0
  251. package/src/internal/object/common.ts +75 -0
  252. package/src/internal/object/create-object.test.ts +116 -0
  253. package/src/internal/object/create-object.ts +95 -0
  254. package/src/internal/object/deleted.ts +19 -0
  255. package/src/internal/object/ids.ts +12 -0
  256. package/src/internal/object/index.ts +11 -0
  257. package/src/internal/object/inspect.ts +46 -0
  258. package/src/internal/object/json-serializer.test.ts +94 -0
  259. package/src/internal/object/json-serializer.ts +230 -0
  260. package/src/internal/object/schema-validator.test.ts +186 -0
  261. package/src/internal/object/schema-validator.ts +242 -0
  262. package/src/internal/object/typed-object.test.ts +34 -0
  263. package/src/internal/object/typed-object.ts +94 -0
  264. package/src/internal/proxy/handler.test.ts +173 -0
  265. package/src/internal/proxy/index.ts +6 -0
  266. package/src/internal/proxy/make-object.ts +113 -0
  267. package/src/internal/proxy/schema.test.ts +137 -0
  268. package/src/internal/proxy/typed-handler.test.ts +102 -0
  269. package/src/internal/proxy/typed-handler.ts +233 -0
  270. package/src/internal/proxy/typed-object.test.ts +105 -0
  271. package/src/internal/ref/index.ts +6 -0
  272. package/src/internal/ref/ref-array.ts +39 -0
  273. package/src/internal/ref/ref.test.ts +101 -0
  274. package/src/internal/ref/ref.ts +525 -0
  275. package/src/internal/schema/compose.test.ts +42 -0
  276. package/src/internal/schema/compose.ts +37 -0
  277. package/src/internal/schema/echo-schema.ts +385 -0
  278. package/src/internal/schema/index.ts +9 -0
  279. package/src/internal/schema/manipulation.ts +92 -0
  280. package/src/internal/schema/persistent-schema.ts +28 -0
  281. package/src/internal/schema/runtime-schema-registry.ts +78 -0
  282. package/src/internal/schema/snapshot.ts +25 -0
  283. package/src/internal/types/base.ts +58 -0
  284. package/src/internal/types/entity.ts +23 -0
  285. package/src/internal/types/index.ts +9 -0
  286. package/src/internal/types/meta.ts +76 -0
  287. package/src/internal/types/typename.ts +45 -0
  288. package/src/internal/types/version.ts +20 -0
  289. package/src/query/filter.ts +455 -0
  290. package/src/query/index.ts +5 -1
  291. package/src/query/order.ts +34 -0
  292. package/src/query/query.test.ts +334 -0
  293. package/src/query/query.ts +303 -0
  294. package/src/query/testing.ts +64 -0
  295. package/src/query/types.ts +23 -0
  296. package/src/query/util.ts +25 -0
  297. package/src/testing/api.test.ts +100 -0
  298. package/src/testing/index.ts +3 -1
  299. package/src/testing/test-data.ts +130 -0
  300. package/src/testing/test-schema.ts +213 -0
  301. package/src/testing/util.ts +78 -0
  302. package/dist/lib/browser/chunk-2KNTYMIW.mjs +0 -697
  303. package/dist/lib/browser/chunk-2KNTYMIW.mjs.map +0 -7
  304. package/dist/lib/node-esm/chunk-EXNNC62J.mjs +0 -697
  305. package/dist/lib/node-esm/chunk-EXNNC62J.mjs.map +0 -7
  306. package/dist/types/src/experimental/database.d.ts +0 -8
  307. package/dist/types/src/experimental/database.d.ts.map +0 -1
  308. package/dist/types/src/experimental/index.d.ts +0 -1
  309. package/dist/types/src/experimental/index.d.ts.map +0 -1
  310. package/dist/types/src/experimental/queue.d.ts +0 -8
  311. package/dist/types/src/experimental/queue.d.ts.map +0 -1
  312. package/dist/types/src/experimental/space.d.ts +0 -8
  313. package/dist/types/src/experimental/space.d.ts.map +0 -1
  314. package/dist/types/src/query/dsl.d.ts +0 -218
  315. package/dist/types/src/query/dsl.d.ts.map +0 -1
  316. package/dist/types/src/query/dsl.test.d.ts +0 -2
  317. package/dist/types/src/query/dsl.test.d.ts.map +0 -1
  318. package/dist/types/src/testing/types.d.ts +0 -113
  319. package/dist/types/src/testing/types.d.ts.map +0 -1
  320. package/src/experimental/database.ts +0 -11
  321. package/src/experimental/index.ts +0 -7
  322. package/src/experimental/queue.ts +0 -11
  323. package/src/experimental/space.ts +0 -11
  324. package/src/query/dsl.test.ts +0 -324
  325. package/src/query/dsl.ts +0 -646
  326. package/src/test/api.test.ts +0 -173
  327. package/src/testing/types.ts +0 -91
  328. /package/dist/types/src/{test → testing}/api.test.d.ts +0 -0
@@ -0,0 +1,528 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Array from 'effect/Array';
6
+ import * as Function from 'effect/Function';
7
+ import * as JSONSchema from 'effect/JSONSchema';
8
+ import * as Option from 'effect/Option';
9
+ import * as Schema from 'effect/Schema';
10
+ import * as SchemaAST from 'effect/SchemaAST';
11
+ import type * as Types from 'effect/Types';
12
+
13
+ import { raise } from '@dxos/debug';
14
+ import { mapAst } from '@dxos/effect';
15
+ import { assertArgument, invariant } from '@dxos/invariant';
16
+ import { DXN, ObjectId } from '@dxos/keys';
17
+ import { log } from '@dxos/log';
18
+ import { clearUndefined, orderKeys, removeProperties } from '@dxos/util';
19
+
20
+ import {
21
+ type TypeAnnotation,
22
+ TypeAnnotationId,
23
+ TypeIdentifierAnnotationId,
24
+ makeTypeJsonSchemaAnnotation,
25
+ } from '../annotations';
26
+ import { Expando } from '../entities';
27
+ import { type JsonSchemaReferenceInfo, Ref, createEchoReferenceSchema } from '../ref';
28
+ import { EntityKind, EntityKindSchema } from '../types';
29
+
30
+ import { CustomAnnotations, DecodedAnnotations, EchoAnnotations } from './annotations';
31
+ import {
32
+ ECHO_ANNOTATIONS_NS_DEPRECATED_KEY,
33
+ ECHO_ANNOTATIONS_NS_KEY,
34
+ type JsonSchemaEchoAnnotations,
35
+ type JsonSchemaType,
36
+ getNormalizedEchoAnnotations,
37
+ } from './json-schema-type';
38
+
39
+ // TODO(burdon): Are these values stored (can they be changed?)
40
+ export enum PropType {
41
+ NONE = 0,
42
+ STRING = 1, // TODO(burdon): vs TEXT?
43
+ NUMBER = 2,
44
+ BOOLEAN = 3,
45
+ DATE = 4,
46
+ REF = 5,
47
+ RECORD = 6,
48
+ ENUM = 7,
49
+ }
50
+
51
+ // TODO(burdon): Reconcile with @dxos/schema.
52
+ export const toPropType = (type?: PropType): string => {
53
+ switch (type) {
54
+ case PropType.STRING:
55
+ return 'string';
56
+ case PropType.NUMBER:
57
+ return 'number';
58
+ case PropType.BOOLEAN:
59
+ return 'boolean';
60
+ case PropType.DATE:
61
+ return 'date';
62
+ case PropType.REF:
63
+ return 'ref';
64
+ case PropType.RECORD:
65
+ return 'object';
66
+ default:
67
+ throw new Error(`Invalid type: ${type}`);
68
+ }
69
+ };
70
+
71
+ const JSON_SCHEMA_URL = 'http://json-schema.org/draft-07/schema#';
72
+
73
+ export type JsonSchemaOptions = {
74
+ strict?: boolean;
75
+ };
76
+
77
+ /**
78
+ * Convert effect schema to JSON Schema.
79
+ * NOTE: This handles custom annotations.
80
+ * @param schema
81
+ */
82
+ // TODO(burdon): Reconcile with possibly extending @effect/Schema/JSONSchema
83
+ // We add additional propertyOrder (but the object properties ARE ordered); and type "string" for literals.
84
+ export const toJsonSchema = (schema: Schema.Schema.All, options: JsonSchemaOptions = {}): JsonSchemaType => {
85
+ assertArgument(Schema.isSchema(schema), 'schema');
86
+ let jsonSchema = _toJsonSchemaAST(schema.ast);
87
+ if (options.strict) {
88
+ // TOOD(burdon): Workaround to ensure JSON schema is valid (for agv parsing).
89
+ jsonSchema = removeProperties(jsonSchema, (key, value) => {
90
+ if (key === '$id' && value === '/schemas/any') {
91
+ return true;
92
+ }
93
+ if (key === '$ref' && value === '#/$defs/dependency') {
94
+ return true;
95
+ }
96
+ if (key === '$ref' && value === '#/$defs/jsonSchema') {
97
+ return true;
98
+ }
99
+
100
+ return false;
101
+ });
102
+ }
103
+
104
+ return jsonSchema;
105
+ };
106
+
107
+ const _toJsonSchemaAST = (ast: SchemaAST.AST): JsonSchemaType => {
108
+ const withRefinements = withEchoRefinements(ast, '#');
109
+ const jsonSchema = JSONSchema.fromAST(withRefinements, {
110
+ definitions: {},
111
+ }) as JsonSchemaType;
112
+
113
+ return normalizeJsonSchema(jsonSchema);
114
+ };
115
+
116
+ const withEchoRefinements = (
117
+ ast: SchemaAST.AST,
118
+ path: string | undefined,
119
+ suspendCache = new Map<SchemaAST.AST, string>(),
120
+ ): SchemaAST.AST => {
121
+ if (path) {
122
+ suspendCache.set(ast, path);
123
+ }
124
+
125
+ let recursiveResult: SchemaAST.AST;
126
+ if (SchemaAST.isSuspend(ast)) {
127
+ // Precompute JSON schema for suspended AST since effect serializer does not support it.
128
+ const suspendedAst = ast.f();
129
+ const cachedPath = suspendCache.get(suspendedAst);
130
+ if (cachedPath) {
131
+ recursiveResult = new SchemaAST.Suspend(() => withEchoRefinements(suspendedAst, path, suspendCache), {
132
+ [SchemaAST.JSONSchemaAnnotationId]: {
133
+ $ref: cachedPath,
134
+ },
135
+ });
136
+ } else {
137
+ const jsonSchema = _toJsonSchemaAST(suspendedAst);
138
+ recursiveResult = new SchemaAST.Suspend(() => withEchoRefinements(suspendedAst, path, suspendCache), {
139
+ [SchemaAST.JSONSchemaAnnotationId]: jsonSchema,
140
+ });
141
+ }
142
+ } else if (SchemaAST.isTypeLiteral(ast)) {
143
+ // Add property order annotations
144
+ recursiveResult = mapAst(ast, (ast, key) =>
145
+ withEchoRefinements(ast, path && typeof key === 'string' ? `${path}/${key}` : undefined, suspendCache),
146
+ );
147
+ recursiveResult = addJsonSchemaFields(recursiveResult, {
148
+ propertyOrder: [...ast.propertySignatures.map((p) => p.name)] as string[],
149
+ });
150
+ } else if (SchemaAST.isUndefinedKeyword(ast)) {
151
+ // Ignore undefined keyword that appears in the optional fields.
152
+ return ast;
153
+ } else {
154
+ recursiveResult = mapAst(ast, (ast, key) =>
155
+ withEchoRefinements(
156
+ ast,
157
+ path && (typeof key === 'string' || typeof key === 'number') ? `${path}/${key}` : undefined,
158
+ suspendCache,
159
+ ),
160
+ );
161
+ }
162
+
163
+ const annotationFields = annotations_toJsonSchemaFields(ast.annotations);
164
+ if (Object.keys(annotationFields).length === 0) {
165
+ return recursiveResult;
166
+ } else {
167
+ return addJsonSchemaFields(recursiveResult, annotationFields);
168
+ }
169
+ };
170
+
171
+ /**
172
+ * Convert JSON schema to effect schema.
173
+ * @param root
174
+ * @param definitions
175
+ */
176
+ export const toEffectSchema = (root: JsonSchemaType, _defs?: JsonSchemaType['$defs']): Schema.Schema.AnyNoContext => {
177
+ const defs = root.$defs ? { ..._defs, ...root.$defs } : (_defs ?? {});
178
+ if ('type' in root && root.type === 'object') {
179
+ return objectToEffectSchema(root, defs);
180
+ }
181
+
182
+ let result: Schema.Schema.AnyNoContext = Schema.Unknown;
183
+ if ('$ref' in root) {
184
+ switch (root.$ref) {
185
+ case '/schemas/echo/ref': {
186
+ result = refToEffectSchema(root);
187
+ break;
188
+ }
189
+ }
190
+ } else if ('$id' in root) {
191
+ switch (root.$id as string) {
192
+ case '/schemas/any': {
193
+ result = anyToEffectSchema(root as JSONSchema.JsonSchema7Any);
194
+ break;
195
+ }
196
+ case '/schemas/unknown': {
197
+ result = Schema.Unknown;
198
+ break;
199
+ }
200
+ case '/schemas/{}':
201
+ case '/schemas/object': {
202
+ result = Schema.Object;
203
+ break;
204
+ }
205
+ // Custom ECHO object reference.
206
+ case '/schemas/echo/ref': {
207
+ result = refToEffectSchema(root);
208
+ break;
209
+ }
210
+ }
211
+ } else if ('enum' in root) {
212
+ result = Schema.Union(...root.enum!.map((e) => Schema.Literal(e)));
213
+ } else if ('oneOf' in root) {
214
+ result = Schema.Union(...root.oneOf!.map((v) => toEffectSchema(v, defs)));
215
+ } else if ('anyOf' in root) {
216
+ result = Schema.Union(...root.anyOf!.map((v) => toEffectSchema(v, defs)));
217
+ } else if ('allOf' in root) {
218
+ if (root.allOf!.length === 1) {
219
+ result = toEffectSchema(root.allOf![0], defs);
220
+ } else {
221
+ log.warn('allOf with multiple schemas is not supported');
222
+ result = Schema.Unknown;
223
+ }
224
+ } else if ('type' in root) {
225
+ switch (root.type) {
226
+ case 'string': {
227
+ result = Schema.String;
228
+ if (root.pattern) {
229
+ result = result.pipe(Schema.pattern(new RegExp(root.pattern)));
230
+ }
231
+ break;
232
+ }
233
+ case 'number': {
234
+ result = Schema.Number;
235
+ break;
236
+ }
237
+ case 'integer': {
238
+ result = Schema.Number.pipe(Schema.int());
239
+ break;
240
+ }
241
+ case 'boolean': {
242
+ result = Schema.Boolean;
243
+ break;
244
+ }
245
+ case 'array': {
246
+ if (Array.isArray(root.items)) {
247
+ const [required, optional] = Function.pipe(
248
+ root.items,
249
+ Array.map((v) => toEffectSchema(v as JsonSchemaType, defs)),
250
+ Array.splitAt(root.minItems ?? root.items.length),
251
+ );
252
+ result = Schema.Tuple(...required, ...optional.map(Schema.optionalElement));
253
+ } else {
254
+ invariant(root.items);
255
+ const items = root.items;
256
+ result = Array.isArray(items)
257
+ ? Schema.Tuple(...items.map((v) => toEffectSchema(v as JsonSchemaType, defs)))
258
+ : Schema.Array(toEffectSchema(items as JsonSchemaType, defs));
259
+ }
260
+ break;
261
+ }
262
+ case 'null': {
263
+ result = Schema.Null;
264
+ break;
265
+ }
266
+ }
267
+ } else if ('$ref' in root) {
268
+ const refSegments = root.$ref!.split('/');
269
+ const jsonSchema = defs[refSegments[refSegments.length - 1]];
270
+ invariant(jsonSchema, `missing definition for ${root.$ref}`);
271
+ result = toEffectSchema(jsonSchema, defs).pipe(
272
+ Schema.annotations({ identifier: refSegments[refSegments.length - 1] }),
273
+ );
274
+ }
275
+
276
+ const annotations = jsonSchemaFieldsToAnnotations(root);
277
+
278
+ // log.info('toEffectSchema', { root, annotations });
279
+ result = result.annotations(annotations);
280
+
281
+ return result;
282
+ };
283
+
284
+ const objectToEffectSchema = (root: JsonSchemaType, defs: JsonSchemaType['$defs']): Schema.Schema.AnyNoContext => {
285
+ invariant('type' in root && root.type === 'object', `not an object: ${root}`);
286
+
287
+ const echoRefinement: JsonSchemaEchoAnnotations = (root as any)[ECHO_ANNOTATIONS_NS_DEPRECATED_KEY];
288
+ const isEchoObject =
289
+ echoRefinement != null || ('$id' in root && typeof root.$id === 'string' && root.$id.startsWith('dxn:'));
290
+
291
+ let fields: Schema.Struct.Fields = {};
292
+ const propertyList = Object.entries(root.properties ?? {});
293
+ let immutableIdField: Schema.Schema.AnyNoContext | undefined;
294
+ for (const [key, value] of propertyList) {
295
+ if (isEchoObject && key === 'id') {
296
+ immutableIdField = toEffectSchema(value, defs);
297
+ } else {
298
+ // TODO(burdon): Mutable cast.
299
+ (fields as any)[key] = root.required?.includes(key)
300
+ ? toEffectSchema(value, defs)
301
+ : Schema.optional(toEffectSchema(value, defs));
302
+ }
303
+ }
304
+
305
+ if (root.propertyOrder) {
306
+ fields = orderKeys(fields, root.propertyOrder as any);
307
+ }
308
+
309
+ let schema: Schema.Schema<any, any, unknown>;
310
+ if (root.patternProperties) {
311
+ invariant(propertyList.length === 0, 'pattern properties mixed with regular properties are not supported');
312
+ invariant(
313
+ Object.keys(root.patternProperties).length === 1 && Object.keys(root.patternProperties)[0] === '',
314
+ 'only one pattern property is supported',
315
+ );
316
+
317
+ schema = Schema.Record({ key: Schema.String, value: toEffectSchema(root.patternProperties[''], defs) });
318
+ } else if (typeof root.additionalProperties !== 'object') {
319
+ schema = Schema.Struct(fields);
320
+ } else {
321
+ const indexValue = toEffectSchema(root.additionalProperties, defs);
322
+ if (propertyList.length > 0) {
323
+ schema = Schema.Struct(fields, { key: Schema.String, value: indexValue });
324
+ } else {
325
+ schema = Schema.Record({ key: Schema.String, value: indexValue });
326
+ }
327
+ }
328
+
329
+ if (immutableIdField) {
330
+ schema = Schema.extend(Schema.mutable(schema), Schema.Struct({ id: immutableIdField }));
331
+ }
332
+
333
+ const annotations = jsonSchemaFieldsToAnnotations(root);
334
+ return schema.annotations(annotations) as any;
335
+ };
336
+
337
+ const anyToEffectSchema = (root: JSONSchema.JsonSchema7Any): Schema.Schema.AnyNoContext => {
338
+ const echoRefinement: JsonSchemaEchoAnnotations = (root as any)[ECHO_ANNOTATIONS_NS_DEPRECATED_KEY];
339
+ // TODO(dmaretskyi): Is this branch still taken?
340
+ if ((echoRefinement as any)?.reference != null) {
341
+ const echoId = root.$id.startsWith('dxn:echo:') ? root.$id : undefined;
342
+ return createEchoReferenceSchema(
343
+ echoId,
344
+ (echoRefinement as any).reference.typename,
345
+ (echoRefinement as any).reference.version,
346
+ );
347
+ }
348
+
349
+ return Schema.Any;
350
+ };
351
+
352
+ // TODO(dmaretskyi): Types.
353
+ const refToEffectSchema = (root: any): Schema.Schema.AnyNoContext => {
354
+ if (!('reference' in root)) {
355
+ return Ref(Expando);
356
+ }
357
+
358
+ const reference: JsonSchemaReferenceInfo = root.reference;
359
+ if (typeof reference !== 'object') {
360
+ throw new Error('Invalid reference field in ref schema');
361
+ }
362
+
363
+ const targetSchemaDXN = DXN.parse(reference.schema.$ref);
364
+ invariant(targetSchemaDXN.kind === DXN.kind.TYPE);
365
+
366
+ return createEchoReferenceSchema(
367
+ targetSchemaDXN.toString(),
368
+ targetSchemaDXN.kind === DXN.kind.TYPE ? targetSchemaDXN.parts[0] : undefined,
369
+ reference.schemaVersion,
370
+ );
371
+ };
372
+
373
+ //
374
+ // Annotations
375
+ //
376
+
377
+ const annotations_toJsonSchemaFields = (annotations: SchemaAST.Annotations): Record<symbol, any> => {
378
+ const schemaFields: Record<string, any> = {};
379
+
380
+ const echoAnnotations: JsonSchemaEchoAnnotations = {};
381
+ for (const [key, annotationId] of Object.entries(EchoAnnotations)) {
382
+ if (annotations[annotationId] != null) {
383
+ echoAnnotations[key as keyof JsonSchemaEchoAnnotations] = annotations[annotationId] as any;
384
+ }
385
+ }
386
+ if (Object.keys(echoAnnotations).length > 0) {
387
+ // TODO(dmaretskyi): use new namespace.
388
+ schemaFields[ECHO_ANNOTATIONS_NS_KEY] = echoAnnotations;
389
+ }
390
+
391
+ const echoIdentifier = annotations[TypeIdentifierAnnotationId];
392
+ if (echoIdentifier) {
393
+ schemaFields[ECHO_ANNOTATIONS_NS_KEY] ??= {};
394
+ schemaFields[ECHO_ANNOTATIONS_NS_KEY].schemaId = echoIdentifier;
395
+ }
396
+
397
+ // Custom (at end).
398
+ for (const [key, annotationId] of Object.entries(CustomAnnotations)) {
399
+ const value = annotations[annotationId];
400
+ if (value != null) {
401
+ schemaFields[key] = value;
402
+ }
403
+ }
404
+
405
+ return schemaFields;
406
+ };
407
+
408
+ const decodeTypeIdentifierAnnotation = (schema: JsonSchemaType): string | undefined => {
409
+ // Limit to dxn:echo: URIs.
410
+ if (schema.$id && schema.$id.startsWith('dxn:echo:')) {
411
+ return schema.$id;
412
+ } else if (schema.$id && schema.$id.startsWith('dxn:type:') && schema?.echo?.type?.schemaId) {
413
+ const id = schema?.echo?.type?.schemaId;
414
+ if (ObjectId.isValid(id)) {
415
+ return DXN.fromLocalObjectId(id).toString();
416
+ }
417
+ }
418
+ return undefined;
419
+ };
420
+
421
+ const decodeTypeAnnotation = (schema: JsonSchemaType): TypeAnnotation | undefined => {
422
+ if (schema.typename) {
423
+ const annotation: Types.Mutable<TypeAnnotation> = {
424
+ // TODO(dmaretskyi): Decoding default.
425
+ kind: schema.entityKind ? Schema.decodeSync(EntityKindSchema)(schema.entityKind) : EntityKind.Object,
426
+ typename: schema.typename,
427
+ version: schema.version ?? '0.1.0',
428
+ };
429
+
430
+ if (annotation.kind === EntityKind.Relation) {
431
+ const source = schema.relationSource?.$ref ?? raise(new Error('Relation source not set'));
432
+ const target = schema.relationTarget?.$ref ?? raise(new Error('Relation target not set'));
433
+ annotation.sourceSchema = DXN.parse(source).toString();
434
+ annotation.targetSchema = DXN.parse(target).toString();
435
+ }
436
+
437
+ return annotation;
438
+ }
439
+
440
+ // Decode legacy schema.
441
+ if (!schema.typename && schema?.echo?.type) {
442
+ return {
443
+ kind: EntityKind.Object,
444
+ typename: schema.echo.type.typename,
445
+ version: schema.echo.type.version,
446
+ };
447
+ }
448
+
449
+ return undefined;
450
+ };
451
+
452
+ const jsonSchemaFieldsToAnnotations = (schema: JsonSchemaType): SchemaAST.Annotations => {
453
+ const annotations: Types.Mutable<Schema.Annotations.Schema<any>> = {};
454
+
455
+ const echoAnnotations: JsonSchemaEchoAnnotations = getNormalizedEchoAnnotations(schema) ?? {};
456
+ if (echoAnnotations) {
457
+ for (const [key, annotationId] of Object.entries(EchoAnnotations)) {
458
+ if (echoAnnotations[key as keyof JsonSchemaEchoAnnotations]) {
459
+ annotations[annotationId] = echoAnnotations[key as keyof JsonSchemaEchoAnnotations];
460
+ }
461
+ }
462
+ }
463
+
464
+ annotations[TypeIdentifierAnnotationId] = decodeTypeIdentifierAnnotation(schema);
465
+ const typeAnnotation = decodeTypeAnnotation(schema);
466
+ if (typeAnnotation) {
467
+ annotations[TypeAnnotationId] = typeAnnotation;
468
+ annotations[SchemaAST.JSONSchemaAnnotationId] = makeTypeJsonSchemaAnnotation({
469
+ kind: typeAnnotation.kind,
470
+ typename: typeAnnotation.typename,
471
+ version: typeAnnotation.version,
472
+ relationSource: typeAnnotation.sourceSchema,
473
+ relationTarget: typeAnnotation.targetSchema,
474
+ });
475
+ }
476
+
477
+ // Custom (at end).
478
+ for (const [key, annotationId] of Object.entries({ ...CustomAnnotations, ...DecodedAnnotations })) {
479
+ if (key in schema) {
480
+ annotations[annotationId] = (schema as any)[key];
481
+ }
482
+ }
483
+
484
+ return clearUndefined(annotations);
485
+ };
486
+
487
+ const makeAnnotatedRefinement = (ast: SchemaAST.AST, annotations: SchemaAST.Annotations): SchemaAST.Refinement => {
488
+ return new SchemaAST.Refinement(ast, () => Option.none(), annotations);
489
+ };
490
+
491
+ const addJsonSchemaFields = (ast: SchemaAST.AST, schema: JsonSchemaType): SchemaAST.AST =>
492
+ makeAnnotatedRefinement(ast, { [SchemaAST.JSONSchemaAnnotationId]: schema });
493
+
494
+ /**
495
+ * Fixes field order.
496
+ * Sets `$schema` prop.
497
+ */
498
+ const normalizeJsonSchema = (jsonSchema: JsonSchemaType): JsonSchemaType => {
499
+ if (jsonSchema.properties && 'id' in jsonSchema.properties) {
500
+ jsonSchema.properties = orderKeys(jsonSchema.properties, ['id']); // Put id first.
501
+ }
502
+
503
+ // TODO(dmaretskyi): Makes sure undefined is not left on optional fields for the resulting object.
504
+ jsonSchema.$schema = JSON_SCHEMA_URL;
505
+ jsonSchema = orderKeys(jsonSchema, [
506
+ '$schema',
507
+ '$id',
508
+
509
+ 'entityKind',
510
+ 'typename',
511
+ 'version',
512
+ 'relationTarget',
513
+ 'relationSource',
514
+
515
+ 'type',
516
+ 'enum',
517
+
518
+ 'properties',
519
+ 'required',
520
+ 'propertyOrder', // Custom.
521
+ 'items',
522
+ 'additionalProperties',
523
+
524
+ 'anyOf',
525
+ 'oneOf',
526
+ ]);
527
+ return jsonSchema;
528
+ };
@@ -0,0 +1,75 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Schema from 'effect/Schema';
6
+
7
+ import { getTypename } from '../annotations';
8
+ import { type AnyProperties } from '../types';
9
+
10
+ // TODO(dmaretskyi): Rename to represent commonality between objects and relations (e.g. `entity`).
11
+ export type TypedObjectOptions = {
12
+ // TODO(burdon): Document.
13
+ partial?: true;
14
+ // TODO(burdon): Document.
15
+ record?: true;
16
+ };
17
+
18
+ /**
19
+ *
20
+ */
21
+ // TODO(burdon): Comment required.
22
+ // TODO(dmaretskyi): Rename to represent commonality between objects and relations (e.g. `entity`).
23
+ type SimplifiedSchemaFields<
24
+ SchemaFields extends Schema.Struct.Fields,
25
+ Options extends TypedObjectOptions,
26
+ > = Options['partial'] extends boolean
27
+ ? Schema.SimplifyMutable<Partial<Schema.Struct.Type<SchemaFields>>>
28
+ : Schema.SimplifyMutable<Schema.Struct.Type<SchemaFields>>;
29
+
30
+ /**
31
+ *
32
+ */
33
+ // TODO(burdon): Comment required.
34
+ // TODO(dmaretskyi): Rename to represent commonality between objects and relations (e.g. `entity`).
35
+ export type TypedObjectFields<
36
+ SchemaFields extends Schema.Struct.Fields,
37
+ Options extends TypedObjectOptions,
38
+ > = SimplifiedSchemaFields<SchemaFields, Options> & { id: string } & (Options['record'] extends boolean
39
+ ? Schema.SimplifyMutable<Schema.IndexSignature.Type<Schema.IndexSignature.Records>>
40
+ : {});
41
+
42
+ export const makeTypedEntityClass = (
43
+ typename: string,
44
+ version: string,
45
+ baseSchema: Schema.Schema.AnyNoContext,
46
+ ): Schema.SchemaClass<any> => {
47
+ return class {
48
+ // Implement TypedObject properties.
49
+ static readonly typename = typename;
50
+ static readonly version = version;
51
+
52
+ // Implement Schema.Schema properties.
53
+ // TODO(burdon): Comment required.
54
+ static readonly [Schema.TypeId] = schemaVariance;
55
+ static readonly ast = baseSchema.ast;
56
+ static readonly annotations = baseSchema.annotations.bind(baseSchema);
57
+ static readonly pipe = baseSchema.pipe.bind(baseSchema);
58
+
59
+ // TODO(burdon): Comment required.
60
+ static [Symbol.hasInstance](obj: AnyProperties) {
61
+ return obj != null && getTypename(obj) === typename;
62
+ }
63
+
64
+ // TODO(burdon): Throw APIError.
65
+ private constructor() {
66
+ throw new Error('Use live(Typename, { ...fields }) to instantiate an object.');
67
+ }
68
+ } as any;
69
+ };
70
+
71
+ const schemaVariance = {
72
+ _A: (_: any) => _,
73
+ _I: (_: any) => _,
74
+ _R: (_: never) => _,
75
+ };