@dxos/echo 0.9.0 → 0.9.1-staging.ee54ba693a

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 (289) hide show
  1. package/dist/lib/neutral/Annotation.mjs +30 -8
  2. package/dist/lib/neutral/Database.mjs +7 -3
  3. package/dist/lib/neutral/Entity.mjs +15 -11
  4. package/dist/lib/neutral/Err.mjs +7 -3
  5. package/dist/lib/neutral/Feed.mjs +15 -19
  6. package/dist/lib/neutral/Filter.mjs +13 -11
  7. package/dist/lib/neutral/Format.mjs +3 -7
  8. package/dist/lib/neutral/JsonSchema.mjs +7 -7
  9. package/dist/lib/neutral/Migration.mjs +11 -11
  10. package/dist/lib/neutral/Obj.mjs +19 -13
  11. package/dist/lib/neutral/Order.mjs +1 -1
  12. package/dist/lib/neutral/Query.mjs +17 -17
  13. package/dist/lib/neutral/QueryResult.mjs +1 -1
  14. package/dist/lib/neutral/Ref.mjs +6 -6
  15. package/dist/lib/neutral/Registry.mjs +1 -1
  16. package/dist/lib/neutral/Relation.mjs +12 -12
  17. package/dist/lib/neutral/Tag.mjs +15 -15
  18. package/dist/lib/neutral/Text.mjs +25 -0
  19. package/dist/lib/neutral/Text.mjs.map +7 -0
  20. package/dist/lib/neutral/Type.mjs +10 -10
  21. package/dist/lib/neutral/chunk-2HKGAQM4.mjs +1394 -0
  22. package/dist/lib/neutral/chunk-2HKGAQM4.mjs.map +7 -0
  23. package/dist/lib/neutral/{chunk-O6BH7EPN.mjs → chunk-2ZHECXUR.mjs} +5 -4
  24. package/dist/lib/neutral/chunk-2ZHECXUR.mjs.map +7 -0
  25. package/dist/lib/neutral/{chunk-QQIYS74I.mjs → chunk-3KTE2Y7Q.mjs} +20 -20
  26. package/dist/lib/neutral/chunk-3KTE2Y7Q.mjs.map +7 -0
  27. package/dist/lib/neutral/{chunk-R5W6DXR4.mjs → chunk-3TN2VMI4.mjs} +72 -36
  28. package/dist/lib/neutral/chunk-3TN2VMI4.mjs.map +7 -0
  29. package/dist/lib/neutral/{chunk-5SMDBFVB.mjs → chunk-42L4HJ3Z.mjs} +11 -15
  30. package/dist/lib/neutral/chunk-42L4HJ3Z.mjs.map +7 -0
  31. package/dist/lib/neutral/{chunk-7PI7C4EF.mjs → chunk-4A2NWKRJ.mjs} +5 -5
  32. package/dist/lib/neutral/chunk-ACFAOTKJ.mjs +1531 -0
  33. package/dist/lib/neutral/chunk-ACFAOTKJ.mjs.map +7 -0
  34. package/dist/lib/neutral/{chunk-SBVFRTST.mjs → chunk-BEFR7LEA.mjs} +20 -10
  35. package/dist/lib/neutral/chunk-BEFR7LEA.mjs.map +7 -0
  36. package/dist/lib/neutral/{chunk-6M2Z6WBH.mjs → chunk-BXIKXT7Q.mjs} +2 -6
  37. package/dist/lib/neutral/{chunk-6M2Z6WBH.mjs.map → chunk-BXIKXT7Q.mjs.map} +1 -1
  38. package/dist/lib/neutral/{chunk-UUP46KUQ.mjs → chunk-C57XMMBY.mjs} +21 -20
  39. package/dist/lib/neutral/chunk-C57XMMBY.mjs.map +7 -0
  40. package/dist/lib/neutral/chunk-C62JYFAD.mjs +183 -0
  41. package/dist/lib/neutral/chunk-C62JYFAD.mjs.map +7 -0
  42. package/dist/lib/neutral/{chunk-MZ7K3MLL.mjs → chunk-FSGX2R62.mjs} +3 -3
  43. package/dist/lib/neutral/chunk-FSGX2R62.mjs.map +7 -0
  44. package/dist/lib/neutral/{chunk-TYGKCRMK.mjs → chunk-HBXT3GSB.mjs} +37 -15
  45. package/dist/lib/neutral/chunk-HBXT3GSB.mjs.map +7 -0
  46. package/dist/lib/neutral/{chunk-WU3GIANS.mjs → chunk-IQR45HAD.mjs} +1 -1
  47. package/dist/lib/neutral/chunk-IQR45HAD.mjs.map +7 -0
  48. package/dist/lib/neutral/{chunk-TFEWTY5A.mjs → chunk-KCBW4BR6.mjs} +4 -8
  49. package/dist/lib/neutral/chunk-KCBW4BR6.mjs.map +7 -0
  50. package/dist/lib/neutral/{chunk-WTQJHC75.mjs → chunk-L3E5IXAE.mjs} +225 -45
  51. package/dist/lib/neutral/chunk-L3E5IXAE.mjs.map +7 -0
  52. package/dist/lib/neutral/{chunk-EVK6XBXO.mjs → chunk-PRC4FEKJ.mjs} +2 -2
  53. package/dist/lib/neutral/chunk-PRC4FEKJ.mjs.map +7 -0
  54. package/dist/lib/neutral/{chunk-6YDI3J37.mjs → chunk-SCT6FFCR.mjs} +9 -4
  55. package/dist/lib/neutral/chunk-SCT6FFCR.mjs.map +7 -0
  56. package/dist/lib/neutral/{chunk-BBFJWWAV.mjs → chunk-TOCVVFK2.mjs} +26 -2
  57. package/dist/lib/neutral/chunk-TOCVVFK2.mjs.map +7 -0
  58. package/dist/lib/neutral/{chunk-RIVWNMSF.mjs → chunk-U53LSQQA.mjs} +3 -3
  59. package/dist/lib/neutral/{chunk-RIVWNMSF.mjs.map → chunk-U53LSQQA.mjs.map} +1 -1
  60. package/dist/lib/neutral/{chunk-IGK6FN65.mjs → chunk-UGFFV2FR.mjs} +2 -2
  61. package/dist/lib/neutral/{chunk-35INCYOE.mjs → chunk-UWLP4RFM.mjs} +1 -1
  62. package/dist/lib/neutral/chunk-UWLP4RFM.mjs.map +7 -0
  63. package/dist/lib/neutral/{chunk-LWXVKPPW.mjs → chunk-UZHCQ6NI.mjs} +13 -11
  64. package/dist/lib/neutral/{chunk-LWXVKPPW.mjs.map → chunk-UZHCQ6NI.mjs.map} +3 -3
  65. package/dist/lib/neutral/{chunk-5SUJPHAE.mjs → chunk-WKIT2YY5.mjs} +2 -2
  66. package/dist/lib/neutral/{chunk-T6E37YIP.mjs → chunk-XB6ISRAO.mjs} +38 -18
  67. package/dist/lib/neutral/chunk-XB6ISRAO.mjs.map +7 -0
  68. package/dist/lib/neutral/chunk-XXL42WCB.mjs +84 -0
  69. package/dist/lib/neutral/chunk-XXL42WCB.mjs.map +7 -0
  70. package/dist/lib/neutral/{chunk-ZGNNFYHS.mjs → chunk-XXWK4J53.mjs} +27 -42
  71. package/dist/lib/neutral/chunk-XXWK4J53.mjs.map +7 -0
  72. package/dist/lib/neutral/index.mjs +30 -26
  73. package/dist/lib/neutral/internal/index.mjs +111 -69
  74. package/dist/lib/neutral/meta.json +1 -1
  75. package/dist/lib/neutral/testing/index.mjs +79 -60
  76. package/dist/lib/neutral/testing/index.mjs.map +3 -3
  77. package/dist/types/src/Annotation.d.ts +35 -1
  78. package/dist/types/src/Annotation.d.ts.map +1 -1
  79. package/dist/types/src/Collection.d.ts +9 -8
  80. package/dist/types/src/Collection.d.ts.map +1 -1
  81. package/dist/types/src/Database.d.ts +38 -0
  82. package/dist/types/src/Database.d.ts.map +1 -1
  83. package/dist/types/src/Dataset.d.ts +1 -16
  84. package/dist/types/src/Dataset.d.ts.map +1 -1
  85. package/dist/types/src/Entity.d.ts +2 -0
  86. package/dist/types/src/Entity.d.ts.map +1 -1
  87. package/dist/types/src/Err.d.ts +67 -0
  88. package/dist/types/src/Err.d.ts.map +1 -1
  89. package/dist/types/src/Feed.d.ts +59 -80
  90. package/dist/types/src/Feed.d.ts.map +1 -1
  91. package/dist/types/src/Filter.d.ts +9 -1
  92. package/dist/types/src/Filter.d.ts.map +1 -1
  93. package/dist/types/src/Hypergraph.d.ts +2 -9
  94. package/dist/types/src/Hypergraph.d.ts.map +1 -1
  95. package/dist/types/src/Migration.d.ts +1 -1
  96. package/dist/types/src/Migration.d.ts.map +1 -1
  97. package/dist/types/src/Obj.d.ts +33 -6
  98. package/dist/types/src/Obj.d.ts.map +1 -1
  99. package/dist/types/src/Order.d.ts +1 -1
  100. package/dist/types/src/Order.d.ts.map +1 -1
  101. package/dist/types/src/Query.d.ts +1 -1
  102. package/dist/types/src/Query.d.ts.map +1 -1
  103. package/dist/types/src/QueryResult.d.ts +2 -2
  104. package/dist/types/src/QueryResult.d.ts.map +1 -1
  105. package/dist/types/src/Ref.d.ts +10 -6
  106. package/dist/types/src/Ref.d.ts.map +1 -1
  107. package/dist/types/src/Registry.d.ts +1 -1
  108. package/dist/types/src/Relation.d.ts.map +1 -1
  109. package/dist/types/src/Tag.d.ts +11 -13
  110. package/dist/types/src/Tag.d.ts.map +1 -1
  111. package/dist/types/src/Text.d.ts +41 -0
  112. package/dist/types/src/Text.d.ts.map +1 -0
  113. package/dist/types/src/Text.test.d.ts +2 -0
  114. package/dist/types/src/Text.test.d.ts.map +1 -0
  115. package/dist/types/src/Type.d.ts +38 -21
  116. package/dist/types/src/Type.d.ts.map +1 -1
  117. package/dist/types/src/View.d.ts +8 -9
  118. package/dist/types/src/View.d.ts.map +1 -1
  119. package/dist/types/src/index.d.ts +1 -0
  120. package/dist/types/src/index.d.ts.map +1 -1
  121. package/dist/types/src/internal/Annotation/annotations.d.ts +50 -0
  122. package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -1
  123. package/dist/types/src/internal/Annotation/atoms.d.ts +14 -0
  124. package/dist/types/src/internal/Annotation/atoms.d.ts.map +1 -0
  125. package/dist/types/src/internal/Annotation/entity-dictionary.d.ts +13 -0
  126. package/dist/types/src/internal/Annotation/entity-dictionary.d.ts.map +1 -1
  127. package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
  128. package/dist/types/src/internal/Entity/guard.d.ts.map +1 -1
  129. package/dist/types/src/internal/Entity/model.d.ts +1 -1
  130. package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
  131. package/dist/types/src/internal/Entity/object.d.ts +5 -1
  132. package/dist/types/src/internal/Entity/object.d.ts.map +1 -1
  133. package/dist/types/src/internal/Entity/relation.d.ts +7 -0
  134. package/dist/types/src/internal/Entity/relation.d.ts.map +1 -1
  135. package/dist/types/src/internal/Entity/type-uri.d.ts.map +1 -1
  136. package/dist/types/src/internal/Filter/index.d.ts +2 -0
  137. package/dist/types/src/internal/Filter/index.d.ts.map +1 -0
  138. package/dist/types/src/internal/Filter/match.d.ts +22 -0
  139. package/dist/types/src/internal/Filter/match.d.ts.map +1 -0
  140. package/dist/types/src/internal/Format/format.d.ts +0 -2
  141. package/dist/types/src/internal/Format/format.d.ts.map +1 -1
  142. package/dist/types/src/internal/Format/index.d.ts +2 -2
  143. package/dist/types/src/internal/Format/index.d.ts.map +1 -1
  144. package/dist/types/src/internal/Format/string.d.ts +0 -8
  145. package/dist/types/src/internal/Format/string.d.ts.map +1 -1
  146. package/dist/types/src/internal/Format/types.d.ts +2 -1
  147. package/dist/types/src/internal/Format/types.d.ts.map +1 -1
  148. package/dist/types/src/internal/Obj/atoms.d.ts +12 -3
  149. package/dist/types/src/internal/Obj/atoms.d.ts.map +1 -1
  150. package/dist/types/src/internal/Obj/clone.d.ts +2 -1
  151. package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
  152. package/dist/types/src/internal/Obj/create-object.d.ts +3 -4
  153. package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
  154. package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
  155. package/dist/types/src/internal/Query/index.d.ts +1 -0
  156. package/dist/types/src/internal/Query/index.d.ts.map +1 -1
  157. package/dist/types/src/internal/Query/query-result-effect.d.ts +9 -0
  158. package/dist/types/src/internal/Query/query-result-effect.d.ts.map +1 -0
  159. package/dist/types/src/internal/Ref/atoms.d.ts +1 -2
  160. package/dist/types/src/internal/Ref/atoms.d.ts.map +1 -1
  161. package/dist/types/src/internal/Ref/index.d.ts +1 -0
  162. package/dist/types/src/internal/Ref/index.d.ts.map +1 -1
  163. package/dist/types/src/internal/Ref/ref.d.ts +79 -8
  164. package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
  165. package/dist/types/src/internal/Ref/strong-deps.d.ts +35 -0
  166. package/dist/types/src/internal/Ref/strong-deps.d.ts.map +1 -0
  167. package/dist/types/src/internal/common/atom-snapshot.d.ts +8 -0
  168. package/dist/types/src/internal/common/atom-snapshot.d.ts.map +1 -0
  169. package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
  170. package/dist/types/src/internal/common/proxy/proxy-types.d.ts +12 -0
  171. package/dist/types/src/internal/common/proxy/proxy-types.d.ts.map +1 -1
  172. package/dist/types/src/internal/common/proxy/proxy-utils.d.ts +25 -0
  173. package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
  174. package/dist/types/src/internal/common/proxy/schema-validator.d.ts +5 -0
  175. package/dist/types/src/internal/common/proxy/schema-validator.d.ts.map +1 -1
  176. package/dist/types/src/internal/common/proxy/typed-handler.d.ts +17 -0
  177. package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
  178. package/dist/types/src/internal/common/types/entity.d.ts +4 -4
  179. package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
  180. package/dist/types/src/internal/common/types/meta.d.ts +2 -4
  181. package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
  182. package/dist/types/src/internal/index.d.ts +1 -0
  183. package/dist/types/src/internal/index.d.ts.map +1 -1
  184. package/dist/types/src/testing/test-schema.d.ts +42 -171
  185. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  186. package/dist/types/tsconfig.tsbuildinfo +1 -1
  187. package/package.json +20 -13
  188. package/src/Annotation.test.ts +257 -10
  189. package/src/Annotation.ts +58 -4
  190. package/src/Collection.ts +10 -12
  191. package/src/Database.ts +55 -21
  192. package/src/Entity.ts +3 -1
  193. package/src/Err.ts +22 -0
  194. package/src/Feed.ts +117 -141
  195. package/src/Filter.test.ts +38 -0
  196. package/src/Filter.ts +17 -3
  197. package/src/Hypergraph.ts +2 -11
  198. package/src/Migration.ts +1 -1
  199. package/src/Obj.test.ts +92 -12
  200. package/src/Obj.ts +38 -5
  201. package/src/Order.ts +3 -3
  202. package/src/Query.test.ts +2 -2
  203. package/src/Query.ts +16 -16
  204. package/src/QueryResult.ts +2 -2
  205. package/src/Ref.ts +14 -6
  206. package/src/Registry.ts +1 -1
  207. package/src/Relation.ts +1 -1
  208. package/src/Tag.ts +13 -16
  209. package/src/Text.test.ts +186 -0
  210. package/src/Text.ts +116 -0
  211. package/src/Type.test.ts +52 -24
  212. package/src/Type.ts +85 -33
  213. package/src/View.ts +22 -30
  214. package/src/index.ts +1 -1
  215. package/src/internal/Annotation/annotations.ts +71 -2
  216. package/src/internal/Annotation/atoms.ts +107 -0
  217. package/src/internal/Annotation/entity-dictionary.ts +40 -37
  218. package/src/internal/Entity/api.ts +1 -1
  219. package/src/internal/Entity/guard.ts +2 -1
  220. package/src/internal/Entity/model.ts +2 -2
  221. package/src/internal/Entity/object.ts +14 -1
  222. package/src/internal/Entity/relation.ts +19 -0
  223. package/src/internal/Entity/type-uri.ts +3 -1
  224. package/src/internal/Filter/index.ts +5 -0
  225. package/src/internal/Filter/match.ts +284 -0
  226. package/src/internal/Format/format.ts +0 -2
  227. package/src/internal/Format/index.ts +2 -2
  228. package/src/internal/Format/string.ts +0 -12
  229. package/src/internal/Format/types.ts +4 -2
  230. package/src/internal/JsonSchema/json-schema.test.ts +82 -54
  231. package/src/internal/Obj/atoms.ts +62 -18
  232. package/src/internal/Obj/clone.ts +61 -20
  233. package/src/internal/Obj/create-object.test.ts +3 -3
  234. package/src/internal/Obj/create-object.ts +3 -4
  235. package/src/internal/Obj/inspect.ts +1 -1
  236. package/src/internal/Obj/json-serializer.test.ts +7 -5
  237. package/src/internal/Obj/json-serializer.ts +4 -4
  238. package/src/internal/Obj/schema-validator.test.ts +53 -0
  239. package/src/internal/Obj/set-value.test.ts +29 -19
  240. package/src/internal/Query/index.ts +1 -0
  241. package/src/internal/Query/query-result-effect.ts +35 -0
  242. package/src/internal/Ref/atoms.ts +23 -3
  243. package/src/internal/Ref/index.ts +1 -0
  244. package/src/internal/Ref/ref.test.ts +8 -8
  245. package/src/internal/Ref/ref.ts +122 -39
  246. package/src/internal/Ref/strong-deps.ts +107 -0
  247. package/src/internal/common/atom-snapshot.ts +19 -0
  248. package/src/internal/common/proxy/make-object.ts +1 -1
  249. package/src/internal/common/proxy/proxy-types.ts +20 -0
  250. package/src/internal/common/proxy/proxy-utils.ts +37 -1
  251. package/src/internal/common/proxy/reactive-array.ts +3 -3
  252. package/src/internal/common/proxy/reactive.test.ts +1 -1
  253. package/src/internal/common/proxy/schema-validator.ts +181 -8
  254. package/src/internal/common/proxy/typed-handler.ts +254 -76
  255. package/src/internal/common/types/entity.ts +15 -7
  256. package/src/internal/index.ts +1 -0
  257. package/src/testing/test-schema.ts +75 -90
  258. package/dist/lib/neutral/chunk-35INCYOE.mjs.map +0 -7
  259. package/dist/lib/neutral/chunk-3PBP4V4O.mjs +0 -101
  260. package/dist/lib/neutral/chunk-3PBP4V4O.mjs.map +0 -7
  261. package/dist/lib/neutral/chunk-4ZUHOTCG.mjs +0 -184
  262. package/dist/lib/neutral/chunk-4ZUHOTCG.mjs.map +0 -7
  263. package/dist/lib/neutral/chunk-5SMDBFVB.mjs.map +0 -7
  264. package/dist/lib/neutral/chunk-6YDI3J37.mjs.map +0 -7
  265. package/dist/lib/neutral/chunk-7FPIAJIV.mjs +0 -2279
  266. package/dist/lib/neutral/chunk-7FPIAJIV.mjs.map +0 -7
  267. package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +0 -7
  268. package/dist/lib/neutral/chunk-EVK6XBXO.mjs.map +0 -7
  269. package/dist/lib/neutral/chunk-MZ7K3MLL.mjs.map +0 -7
  270. package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +0 -7
  271. package/dist/lib/neutral/chunk-QQIYS74I.mjs.map +0 -7
  272. package/dist/lib/neutral/chunk-R5W6DXR4.mjs.map +0 -7
  273. package/dist/lib/neutral/chunk-SBVFRTST.mjs.map +0 -7
  274. package/dist/lib/neutral/chunk-T6E37YIP.mjs.map +0 -7
  275. package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +0 -7
  276. package/dist/lib/neutral/chunk-TYGKCRMK.mjs.map +0 -7
  277. package/dist/lib/neutral/chunk-UUP46KUQ.mjs.map +0 -7
  278. package/dist/lib/neutral/chunk-WTQJHC75.mjs.map +0 -7
  279. package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +0 -7
  280. package/dist/lib/neutral/chunk-ZGNNFYHS.mjs.map +0 -7
  281. package/dist/types/src/exemplars.test.d.ts +0 -2
  282. package/dist/types/src/exemplars.test.d.ts.map +0 -1
  283. package/dist/types/src/hierarchy.test.d.ts +0 -2
  284. package/dist/types/src/hierarchy.test.d.ts.map +0 -1
  285. package/src/exemplars.test.ts +0 -21
  286. package/src/hierarchy.test.ts +0 -33
  287. /package/dist/lib/neutral/{chunk-7PI7C4EF.mjs.map → chunk-4A2NWKRJ.mjs.map} +0 -0
  288. /package/dist/lib/neutral/{chunk-IGK6FN65.mjs.map → chunk-UGFFV2FR.mjs.map} +0 -0
  289. /package/dist/lib/neutral/{chunk-5SUJPHAE.mjs.map → chunk-WKIT2YY5.mjs.map} +0 -0
@@ -81,7 +81,8 @@ export const getReferenceAst = (ast: SchemaAST.AST): RefereneAST | undefined =>
81
81
  };
82
82
  };
83
83
 
84
- export const RefTypeId: unique symbol = Symbol('@dxos/echo/internal/Ref');
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ export const RefTypeId: unique symbol = Symbol.for('@dxos/echo/internal/Ref') as any;
85
86
 
86
87
  /**
87
88
  * Reference Schema.
@@ -188,7 +189,14 @@ export interface Ref<T> extends Pipeable.Pipeable {
188
189
  /**
189
190
  * @returns Promise that will resolves with the target object.
190
191
  * Will load the object from disk if it is not present in the working set.
192
+ * Short-circuits immediately when the target is already loaded.
191
193
  * @throws If the object is not available locally.
194
+ *
195
+ * @idiom org.dxos.echo.refLoad
196
+ * applies: Resolving a ref inside an async function or Effect handler — guarantees the object is available before proceeding
197
+ * instead-of: `ref.target` — not guaranteed to be defined in async contexts; use `await ref.load()` (or `yield* Database.load(ref)` in Effect) to ensure the target is present
198
+ * uses: {@link load}
199
+ * related: org.dxos.echo-react.useObjectReactive
192
200
  */
193
201
  load(): Promise<T>;
194
202
 
@@ -253,7 +261,7 @@ export declare namespace Ref {
253
261
  }
254
262
 
255
263
  Ref.isRef = (obj: any): obj is Ref<any> => {
256
- return obj && typeof obj === 'object' && RefTypeId in obj;
264
+ return obj != null && typeof obj === 'object' && RefTypeId in obj;
257
265
  };
258
266
 
259
267
  Ref.hasEntityId = (id: EntityId) => (ref: Ref<any>) => {
@@ -278,7 +286,8 @@ Ref.make = <T extends AnyProperties>(obj: T): Ref<T> => {
278
286
  const id = obj.id;
279
287
  invariant(EntityId.isValid(id), 'Invalid object ID');
280
288
  const uri = EID.make({ entityId: id });
281
- return new RefImpl(uri, obj);
289
+ const ref = new RefImpl(uri, obj);
290
+ return ref;
282
291
  };
283
292
 
284
293
  Ref.fromURI = (uri: URI.URI): Ref<any> => {
@@ -380,22 +389,79 @@ const getSchemaExpectedName = (ast: SchemaAST.Annotated): string | undefined =>
380
389
  );
381
390
  };
382
391
 
392
+ /**
393
+ * Load-source ceiling for a resolution request. Cheaper tiers are always probed first; the
394
+ * ceiling caps how far a request is allowed to reach:
395
+ * - `working-set`: synchronous, in-memory only. A miss settles `unavailable` immediately.
396
+ * - `disk`: probe the working set, then local storage; never the network.
397
+ * - `network`: probe the working set, disk, then fetch from peers.
398
+ *
399
+ * `unavailable` is always relative to the requested ceiling (disk-unavailable ≠ network-unavailable).
400
+ */
401
+ export type RefSource = 'working-set' | 'disk' | 'network';
402
+
403
+ /**
404
+ * A stateful, closure-aware handle to an in-flight (or settled) reference resolution.
405
+ *
406
+ * `ready` means the entity is FULLY USABLE: its own body and its strong-dependency closure are all
407
+ * materialized. The body-vs-closure split is internal; `requesting` transparently covers "a
408
+ * dependency is still loading".
409
+ */
410
+ export interface RefResolverRequest {
411
+ /**
412
+ * `pending` is a one-way entry state (never re-entered). `requesting` means the body and/or
413
+ * closure is still loading. `ready` means fully usable. `unavailable` means unreachable at the
414
+ * requested ceiling.
415
+ */
416
+ readonly state: 'pending' | 'requesting' | 'ready' | 'unavailable';
417
+
418
+ /**
419
+ * Fires (deferred to a microtask) whenever {@link state} changes.
420
+ */
421
+ readonly stateChanged: Event<void>;
422
+
423
+ /**
424
+ * Synchronous snapshot of the resolved entity; defined iff `state === 'ready'`.
425
+ */
426
+ getResult(): AnyProperties | undefined;
427
+
428
+ /**
429
+ * Settles when `state ∈ {ready, unavailable}`.
430
+ */
431
+ wait(): Promise<AnyProperties | undefined>;
432
+
433
+ /**
434
+ * Decrements the refcount on the shared load op(s); cancels the underlying IO at zero.
435
+ */
436
+ abort(): void;
437
+ }
438
+
383
439
  export interface RefResolver {
440
+ /**
441
+ * Resolve a reference, returning a stateful handle. `source` is a required ceiling; cheaper
442
+ * tiers are always probed first.
443
+ */
444
+ resolve(uri: URI.URI, options: { source: RefSource }): RefResolverRequest;
445
+
384
446
  /**
385
447
  * Resolve ref synchronously from the objects in the working set.
386
448
  *
387
449
  * @param uri
388
450
  * @param load If true the resolver should attempt to load the object from disk.
389
451
  * @param onLoad Callback to call when the object is loaded.
452
+ * @deprecated Use {@link resolve} with `{ source: 'working-set' }`. Removed in Task 11.
390
453
  */
391
454
  resolveSync(uri: URI.URI, load: boolean, onLoad?: () => void): AnyProperties | undefined;
392
455
 
393
456
  /**
394
457
  * Resolver ref asynchronously.
458
+ * @deprecated Use {@link resolve} with `{ source: 'network' }`. Removed in Task 11.
395
459
  */
396
- resolve(uri: URI.URI): Promise<AnyProperties | undefined>;
460
+ resolveLegacy(uri: URI.URI): Promise<AnyProperties | undefined>;
397
461
 
398
- // TODO(dmaretskyi): Combine with `resolve`.
462
+ /**
463
+ * @deprecated Use {@link resolve} + `Type.getSchema`. Removed in Task 11.
464
+ */
399
465
  resolveSchema(uri: URI.URI): Promise<Schema.Schema.AnyNoContext | undefined>;
400
466
 
401
467
  /**
@@ -404,14 +470,30 @@ export interface RefResolver {
404
470
  * via `Obj.getType` / `Entity.getType`. Optional — resolvers that only
405
471
  * carry raw schemas may leave this unimplemented; the deserializer falls
406
472
  * back to leaving the type entity unset.
473
+ * @deprecated Use {@link resolve}. Removed in Task 11.
407
474
  */
408
475
  resolveType?(uri: URI.URI): Promise<unknown | undefined>;
409
476
  }
410
477
 
478
+ /**
479
+ * A settled {@link RefResolverRequest} with a fixed `state` and `result`, used by resolvers
480
+ * whose backends are fully synchronous (e.g. {@link StaticRefResolver}).
481
+ */
482
+ export const makeSettledRequest = (
483
+ state: RefResolverRequest['state'],
484
+ result: AnyProperties | undefined,
485
+ ): RefResolverRequest => ({
486
+ state,
487
+ stateChanged: new Event<void>(),
488
+ getResult: () => (state === 'ready' ? result : undefined),
489
+ wait: async () => (state === 'ready' ? result : undefined),
490
+ abort: () => {},
491
+ });
492
+
411
493
  export class RefImpl<T> implements Ref<T> {
494
+ [RefTypeId] = refVariance;
495
+
412
496
  #uri: URI.URI;
413
- #resolver?: RefResolver = undefined;
414
- #resolved = new Event<void>();
415
497
 
416
498
  /**
417
499
  * Target is set when the reference is created from a specific object.
@@ -419,6 +501,9 @@ export class RefImpl<T> implements Ref<T> {
419
501
  */
420
502
  #target: T | undefined = undefined;
421
503
 
504
+ #resolver?: RefResolver = undefined;
505
+ #resolved = new Event<void>();
506
+
422
507
  /**
423
508
  * Callback to issue a reactive notification when object is resolved.
424
509
  */
@@ -438,13 +523,6 @@ export class RefImpl<T> implements Ref<T> {
438
523
  return this.#uri;
439
524
  }
440
525
 
441
- /**
442
- * @inheritdoc
443
- */
444
- get isAvailable(): boolean {
445
- return this.#target !== undefined || this.#resolver !== undefined;
446
- }
447
-
448
526
  /**
449
527
  * @inheritdoc
450
528
  */
@@ -457,6 +535,17 @@ export class RefImpl<T> implements Ref<T> {
457
535
  return this.#resolver.resolveSync(this.#uri, true, this.#resolverCallback) as T | undefined;
458
536
  }
459
537
 
538
+ /**
539
+ * @inheritdoc
540
+ */
541
+ get isAvailable(): boolean {
542
+ return this.#target !== undefined || this.#resolver !== undefined;
543
+ }
544
+
545
+ get atom(): Atom.Atom<T | undefined> {
546
+ return RefAtoms.refSimpleFamily(this);
547
+ }
548
+
460
549
  /**
461
550
  * @inheritdoc
462
551
  */
@@ -465,7 +554,7 @@ export class RefImpl<T> implements Ref<T> {
465
554
  return this.#target;
466
555
  }
467
556
  invariant(this.#resolver, 'Resolver is not set');
468
- const obj = await this.#resolver.resolve(this.#uri);
557
+ const obj = await this.#resolver.resolveLegacy(this.#uri);
469
558
  if (obj == null) {
470
559
  throw new Error('Object not found');
471
560
  }
@@ -480,7 +569,7 @@ export class RefImpl<T> implements Ref<T> {
480
569
  return this.#target;
481
570
  }
482
571
  invariant(this.#resolver, 'Resolver is not set');
483
- return (await this.#resolver.resolve(this.#uri)) as T | undefined;
572
+ return (await this.#resolver.resolveLegacy(this.#uri)) as T | undefined;
484
573
  }
485
574
 
486
575
  /**
@@ -530,8 +619,6 @@ export class RefImpl<T> implements Ref<T> {
530
619
  return this.toString();
531
620
  };
532
621
 
533
- [RefTypeId] = refVariance;
534
-
535
622
  /**
536
623
  * Effect Hash trait. Required for MutableHashMap-based caches (e.g., Atom.family)
537
624
  * to deduplicate Ref instances that point to the same object.
@@ -547,13 +634,12 @@ export class RefImpl<T> implements Ref<T> {
547
634
  return that instanceof RefImpl && this.#uri === that.uri;
548
635
  }
549
636
 
550
- get atom(): Atom.Atom<T | undefined> {
551
- return RefAtoms.refSimpleFamily(this);
637
+ pipe() {
638
+ // eslint-disable-next-line prefer-rest-params
639
+ return Pipeable.pipeArguments(this, arguments);
552
640
  }
553
641
 
554
642
  /**
555
- * Internal method to set the resolver.
556
- *
557
643
  * @internal
558
644
  */
559
645
  _setResolver(resolver: RefResolver): void {
@@ -566,11 +652,6 @@ export class RefImpl<T> implements Ref<T> {
566
652
  _getSavedTarget(): T | undefined {
567
653
  return this.#target;
568
654
  }
569
-
570
- pipe() {
571
- // eslint-disable-next-line prefer-rest-params
572
- return Pipeable.pipeArguments(this, arguments);
573
- }
574
655
  }
575
656
 
576
657
  /**
@@ -624,27 +705,29 @@ export class StaticRefResolver implements RefResolver {
624
705
  return this;
625
706
  }
626
707
 
708
+ resolve(uri: URI.URI, _options: { source: RefSource }): RefResolverRequest {
709
+ const obj = this.#lookup(uri);
710
+ return makeSettledRequest(obj ? 'ready' : 'unavailable', obj);
711
+ }
712
+
627
713
  resolveSync(uri: URI.URI, _load: boolean, _onLoad?: () => void): AnyProperties | undefined {
628
- const echoUri = EID.tryParse(uri);
629
- const id = echoUri ? EID.getEntityId(echoUri) : undefined;
630
- if (id == null) {
631
- return undefined;
632
- }
714
+ return this.#lookup(uri);
715
+ }
633
716
 
634
- return this.objects.get(id);
717
+ async resolveLegacy(uri: URI.URI): Promise<AnyProperties | undefined> {
718
+ return this.#lookup(uri);
719
+ }
720
+
721
+ async resolveSchema(uri: URI.URI): Promise<Schema.Schema.AnyNoContext | undefined> {
722
+ return this.schemas.get(uri);
635
723
  }
636
724
 
637
- async resolve(uri: URI.URI): Promise<AnyProperties | undefined> {
725
+ #lookup(uri: URI.URI): AnyProperties | undefined {
638
726
  const echoUri = EID.tryParse(uri);
639
727
  const id = echoUri ? EID.getEntityId(echoUri) : undefined;
640
728
  if (id == null) {
641
729
  return undefined;
642
730
  }
643
-
644
731
  return this.objects.get(id);
645
732
  }
646
-
647
- async resolveSchema(uri: URI.URI): Promise<Schema.Schema.AnyNoContext | undefined> {
648
- return this.schemas.get(uri);
649
- }
650
733
  }
@@ -0,0 +1,107 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { EID, type SpaceId, type URI } from '@dxos/keys';
6
+
7
+ import { EntityKind } from '../common/types/entity';
8
+ import { RelationSourceDXNId, RelationTargetDXNId } from '../common/types/model-symbols';
9
+ import { ParentId, TypeId } from '../common/types/typename';
10
+ import { getObjectEchoUri } from '../Entity/util';
11
+
12
+ /**
13
+ * Normalized view of the references that make up an entity's strong-dependency set, store-agnostic
14
+ * so it can be filled from an {@link ObjectCore} (db) or a decoded entity (queue item / snapshot).
15
+ */
16
+ export interface StrongDepRefs {
17
+ /** Entity kind — relations additionally depend on their source/target. */
18
+ kind: EntityKind;
19
+ /** Type reference URI (`echo:` for a persisted stored schema, `dxn:` for a static/registry type). */
20
+ type?: URI.URI;
21
+ /** Relation source reference URI. */
22
+ source?: URI.URI;
23
+ /** Relation target reference URI. */
24
+ target?: URI.URI;
25
+ /** Parent reference URI. */
26
+ parent?: URI.URI;
27
+ }
28
+
29
+ /**
30
+ * Direct strong-dependency URIs of an entity: the schema (only when stored as an object), the
31
+ * relation source/target, and the parent. Returns URIs (cross-space `echo:` EIDs and queue-item
32
+ * EIDs included); a persisted schema is an `echo:` URI, a static/registry type is a `dxn:` URI.
33
+ *
34
+ * A static/registry type (`dxn:`) is intentionally NOT a strong dep: it is always synchronously
35
+ * available through the registry, so gating on it would needlessly delay surfacing. Only a
36
+ * persisted (db-backed) schema, addressed by an `echo:` URI, must load before its instances.
37
+ */
38
+ export const getStrongDependencyUris = (refs: StrongDepRefs, owningSpaceId?: SpaceId): URI.URI[] => {
39
+ const res: URI.URI[] = [];
40
+
41
+ if (refs.type != null && EID.tryParse(refs.type) != null) {
42
+ res.push(qualifyToSpace(refs.type, owningSpaceId));
43
+ }
44
+
45
+ if (refs.kind === EntityKind.Relation) {
46
+ if (refs.source != null) {
47
+ res.push(qualifyToSpace(refs.source, owningSpaceId));
48
+ }
49
+ if (refs.target != null) {
50
+ res.push(qualifyToSpace(refs.target, owningSpaceId));
51
+ }
52
+ }
53
+
54
+ if (refs.parent != null) {
55
+ res.push(qualifyToSpace(refs.parent, owningSpaceId));
56
+ }
57
+
58
+ return res;
59
+ };
60
+
61
+ /**
62
+ * Qualifies a space-less (relative) `echo:` dependency URI with the space of the entity that owns it.
63
+ * Same-space references are persisted relative; resolution needs them absolute to route to a single
64
+ * space. Already-qualified URIs (cross-space) and non-`echo:` URIs (registry `dxn:`) pass through.
65
+ */
66
+ const qualifyToSpace = (uri: URI.URI, owningSpaceId: SpaceId | undefined): URI.URI => {
67
+ if (owningSpaceId == null) {
68
+ return uri;
69
+ }
70
+ const eid = EID.tryParse(uri);
71
+ if (eid == null || !EID.isLocal(eid)) {
72
+ return uri;
73
+ }
74
+ const entityId = EID.getEntityId(eid);
75
+ return entityId != null ? EID.make({ spaceId: owningSpaceId, entityId }) : uri;
76
+ };
77
+
78
+ /**
79
+ * Direct strong-dependency URIs of a live (decoded) entity — a queue item, cross-space proxy, or
80
+ * snapshot. Reads the reference URIs off the entity's hidden model symbols. ECHO db cores compute
81
+ * the same set from their raw encoded references via {@link getStrongDependencyUris}.
82
+ */
83
+ export const getStrongDependencies = (entity: unknown): URI.URI[] => {
84
+ if (entity == null || typeof entity !== 'object') {
85
+ return [];
86
+ }
87
+ const props = entity as Record<symbol, unknown>;
88
+ const kind =
89
+ props[RelationSourceDXNId] != null || props[RelationTargetDXNId] != null ? EntityKind.Relation : EntityKind.Object;
90
+ const parent = props[ParentId];
91
+
92
+ // The entity's own space qualifies any relative dependency URIs it carries.
93
+ const selfUri = getObjectEchoUri(entity);
94
+ const owningSpaceId = selfUri != null ? EID.getSpaceId(selfUri) : undefined;
95
+
96
+ return getStrongDependencyUris(
97
+ {
98
+ kind,
99
+ type: typeof props[TypeId] === 'string' ? (props[TypeId] as URI.URI) : undefined,
100
+ source: props[RelationSourceDXNId] as URI.URI | undefined,
101
+ target: props[RelationTargetDXNId] as URI.URI | undefined,
102
+ // A parent is held as the resolved entity; derive its absolute URI for the dependency edge.
103
+ parent: parent != null ? getObjectEchoUri(parent) : undefined,
104
+ },
105
+ owningSpaceId,
106
+ );
107
+ };
@@ -0,0 +1,19 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ /**
6
+ * Snapshot a value to create a new reference for atom change-detection and React dependency tracking.
7
+ * Objects and arrays are shallow-copied (a fresh reference each read, so an in-place mutation is
8
+ * observed); primitives are returned as-is (so they dedupe via `!==`). Shared by the object-property
9
+ * and annotation atom families.
10
+ */
11
+ export const snapshotForComparison = <V>(value: V): V => {
12
+ if (Array.isArray(value)) {
13
+ return [...value] as V;
14
+ }
15
+ if (value !== null && typeof value === 'object') {
16
+ return { ...value } as V;
17
+ }
18
+ return value;
19
+ };
@@ -13,7 +13,7 @@ import { MetaId } from '../types/model-symbols';
13
13
  import { defineHiddenProperty } from './define-hidden-property';
14
14
  import { attachTypedJsonSerializer } from './json-serializer';
15
15
  import { createProxy, getProxyTarget, isValidProxyTarget } from './proxy-utils';
16
- import { TypeSource, TypedReactiveHandler, prepareTypedTarget, setMetaOwner } from './typed-handler';
16
+ import { TypedReactiveHandler, TypeSource, prepareTypedTarget, setMetaOwner } from './typed-handler';
17
17
 
18
18
  /**
19
19
  *
@@ -15,6 +15,26 @@ export interface ReactiveHandler<T extends object> extends ProxyHandler<T> {
15
15
  * Called when a proxy is created for this target.
16
16
  */
17
17
  init(target: T): void;
18
+
19
+ /**
20
+ * Replace the string CRDT value at `path` with `newText`, applying a minimal diff so cursors and
21
+ * concurrent edits are preserved. Implemented by handlers that back string fields; `Text.update`
22
+ * dispatches here. Must run inside a change context (`Obj.update`).
23
+ */
24
+ textUpdate?(target: T, path: readonly (string | number)[], newText: string): void;
25
+
26
+ /**
27
+ * Splice the string CRDT value at `path` (character indices, mirroring `Array.splice`): remove
28
+ * `deleteCount` characters at `start` and insert `insert`. Returns the removed substring. `Text.splice`
29
+ * dispatches here. Must run inside a change context (`Obj.update`).
30
+ */
31
+ textSplice?(
32
+ target: T,
33
+ path: readonly (string | number)[],
34
+ start: number,
35
+ deleteCount: number,
36
+ insert: string,
37
+ ): string;
18
38
  }
19
39
 
20
40
  /**
@@ -8,11 +8,30 @@ import { type ReactiveHandler } from './proxy-types';
8
8
 
9
9
  export const symbolIsProxy = Symbol.for('@dxos/schema/Proxy');
10
10
 
11
+ /**
12
+ * Marker placed on a reactive-object behaviour prototype (e.g. the typed handler's
13
+ * `TypedObject` prototype). A record target whose prototype chain carries this marker
14
+ * is a reactive data record — equivalent, for the purposes of the "plain object" gates
15
+ * below, to one rooted directly at `Object.prototype`. This lets a handler move its
16
+ * per-object metadata onto an intermediate prototype without those gates mistaking the
17
+ * record for a foreign class instance.
18
+ */
19
+ export const symbolReactivePrototype = Symbol.for('@dxos/echo/ReactivePrototype');
20
+
11
21
  /**
12
22
  * Internal api.
13
23
  */
14
24
  export const isProxy = (value: unknown) => !!(value as any)?.[symbolIsProxy];
15
25
 
26
+ /**
27
+ * True if `value` is a plain data record — either rooted at `Object.prototype` or carrying
28
+ * a reactive behaviour prototype (see {@link symbolReactivePrototype}).
29
+ */
30
+ export const isReactiveRecord = (value: any): boolean => {
31
+ const proto = Object.getPrototypeOf(value);
32
+ return proto === Object.prototype || (proto != null && !!proto[symbolReactivePrototype]);
33
+ };
34
+
16
35
  export const isValidProxyTarget = (value: any): value is object => {
17
36
  if (value == null || value[symbolIsProxy]) {
18
37
  return false;
@@ -21,7 +40,7 @@ export const isValidProxyTarget = (value: any): value is object => {
21
40
  return true;
22
41
  }
23
42
 
24
- return typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype;
43
+ return typeof value === 'object' && isReactiveRecord(value);
25
44
  };
26
45
 
27
46
  /**
@@ -41,6 +60,23 @@ export const getProxyHandler = <T extends object>(proxy: any): ReactiveHandler<T
41
60
  return getProxySlot<T>(proxy).handler;
42
61
  };
43
62
 
63
+ /**
64
+ * Clamp a splice range to `Array.prototype.splice` semantics for a string of the given `length`:
65
+ * a negative `start` counts from the end, a `start` past the end appends, and `deleteCount` is bounded
66
+ * to the remaining characters. Shared by both reactive handlers so the string CRDT API behaves
67
+ * identically across the in-memory and Automerge backends (Automerge's `splice` otherwise throws on
68
+ * out-of-range indices).
69
+ */
70
+ export const normalizeSpliceRange = (
71
+ length: number,
72
+ start: number,
73
+ deleteCount: number,
74
+ ): { start: number; deleteCount: number } => {
75
+ const safeStart = start < 0 ? Math.max(length + start, 0) : Math.min(start, length);
76
+ const safeDeleteCount = Math.max(0, Math.min(deleteCount, length - safeStart));
77
+ return { start: safeStart, deleteCount: safeDeleteCount };
78
+ };
79
+
44
80
  /**
45
81
  * Unsafe method to override id for debugging/testing and migration purposes.
46
82
  * @deprecated
@@ -7,7 +7,7 @@ import { createArrayMethodError } from './errors';
7
7
  import { batchEvents } from './event-batch';
8
8
  import { getEchoRoot } from './ownership';
9
9
  import { getProxyTarget, isProxy } from './proxy-utils';
10
- import { ChangeId, EventId } from './symbols';
10
+ import { EventId } from './symbols';
11
11
 
12
12
  /**
13
13
  * Check if array mutation is allowed (inside a change context).
@@ -20,8 +20,8 @@ const checkArrayMutationAllowed = (arr: any, method: string): void => {
20
20
  // Find the root ECHO object.
21
21
  const echoRoot = getEchoRoot(target);
22
22
 
23
- // Check if initialized (has ChangeId marker or EventId).
24
- const isInitialized = (echoRoot as any)[ChangeId] === true || EventId in echoRoot;
23
+ // A root object owns an `EventId` once initialized; before that, mutations are allowed.
24
+ const isInitialized = EventId in echoRoot;
25
25
  if (!isInitialized) {
26
26
  // Array is still being initialized, allow mutations.
27
27
  return;
@@ -36,7 +36,7 @@ describe('Obj.subscribe', () => {
36
36
  test('returns a no-op unsubscribe for non-proxy inputs', () => {
37
37
  const queueShaped: any = {
38
38
  id: '01KQ5NKXJWSKMRPVTVG2GHV8V3',
39
- blueprints: { added: [], removed: [] },
39
+ skills: { added: [], removed: [] },
40
40
  objects: { added: [], removed: [] },
41
41
  };
42
42
  const unsubscribe = Obj.subscribe(queueShaped, () => {});