@optimystic/db-core 0.14.1 → 0.16.2

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 (301) hide show
  1. package/dist/src/blocks/block-store.d.ts +18 -1
  2. package/dist/src/blocks/block-store.d.ts.map +1 -1
  3. package/dist/src/blocks/helpers.d.ts +2 -2
  4. package/dist/src/blocks/helpers.d.ts.map +1 -1
  5. package/dist/src/blocks/helpers.js +2 -2
  6. package/dist/src/blocks/helpers.js.map +1 -1
  7. package/dist/src/btree/btree.d.ts +27 -6
  8. package/dist/src/btree/btree.d.ts.map +1 -1
  9. package/dist/src/btree/btree.js +104 -61
  10. package/dist/src/btree/btree.js.map +1 -1
  11. package/dist/src/chain/chain.d.ts.map +1 -1
  12. package/dist/src/chain/chain.js +11 -1
  13. package/dist/src/chain/chain.js.map +1 -1
  14. package/dist/src/cluster/index.d.ts +1 -0
  15. package/dist/src/cluster/index.d.ts.map +1 -1
  16. package/dist/src/cluster/index.js +1 -0
  17. package/dist/src/cluster/index.js.map +1 -1
  18. package/dist/src/cluster/membership.d.ts +49 -0
  19. package/dist/src/cluster/membership.d.ts.map +1 -0
  20. package/dist/src/cluster/membership.js +75 -0
  21. package/dist/src/cluster/membership.js.map +1 -0
  22. package/dist/src/cluster/structs.d.ts +50 -1
  23. package/dist/src/cluster/structs.d.ts.map +1 -1
  24. package/dist/src/cluster/structs.js +9 -1
  25. package/dist/src/cluster/structs.js.map +1 -1
  26. package/dist/src/cohort-topic/addressing.d.ts +8 -2
  27. package/dist/src/cohort-topic/addressing.d.ts.map +1 -1
  28. package/dist/src/cohort-topic/addressing.js +11 -3
  29. package/dist/src/cohort-topic/addressing.js.map +1 -1
  30. package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts +13 -7
  31. package/dist/src/cohort-topic/antidos/bootstrap-evidence.d.ts.map +1 -1
  32. package/dist/src/cohort-topic/antidos/bootstrap-evidence.js +17 -6
  33. package/dist/src/cohort-topic/antidos/bootstrap-evidence.js.map +1 -1
  34. package/dist/src/cohort-topic/antidos/replay-guard.d.ts +17 -0
  35. package/dist/src/cohort-topic/antidos/replay-guard.d.ts.map +1 -1
  36. package/dist/src/cohort-topic/antidos/replay-guard.js +33 -0
  37. package/dist/src/cohort-topic/antidos/replay-guard.js.map +1 -1
  38. package/dist/src/cohort-topic/antidos/topic-budget.d.ts +7 -0
  39. package/dist/src/cohort-topic/antidos/topic-budget.d.ts.map +1 -1
  40. package/dist/src/cohort-topic/antidos/topic-budget.js +8 -2
  41. package/dist/src/cohort-topic/antidos/topic-budget.js.map +1 -1
  42. package/dist/src/cohort-topic/coldstart.d.ts +34 -14
  43. package/dist/src/cohort-topic/coldstart.d.ts.map +1 -1
  44. package/dist/src/cohort-topic/coldstart.js +25 -11
  45. package/dist/src/cohort-topic/coldstart.js.map +1 -1
  46. package/dist/src/cohort-topic/gossip/bus.d.ts +12 -1
  47. package/dist/src/cohort-topic/gossip/bus.d.ts.map +1 -1
  48. package/dist/src/cohort-topic/gossip/bus.js +27 -1
  49. package/dist/src/cohort-topic/gossip/bus.js.map +1 -1
  50. package/dist/src/cohort-topic/gossip/view.d.ts +8 -0
  51. package/dist/src/cohort-topic/gossip/view.d.ts.map +1 -1
  52. package/dist/src/cohort-topic/gossip/view.js +17 -1
  53. package/dist/src/cohort-topic/gossip/view.js.map +1 -1
  54. package/dist/src/cohort-topic/member-engine.d.ts +10 -3
  55. package/dist/src/cohort-topic/member-engine.d.ts.map +1 -1
  56. package/dist/src/cohort-topic/member-engine.js +29 -14
  57. package/dist/src/cohort-topic/member-engine.js.map +1 -1
  58. package/dist/src/cohort-topic/membership/publisher.d.ts +14 -7
  59. package/dist/src/cohort-topic/membership/publisher.d.ts.map +1 -1
  60. package/dist/src/cohort-topic/membership/publisher.js +15 -27
  61. package/dist/src/cohort-topic/membership/publisher.js.map +1 -1
  62. package/dist/src/cohort-topic/membership/verifier.d.ts +35 -0
  63. package/dist/src/cohort-topic/membership/verifier.d.ts.map +1 -1
  64. package/dist/src/cohort-topic/membership/verifier.js +88 -3
  65. package/dist/src/cohort-topic/membership/verifier.js.map +1 -1
  66. package/dist/src/cohort-topic/promotion.d.ts +7 -0
  67. package/dist/src/cohort-topic/promotion.d.ts.map +1 -1
  68. package/dist/src/cohort-topic/promotion.js +16 -2
  69. package/dist/src/cohort-topic/promotion.js.map +1 -1
  70. package/dist/src/cohort-topic/registration/renewal.d.ts +18 -0
  71. package/dist/src/cohort-topic/registration/renewal.d.ts.map +1 -1
  72. package/dist/src/cohort-topic/registration/renewal.js +54 -0
  73. package/dist/src/cohort-topic/registration/renewal.js.map +1 -1
  74. package/dist/src/cohort-topic/registration/types.d.ts +12 -0
  75. package/dist/src/cohort-topic/registration/types.d.ts.map +1 -1
  76. package/dist/src/cohort-topic/registration/types.js +14 -0
  77. package/dist/src/cohort-topic/registration/types.js.map +1 -1
  78. package/dist/src/cohort-topic/service.d.ts +4 -3
  79. package/dist/src/cohort-topic/service.d.ts.map +1 -1
  80. package/dist/src/cohort-topic/service.js +38 -12
  81. package/dist/src/cohort-topic/service.js.map +1 -1
  82. package/dist/src/cohort-topic/sig/payloads.d.ts +23 -7
  83. package/dist/src/cohort-topic/sig/payloads.d.ts.map +1 -1
  84. package/dist/src/cohort-topic/sig/payloads.js +22 -6
  85. package/dist/src/cohort-topic/sig/payloads.js.map +1 -1
  86. package/dist/src/cohort-topic/traffic.d.ts +6 -0
  87. package/dist/src/cohort-topic/traffic.d.ts.map +1 -1
  88. package/dist/src/cohort-topic/traffic.js +16 -1
  89. package/dist/src/cohort-topic/traffic.js.map +1 -1
  90. package/dist/src/cohort-topic/walk.d.ts +22 -7
  91. package/dist/src/cohort-topic/walk.d.ts.map +1 -1
  92. package/dist/src/cohort-topic/walk.js +78 -18
  93. package/dist/src/cohort-topic/walk.js.map +1 -1
  94. package/dist/src/cohort-topic/wire/codec.d.ts +3 -1
  95. package/dist/src/cohort-topic/wire/codec.d.ts.map +1 -1
  96. package/dist/src/cohort-topic/wire/codec.js +7 -1
  97. package/dist/src/cohort-topic/wire/codec.js.map +1 -1
  98. package/dist/src/cohort-topic/wire/index.d.ts +1 -1
  99. package/dist/src/cohort-topic/wire/index.d.ts.map +1 -1
  100. package/dist/src/cohort-topic/wire/index.js +1 -1
  101. package/dist/src/cohort-topic/wire/index.js.map +1 -1
  102. package/dist/src/cohort-topic/wire/payloads.d.ts +5 -4
  103. package/dist/src/cohort-topic/wire/payloads.d.ts.map +1 -1
  104. package/dist/src/cohort-topic/wire/payloads.js +14 -5
  105. package/dist/src/cohort-topic/wire/payloads.js.map +1 -1
  106. package/dist/src/cohort-topic/wire/primitives.d.ts +65 -0
  107. package/dist/src/cohort-topic/wire/primitives.d.ts.map +1 -0
  108. package/dist/src/cohort-topic/wire/primitives.js +173 -0
  109. package/dist/src/cohort-topic/wire/primitives.js.map +1 -0
  110. package/dist/src/cohort-topic/wire/types.d.ts +132 -5
  111. package/dist/src/cohort-topic/wire/types.d.ts.map +1 -1
  112. package/dist/src/cohort-topic/wire/validate.d.ts +15 -5
  113. package/dist/src/cohort-topic/wire/validate.d.ts.map +1 -1
  114. package/dist/src/cohort-topic/wire/validate.js +146 -123
  115. package/dist/src/cohort-topic/wire/validate.js.map +1 -1
  116. package/dist/src/collection/collection.d.ts +23 -12
  117. package/dist/src/collection/collection.d.ts.map +1 -1
  118. package/dist/src/collection/collection.js +111 -35
  119. package/dist/src/collection/collection.js.map +1 -1
  120. package/dist/src/collection/struct.d.ts +37 -2
  121. package/dist/src/collection/struct.d.ts.map +1 -1
  122. package/dist/src/collection/struct.js +16 -1
  123. package/dist/src/collection/struct.js.map +1 -1
  124. package/dist/src/collections/tree/tree.d.ts +18 -1
  125. package/dist/src/collections/tree/tree.d.ts.map +1 -1
  126. package/dist/src/collections/tree/tree.js +36 -6
  127. package/dist/src/collections/tree/tree.js.map +1 -1
  128. package/dist/src/index.d.ts +1 -0
  129. package/dist/src/index.d.ts.map +1 -1
  130. package/dist/src/index.js +1 -0
  131. package/dist/src/index.js.map +1 -1
  132. package/dist/src/log/log.d.ts +26 -3
  133. package/dist/src/log/log.d.ts.map +1 -1
  134. package/dist/src/log/log.js +34 -7
  135. package/dist/src/log/log.js.map +1 -1
  136. package/dist/src/log/struct.d.ts +5 -4
  137. package/dist/src/log/struct.d.ts.map +1 -1
  138. package/dist/src/log/struct.js.map +1 -1
  139. package/dist/src/matchmaking/wire.d.ts +2 -1
  140. package/dist/src/matchmaking/wire.d.ts.map +1 -1
  141. package/dist/src/matchmaking/wire.js +13 -92
  142. package/dist/src/matchmaking/wire.js.map +1 -1
  143. package/dist/src/network/i-key-network.d.ts +9 -0
  144. package/dist/src/network/i-key-network.d.ts.map +1 -1
  145. package/dist/src/network/i-repo.d.ts +8 -0
  146. package/dist/src/network/i-repo.d.ts.map +1 -1
  147. package/dist/src/network/struct.d.ts +10 -0
  148. package/dist/src/network/struct.d.ts.map +1 -1
  149. package/dist/src/reactivity/push-state.d.ts.map +1 -1
  150. package/dist/src/reactivity/push-state.js +4 -33
  151. package/dist/src/reactivity/push-state.js.map +1 -1
  152. package/dist/src/reactivity/wire-validate.d.ts +7 -22
  153. package/dist/src/reactivity/wire-validate.d.ts.map +1 -1
  154. package/dist/src/reactivity/wire-validate.js +7 -73
  155. package/dist/src/reactivity/wire-validate.js.map +1 -1
  156. package/dist/src/reactivity/wire.js +3 -3
  157. package/dist/src/reactivity/wire.js.map +1 -1
  158. package/dist/src/testing/async-wait.d.ts +23 -0
  159. package/dist/src/testing/async-wait.d.ts.map +1 -0
  160. package/dist/src/testing/async-wait.js +42 -0
  161. package/dist/src/testing/async-wait.js.map +1 -0
  162. package/dist/src/testing/index.d.ts +3 -0
  163. package/dist/src/testing/index.d.ts.map +1 -0
  164. package/dist/src/testing/index.js +3 -0
  165. package/dist/src/testing/index.js.map +1 -0
  166. package/dist/src/testing/test-transactor.d.ts +44 -0
  167. package/dist/src/testing/test-transactor.d.ts.map +1 -0
  168. package/dist/src/testing/test-transactor.js +423 -0
  169. package/dist/src/testing/test-transactor.js.map +1 -0
  170. package/dist/src/transaction/actions-engine.d.ts +6 -3
  171. package/dist/src/transaction/actions-engine.d.ts.map +1 -1
  172. package/dist/src/transaction/actions-engine.js +8 -7
  173. package/dist/src/transaction/actions-engine.js.map +1 -1
  174. package/dist/src/transaction/coordinator.d.ts +43 -22
  175. package/dist/src/transaction/coordinator.d.ts.map +1 -1
  176. package/dist/src/transaction/coordinator.js +443 -178
  177. package/dist/src/transaction/coordinator.js.map +1 -1
  178. package/dist/src/transaction/errors.d.ts +82 -0
  179. package/dist/src/transaction/errors.d.ts.map +1 -0
  180. package/dist/src/transaction/errors.js +93 -0
  181. package/dist/src/transaction/errors.js.map +1 -0
  182. package/dist/src/transaction/index.d.ts +6 -3
  183. package/dist/src/transaction/index.d.ts.map +1 -1
  184. package/dist/src/transaction/index.js +4 -2
  185. package/dist/src/transaction/index.js.map +1 -1
  186. package/dist/src/transaction/operations-hash.d.ts +119 -0
  187. package/dist/src/transaction/operations-hash.d.ts.map +1 -0
  188. package/dist/src/transaction/operations-hash.js +180 -0
  189. package/dist/src/transaction/operations-hash.js.map +1 -0
  190. package/dist/src/transaction/read-dependency-collector.d.ts +43 -0
  191. package/dist/src/transaction/read-dependency-collector.d.ts.map +1 -0
  192. package/dist/src/transaction/read-dependency-collector.js +69 -0
  193. package/dist/src/transaction/read-dependency-collector.js.map +1 -0
  194. package/dist/src/transaction/session.d.ts +12 -3
  195. package/dist/src/transaction/session.d.ts.map +1 -1
  196. package/dist/src/transaction/session.js +35 -9
  197. package/dist/src/transaction/session.js.map +1 -1
  198. package/dist/src/transaction/transaction.d.ts +162 -1
  199. package/dist/src/transaction/transaction.d.ts.map +1 -1
  200. package/dist/src/transaction/transaction.js +85 -3
  201. package/dist/src/transaction/transaction.js.map +1 -1
  202. package/dist/src/transaction/validator.d.ts +3 -11
  203. package/dist/src/transaction/validator.d.ts.map +1 -1
  204. package/dist/src/transaction/validator.js +69 -28
  205. package/dist/src/transaction/validator.js.map +1 -1
  206. package/dist/src/transactor/network-transactor.d.ts +35 -0
  207. package/dist/src/transactor/network-transactor.d.ts.map +1 -1
  208. package/dist/src/transactor/network-transactor.js +146 -40
  209. package/dist/src/transactor/network-transactor.js.map +1 -1
  210. package/dist/src/transactor/transactor-source.d.ts +19 -5
  211. package/dist/src/transactor/transactor-source.d.ts.map +1 -1
  212. package/dist/src/transactor/transactor-source.js +43 -11
  213. package/dist/src/transactor/transactor-source.js.map +1 -1
  214. package/dist/src/transform/atomic-proxy.d.ts +35 -5
  215. package/dist/src/transform/atomic-proxy.d.ts.map +1 -1
  216. package/dist/src/transform/atomic-proxy.js +39 -7
  217. package/dist/src/transform/atomic-proxy.js.map +1 -1
  218. package/dist/src/transform/cache-source.d.ts +36 -5
  219. package/dist/src/transform/cache-source.d.ts.map +1 -1
  220. package/dist/src/transform/cache-source.js +84 -8
  221. package/dist/src/transform/cache-source.js.map +1 -1
  222. package/dist/src/transform/helpers.d.ts.map +1 -1
  223. package/dist/src/transform/helpers.js +8 -2
  224. package/dist/src/transform/helpers.js.map +1 -1
  225. package/dist/src/transform/tracker.d.ts +17 -2
  226. package/dist/src/transform/tracker.d.ts.map +1 -1
  227. package/dist/src/transform/tracker.js +66 -11
  228. package/dist/src/transform/tracker.js.map +1 -1
  229. package/dist/src/utility/backoff.d.ts +48 -0
  230. package/dist/src/utility/backoff.d.ts.map +1 -0
  231. package/dist/src/utility/backoff.js +60 -0
  232. package/dist/src/utility/backoff.js.map +1 -0
  233. package/dist/src/utility/pending.d.ts +1 -0
  234. package/dist/src/utility/pending.d.ts.map +1 -1
  235. package/dist/src/utility/pending.js +3 -1
  236. package/dist/src/utility/pending.js.map +1 -1
  237. package/package.json +4 -4
  238. package/src/blocks/block-store.ts +19 -1
  239. package/src/blocks/helpers.ts +3 -3
  240. package/src/btree/btree.ts +108 -63
  241. package/src/chain/chain.ts +11 -1
  242. package/src/cluster/index.ts +1 -0
  243. package/src/cluster/membership.ts +85 -0
  244. package/src/cluster/structs.ts +51 -1
  245. package/src/cohort-topic/addressing.ts +12 -4
  246. package/src/cohort-topic/antidos/bootstrap-evidence.ts +21 -9
  247. package/src/cohort-topic/antidos/replay-guard.ts +37 -0
  248. package/src/cohort-topic/antidos/topic-budget.ts +17 -2
  249. package/src/cohort-topic/coldstart.ts +48 -15
  250. package/src/cohort-topic/gossip/bus.ts +39 -2
  251. package/src/cohort-topic/gossip/view.ts +26 -1
  252. package/src/cohort-topic/member-engine.ts +36 -15
  253. package/src/cohort-topic/membership/publisher.ts +25 -33
  254. package/src/cohort-topic/membership/verifier.ts +119 -3
  255. package/src/cohort-topic/promotion.ts +23 -2
  256. package/src/cohort-topic/registration/renewal.ts +73 -1
  257. package/src/cohort-topic/registration/types.ts +15 -0
  258. package/src/cohort-topic/service.ts +41 -15
  259. package/src/cohort-topic/sig/payloads.ts +29 -9
  260. package/src/cohort-topic/traffic.ts +23 -1
  261. package/src/cohort-topic/walk.ts +95 -24
  262. package/src/cohort-topic/wire/codec.ts +12 -0
  263. package/src/cohort-topic/wire/index.ts +2 -0
  264. package/src/cohort-topic/wire/payloads.ts +14 -5
  265. package/src/cohort-topic/wire/primitives.ts +188 -0
  266. package/src/cohort-topic/wire/types.ts +136 -4
  267. package/src/cohort-topic/wire/validate.ts +168 -134
  268. package/src/collection/collection.ts +123 -40
  269. package/src/collection/struct.ts +44 -2
  270. package/src/collections/tree/tree.ts +42 -5
  271. package/src/index.ts +1 -0
  272. package/src/log/log.ts +37 -9
  273. package/src/log/struct.ts +5 -4
  274. package/src/matchmaking/wire.ts +25 -102
  275. package/src/network/i-key-network.ts +10 -0
  276. package/src/network/i-repo.ts +8 -0
  277. package/src/network/struct.ts +10 -0
  278. package/src/reactivity/push-state.ts +4 -37
  279. package/src/reactivity/wire-validate.ts +7 -81
  280. package/src/reactivity/wire.ts +3 -3
  281. package/src/testing/async-wait.ts +65 -0
  282. package/src/testing/index.ts +2 -0
  283. package/src/testing/test-transactor.ts +468 -0
  284. package/src/transaction/actions-engine.ts +8 -6
  285. package/src/transaction/coordinator.ts +498 -229
  286. package/src/transaction/errors.ts +91 -0
  287. package/src/transaction/index.ts +23 -3
  288. package/src/transaction/operations-hash.ts +196 -0
  289. package/src/transaction/read-dependency-collector.ts +78 -0
  290. package/src/transaction/session.ts +37 -9
  291. package/src/transaction/transaction.ts +211 -4
  292. package/src/transaction/validator.ts +73 -48
  293. package/src/transactor/network-transactor.ts +164 -49
  294. package/src/transactor/transactor-source.ts +47 -12
  295. package/src/transform/atomic-proxy.ts +92 -49
  296. package/src/transform/cache-source.ts +87 -9
  297. package/src/transform/helpers.ts +8 -2
  298. package/src/transform/tracker.ts +69 -11
  299. package/src/utility/backoff.ts +95 -0
  300. package/src/utility/pending.ts +3 -1
  301. package/src/transaction/context.ts +0 -103
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../../src/transform/tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../../src/transform/tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Jittered exponential backoff shared by the retry loops in db-core
3
+ * ({@link Collection.sync} and {@link TransactionCoordinator.commit}).
4
+ *
5
+ * The point of the jitter is fairness under contention: when many clients lose the SAME
6
+ * optimistic-concurrency race at t=0, a bare exponential curve makes them all re-attempt at the
7
+ * identical next tick — a thundering herd that just re-collides. Multiplying the exponential value
8
+ * by a random factor spreads those re-attempts across a window so offered load per tick sheds
9
+ * instead of cascading. This is the same shape as `cohort-topic`'s `backoffRetryMs`, with the
10
+ * proportional-jitter term added.
11
+ */
12
+ /** A source of uniform randomness in [0, 1). Injected in tests so a deterministic sequence can be
13
+ * asserted; production uses {@link cryptoRand}. */
14
+ export type RandFn = () => number;
15
+ /** Uniform value in [0, 1) drawn from the same CSPRNG (`@noble/hashes` `randomBytes`) the rest of
16
+ * db-core uses — deliberately NOT `Math.random`, so backoff jitter shares the package's randomness
17
+ * source rather than introducing a second, weaker one. */
18
+ export declare function cryptoRand(): number;
19
+ export interface JitteredBackoffConfig {
20
+ /** Base delay (ms) for attempt 0, before jitter. */
21
+ baseMs: number;
22
+ /** Hard ceiling (ms) on the pre-jitter exponential value. */
23
+ capMs: number;
24
+ /** Geometric growth per attempt. Default 2 (doubling). */
25
+ factor?: number;
26
+ /** Fraction of the exponential value that jitter may subtract, in [0, 1]. Default 0.5, so the
27
+ * returned delay lands uniformly in `((1 - jitterFraction) · exp, exp]` — i.e. `(0.5·exp, exp]`. */
28
+ jitterFraction?: number;
29
+ }
30
+ /**
31
+ * Delay (ms) for retry `attempt` (0-based):
32
+ *
33
+ * exp = min(baseMs · factor^attempt, capMs)
34
+ * delay = exp · (1 - jitterFraction · rand()) // rand() ∈ [0, 1)
35
+ *
36
+ * With the defaults (factor 2, jitterFraction 0.5) the delay is uniform in `(0.5·exp, exp]`: never
37
+ * zero (as long as `baseMs > 0`) and never above `capMs`. `attempt` must be a non-negative integer
38
+ * — pass `consecutiveFailures - 1` so the first retry backs off by ~`baseMs`.
39
+ */
40
+ export declare function jitteredBackoffMs(attempt: number, config: JitteredBackoffConfig, rand?: RandFn): number;
41
+ /** Build an AbortError for a cooperatively-aborted wait. Prefers the signal's own reason when it is
42
+ * an Error (so callers who passed a custom abort reason see it), otherwise a `name='AbortError'`
43
+ * Error. */
44
+ export declare function makeAbortError(signal?: AbortSignal): Error;
45
+ /** Sleep for `ms`, resolving early (rejecting with an AbortError) if `signal` aborts — so a retry
46
+ * loop waiting out a backoff rejects promptly instead of finishing the sleep. */
47
+ export declare function abortableDelay(ms: number, signal?: AbortSignal): Promise<void>;
48
+ //# sourceMappingURL=backoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backoff.d.ts","sourceRoot":"","sources":["../../../src/utility/backoff.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH;mDACmD;AACnD,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;AAElC;;0DAE0D;AAC1D,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAED,MAAM,WAAW,qBAAqB;IACrC,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;wGACoG;IACpG,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,qBAAqB,EAC7B,IAAI,GAAE,MAAmB,GACvB,MAAM,CAQR;AAED;;YAEY;AACZ,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAO1D;AAED;iFACiF;AACjF,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9E"}
@@ -0,0 +1,60 @@
1
+ import { randomBytes } from '@noble/hashes/utils.js';
2
+ /** Uniform value in [0, 1) drawn from the same CSPRNG (`@noble/hashes` `randomBytes`) the rest of
3
+ * db-core uses — deliberately NOT `Math.random`, so backoff jitter shares the package's randomness
4
+ * source rather than introducing a second, weaker one. */
5
+ export function cryptoRand() {
6
+ const b = randomBytes(4);
7
+ // Assemble a uint32 (>>> 0 clears the sign bit the shifts would otherwise set), then normalise.
8
+ const u = (((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]) >>> 0);
9
+ return u / 0x1_0000_0000;
10
+ }
11
+ /**
12
+ * Delay (ms) for retry `attempt` (0-based):
13
+ *
14
+ * exp = min(baseMs · factor^attempt, capMs)
15
+ * delay = exp · (1 - jitterFraction · rand()) // rand() ∈ [0, 1)
16
+ *
17
+ * With the defaults (factor 2, jitterFraction 0.5) the delay is uniform in `(0.5·exp, exp]`: never
18
+ * zero (as long as `baseMs > 0`) and never above `capMs`. `attempt` must be a non-negative integer
19
+ * — pass `consecutiveFailures - 1` so the first retry backs off by ~`baseMs`.
20
+ */
21
+ export function jitteredBackoffMs(attempt, config, rand = cryptoRand) {
22
+ if (!Number.isInteger(attempt) || attempt < 0) {
23
+ throw new RangeError(`attempt must be a non-negative integer, got ${attempt}`);
24
+ }
25
+ const factor = config.factor ?? 2;
26
+ const jitterFraction = config.jitterFraction ?? 0.5;
27
+ const exp = Math.min(config.baseMs * factor ** attempt, config.capMs);
28
+ return exp * (1 - jitterFraction * rand());
29
+ }
30
+ /** Build an AbortError for a cooperatively-aborted wait. Prefers the signal's own reason when it is
31
+ * an Error (so callers who passed a custom abort reason see it), otherwise a `name='AbortError'`
32
+ * Error. */
33
+ export function makeAbortError(signal) {
34
+ if (signal && signal.reason instanceof Error) {
35
+ return signal.reason;
36
+ }
37
+ const err = new Error('The operation was aborted');
38
+ err.name = 'AbortError';
39
+ return err;
40
+ }
41
+ /** Sleep for `ms`, resolving early (rejecting with an AbortError) if `signal` aborts — so a retry
42
+ * loop waiting out a backoff rejects promptly instead of finishing the sleep. */
43
+ export function abortableDelay(ms, signal) {
44
+ return new Promise((resolve, reject) => {
45
+ if (signal?.aborted) {
46
+ reject(makeAbortError(signal));
47
+ return;
48
+ }
49
+ const onAbort = () => {
50
+ clearTimeout(timer);
51
+ reject(makeAbortError(signal));
52
+ };
53
+ const timer = setTimeout(() => {
54
+ signal?.removeEventListener('abort', onAbort);
55
+ resolve();
56
+ }, ms);
57
+ signal?.addEventListener('abort', onAbort, { once: true });
58
+ });
59
+ }
60
+ //# sourceMappingURL=backoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backoff.js","sourceRoot":"","sources":["../../../src/utility/backoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAkBrD;;0DAE0D;AAC1D,MAAM,UAAU,UAAU;IACzB,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACzB,gGAAgG;IAChG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,OAAO,CAAC,GAAG,aAAa,CAAC;AAC1B,CAAC;AAcD;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAe,EACf,MAA6B,EAC7B,OAAe,UAAU;IAEzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,UAAU,CAAC,+CAA+C,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAClC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,GAAG,CAAC;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACtE,OAAO,GAAG,GAAG,CAAC,CAAC,GAAG,cAAc,GAAG,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED;;YAEY;AACZ,MAAM,UAAU,cAAc,CAAC,MAAoB;IAClD,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,YAAY,KAAK,EAAE,CAAC;QAC9C,OAAO,MAAM,CAAC,MAAM,CAAC;IACtB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACnD,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;IACxB,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;iFACiF;AACjF,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,MAAoB;IAC9D,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC5C,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/B,OAAO;QACR,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,cAAc,CAAC,MAAO,CAAC,CAAC,CAAC;QACjC,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,OAAO,EAAE,CAAC;QACX,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -2,6 +2,7 @@ export declare class Pending<T> {
2
2
  promise: Promise<T>;
3
3
  response?: T;
4
4
  error?: unknown;
5
+ private _responded;
5
6
  t1: number;
6
7
  duration?: number;
7
8
  get isResponse(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../src/utility/pending.ts"],"names":[],"mappings":"AAAA,qBAAa,OAAO,CAAC,CAAC;IA6Bb,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IA5B3B,QAAQ,CAAC,EAAE,CAAC,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,SAAc;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAEK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;gBAWlB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;CAW3B"}
1
+ {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../src/utility/pending.ts"],"names":[],"mappings":"AAAA,qBAAa,OAAO,CAAC,CAAC;IA8Bb,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IA7B3B,QAAQ,CAAC,EAAE,CAAC,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,UAAU,CAAS;IAC3B,EAAE,SAAc;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAEK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;gBAWlB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;CAY3B"}
@@ -2,10 +2,11 @@ export class Pending {
2
2
  promise;
3
3
  response;
4
4
  error;
5
+ _responded = false;
5
6
  t1 = Date.now();
6
7
  duration;
7
8
  get isResponse() {
8
- return this.response !== undefined;
9
+ return this._responded;
9
10
  }
10
11
  get isError() {
11
12
  return this.error !== undefined;
@@ -27,6 +28,7 @@ export class Pending {
27
28
  promise.then(response => {
28
29
  this.duration = Date.now() - this.t1;
29
30
  this.response = response;
31
+ this._responded = true;
30
32
  return response;
31
33
  }, error => {
32
34
  this.duration = Date.now() - this.t1;
@@ -1 +1 @@
1
- {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../../src/utility/pending.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,OAAO;IA6BX;IA5BR,QAAQ,CAAK;IACb,KAAK,CAAW;IAChB,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAU;IAElB,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC;IACpC,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;IACjC,CAAC;IAED,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,MAAM;QACX,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,QAAS,CAAC;QACvB,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,KAAM,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,YACQ,OAAmB;QAAnB,YAAO,GAAP,OAAO,CAAY;QAE1B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;YACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACzB,OAAO,QAAQ,CAAC;QACjB,CAAC,EAAE,KAAK,CAAC,EAAE;YACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACpB,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../../src/utility/pending.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,OAAO;IA8BX;IA7BR,QAAQ,CAAK;IACb,KAAK,CAAW;IACR,UAAU,GAAG,KAAK,CAAC;IAC3B,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAChB,QAAQ,CAAU;IAElB,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;IACjC,CAAC;IAED,IAAI,UAAU;QACb,OAAO,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,MAAM;QACX,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,QAAS,CAAC;QACvB,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,KAAM,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,YACQ,OAAmB;QAAnB,YAAO,GAAP,OAAO,CAAY;QAE1B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;YACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,OAAO,QAAQ,CAAC;QACjB,CAAC,EAAE,KAAK,CAAC,EAAE;YACV,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACpB,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimystic/db-core",
3
- "version": "0.14.1",
3
+ "version": "0.16.2",
4
4
  "type": "module",
5
5
  "description": "Core database functionality for Optimystic",
6
6
  "main": "dist/src/index.js",
@@ -17,8 +17,8 @@
17
17
  "import": "./dist/src/index.js"
18
18
  },
19
19
  "./test": {
20
- "types": "./dist/test/test-transactor.d.ts",
21
- "import": "./dist/test/test-transactor.js"
20
+ "types": "./dist/src/testing/index.d.ts",
21
+ "import": "./dist/src/testing/index.js"
22
22
  }
23
23
  },
24
24
  "repository": {
@@ -68,6 +68,6 @@
68
68
  "@noble/hashes": "^2.0.1",
69
69
  "debug": "^4.4.3",
70
70
  "multiformats": "^13.4.2",
71
- "uint8arrays": "^5.1.0"
71
+ "uint8arrays": "^6.1.1"
72
72
  }
73
73
  }
@@ -1,8 +1,26 @@
1
1
  import type { BlockType, IBlock, BlockId, BlockHeader, BlockOperation } from "./index.js";
2
2
 
3
+ /** Why a block was read, used to filter the optimistic-concurrency conflict (read) set.
4
+ *
5
+ * - `value` — the transaction's result depends on this block's CONTENT (a leaf/entry, a log
6
+ * entry, or an interior node whose keys/counts were used as data). Always retained.
7
+ * - `navigation` — an interior structural block (a B-tree branch) walked through ONLY to reach
8
+ * a separately-captured `value` read further down the same descent. May be dropped from the
9
+ * conflict set, because any concurrent restructuring that would change the queried result also
10
+ * bumps the revision of a `value` block that stays in the set (the target leaf). See
11
+ * docs/correctness.md Theorem 5.
12
+ *
13
+ * Defaults to `value` EVERYWHERE a read is captured, so an unclassified read is always retained
14
+ * (fail-safe): a forgotten tag can only cause an extra false-positive rejection, never a missed
15
+ * conflict. Only the B-tree point-lookup descent opts specific interior reads into `navigation`. */
16
+ export type ReadPurpose = 'value' | 'navigation';
17
+
3
18
  export type BlockSource<T extends IBlock> = {
4
19
  createBlockHeader(type: BlockType, newId?: BlockId): BlockHeader;
5
- tryGet(id: BlockId): Promise<T | undefined>;
20
+ /** Fetch a block by id. `purpose` classifies WHY the block is being read for OCC read-set
21
+ * filtering (see {@link ReadPurpose}); it defaults to `value`, so existing callers that omit
22
+ * it capture a retained read exactly as before. */
23
+ tryGet(id: BlockId, purpose?: ReadPurpose): Promise<T | undefined>;
6
24
  generateId(): BlockId;
7
25
  };
8
26
 
@@ -1,8 +1,8 @@
1
- import type { BlockOperation, IBlock, BlockId, BlockStore } from "../index.js";
1
+ import type { BlockOperation, IBlock, BlockId, BlockStore, ReadPurpose } from "../index.js";
2
2
  import { applyOperation } from "../transform/helpers.js";
3
3
 
4
- export async function get<T extends IBlock>(store: BlockStore<T>, id: BlockId): Promise<T> {
5
- const block = await store.tryGet(id);
4
+ export async function get<T extends IBlock>(store: BlockStore<T>, id: BlockId, purpose?: ReadPurpose): Promise<T> {
5
+ const block = await store.tryGet(id, purpose);
6
6
  if (!block) throw Error(`Missing block (${id})`);
7
7
  return block;
8
8
  }
@@ -4,7 +4,7 @@ import { apply, get } from "../blocks/index.js";
4
4
  import { TreeLeafBlockType, TreeBranchBlockType, entries$, nodes$, partitions$ } from "./nodes.js";
5
5
  import type { BranchNode, ITreeNode, LeafNode } from "./nodes.js";
6
6
  import type { TreeBlock } from "./tree-block.js";
7
- import { AtomicProxy } from "../transform/atomic-proxy.js";
7
+ import { AtomicProxy, type AtomicScope } from "../transform/atomic-proxy.js";
8
8
 
9
9
  export const NodeCapacity = 64;
10
10
 
@@ -27,11 +27,12 @@ export class BTree<TKey, TEntry> {
27
27
  public readonly trunk: ITreeTrunk,
28
28
  public readonly keyFromEntry = (entry: TEntry) => entry as unknown as TKey,
29
29
  public readonly compare = (a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0 as number,
30
+ public readonly nodeCapacity = NodeCapacity,
30
31
  ) {
31
32
  }
32
33
 
33
- private atomic<T>(fn: () => Promise<T>): Promise<T> {
34
- return this._proxy ? this._proxy.atomic(fn) : fn();
34
+ private atomic<T>(fn: (scope?: AtomicScope) => Promise<T>, parent?: AtomicScope): Promise<T> {
35
+ return this._proxy ? this._proxy.atomic(fn, parent) : fn(parent);
35
36
  }
36
37
 
37
38
  static createRoot(
@@ -45,13 +46,14 @@ export class BTree<TKey, TEntry> {
45
46
  createTrunk: getTrunkFunc,
46
47
  keyFromEntry = (entry: TEntry) => entry as unknown as TKey,
47
48
  compare = (a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0,
49
+ nodeCapacity = NodeCapacity,
48
50
  newId?: BlockId,
49
51
  ) {
50
52
  const proxy = new AtomicProxy(store);
51
53
  const root = BTree.createRoot(proxy as BlockStore<TreeBlock>);
52
54
  proxy.insert(root);
53
55
  const trunk = createTrunk(proxy as BlockStore<TreeBlock>, root.header.id, newId);
54
- const tree = new BTree(proxy, trunk, keyFromEntry, compare);
56
+ const tree = new BTree(proxy, trunk, keyFromEntry, compare, nodeCapacity);
55
57
  tree._proxy = proxy;
56
58
  return tree;
57
59
  }
@@ -68,16 +70,24 @@ export class BTree<TKey, TEntry> {
68
70
 
69
71
  /** Attempts to find the given key
70
72
  * @returns Path to the key or the "crack" before it. If `on` is true on the resulting path, the key was found.
71
- * If `on` is false, next() and prior() can attempt to move to the nearest match. */
72
- async find(key: TKey): Promise<Path<TKey, TEntry>> {
73
- return await this.getPath(await this.trunk.get(), key);
73
+ * If `on` is false, next() and prior() can attempt to move to the nearest match.
74
+ * @param navigate when true, the interior descent nodes are captured as droppable `navigation`
75
+ * reads (see {@link getPath}). DEFAULT false: `find` returns a Path a caller may use to seed a
76
+ * range scan (`ascending`/`next`), whose result depends on tree shape, so its structural reads
77
+ * must stay retained. Only {@link get} — a point lookup with no such escape — opts in. */
78
+ async find(key: TKey, navigate = false): Promise<Path<TKey, TEntry>> {
79
+ return await this.getPath(await this.trunk.get(), key, navigate);
74
80
  }
75
81
 
76
82
  /** Retrieves the entry for the given key.
77
83
  * Use find instead for a path to the key, the nearest match, or as a basis for navigation.
78
84
  * @returns the entry for the given key if found; undefined otherwise. */
79
85
  async get(key: TKey): Promise<TEntry | undefined> {
80
- return this.at(await this.find(key));
86
+ // Value-of-key point lookup: the result depends ONLY on the terminal leaf's content, so the
87
+ // interior descent nodes are pure navigation and are dropped from the OCC conflict set. The
88
+ // returned Path is consumed by `at` and discarded — it never seeds a scan — so navigate=true
89
+ // is safe here (unlike the public `find`).
90
+ return this.at(await this.find(key, /* navigate */ true));
81
91
  }
82
92
 
83
93
  /** @returns the entry for the given path if on an entry; undefined otherwise. */
@@ -122,6 +132,14 @@ export class BTree<TKey, TEntry> {
122
132
  return path.version === this._version;
123
133
  }
124
134
 
135
+ /** Bump the version so every Path handed out before now reports invalid (see {@link isValid}).
136
+ * Needed when the tree's data was mutated through a DIFFERENT store binding than this instance —
137
+ * e.g. the tree collection's action handler writes through a per-action Atomic store, so this
138
+ * read-side btree never sees the mutation and must be told to invalidate outstanding paths. */
139
+ invalidatePaths() {
140
+ ++this._version;
141
+ }
142
+
125
143
  /**
126
144
  * Adds a value to the tree. Be sure to check the result, as the tree does not allow duplicate keys.
127
145
  * Added entries are frozen to ensure immutability
@@ -145,7 +163,7 @@ export class BTree<TKey, TEntry> {
145
163
  * * on = false if update/insert failed.
146
164
  * * wasUpdate = true, given path is not on an entry
147
165
  * * else newEntry's new key already present; returned path is "near" existing entry */
148
- async updateAt(path: Path<TKey, TEntry>, newEntry: TEntry): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]> {
166
+ async updateAt(path: Path<TKey, TEntry>, newEntry: TEntry, parent?: AtomicScope): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]> {
149
167
  return this.atomic(async () => {
150
168
  this.validatePath(path);
151
169
  if (path.on) {
@@ -156,7 +174,7 @@ export class BTree<TKey, TEntry> {
156
174
  result[0].version = ++this._version;
157
175
  }
158
176
  return result;
159
- });
177
+ }, parent);
160
178
  }
161
179
 
162
180
  /** Inserts the entry if it doesn't exist, or updates it if it does.
@@ -182,11 +200,13 @@ export class BTree<TKey, TEntry> {
182
200
  * @returns path to new entry and whether an update or insert attempted.
183
201
  * If getUpdated callback returns a row that is already present, the resulting path will not be on. */
184
202
  async merge(newEntry: TEntry, getUpdated: (existing: TEntry) => TEntry): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]> {
185
- return this.atomic(async () => {
186
- const newKey = await this.keyFromEntry(newEntry);
203
+ return this.atomic(async (scope) => {
204
+ const newKey = this.keyFromEntry(newEntry);
187
205
  const path = await this.find(newKey);
188
206
  if (path.on) {
189
- const result = await this.updateAt(path, getUpdated(this.getEntry(path))); // Don't use internalUpdate - need to freeze and check for mutation
207
+ // Thread this scope into updateAt so the nested call joins this atomic batch
208
+ // (reuses the tracker) rather than opening/committing a second scope.
209
+ const result = await this.updateAt(path, getUpdated(this.getEntry(path)), scope); // Don't use internalUpdate - need to freeze and check for mutation
190
210
  // Note: updateAt already increments version, so don't double-increment here
191
211
  return result;
192
212
  } else {
@@ -277,7 +297,7 @@ export class BTree<TKey, TEntry> {
277
297
  /** @returns a path one step backward. on will be true if the path hasn't hit the end. */
278
298
  async prior(path: Path<TKey, TEntry>): Promise<Path<TKey, TEntry>> {
279
299
  const newPath = path.clone();
280
- this.movePrior(newPath);
300
+ await this.movePrior(newPath);
281
301
  return newPath;
282
302
  }
283
303
 
@@ -332,20 +352,40 @@ export class BTree<TKey, TEntry> {
332
352
  return endPath;
333
353
  }
334
354
 
335
- protected async getPath(node: ITreeNode, key: TKey): Promise<Path<TKey, TEntry>> {
355
+ /** Descend from `node` toward `key`, building the path. When `navigate` is true this is a point
356
+ * lookup (from {@link get}): each interior branch read below the root is captured as a droppable
357
+ * `navigation` read, and the terminal leaf is upgraded back to a retained `value` read — the
358
+ * result depends only on the leaf, and any concurrent restructuring that would change the result
359
+ * also bumps the leaf's revision (Theorem 5), so the interior reads are redundant. When false
360
+ * (find/range/scan/write descents) every read stays `value` (retained). */
361
+ protected async getPath(node: ITreeNode, key: TKey, navigate = false): Promise<Path<TKey, TEntry>> {
336
362
  if (node.header.type === TreeLeafBlockType) {
337
363
  const leaf = node as LeafNode<TEntry>;
364
+ if (navigate) {
365
+ // The leaf ends a point-lookup descent: its content is the load-bearing VALUE read.
366
+ // Its parent fetched it as `navigation` (a child's type is unknown before reading);
367
+ // upgrade it (value-wins) so it is retained while the interior nodes above are dropped.
368
+ this.markReadValue(leaf.header.id);
369
+ }
338
370
  const [on, index] = this.indexOfEntry(leaf.entries, key);
339
371
  return new Path<TKey, TEntry>([], leaf, index, on, this._version);
340
372
  } else {
341
373
  const branch = node as BranchNode<TKey>;
342
374
  const index = this.indexOfKey(branch.partitions, key);
343
- const path = await this.getPath(await get(this.store, branch.nodes[index]!), key);
375
+ const child = await get(this.store, branch.nodes[index]!, navigate ? 'navigation' : 'value');
376
+ const path = await this.getPath(child, key, navigate);
344
377
  path.branches.unshift(new PathBranch(branch, index));
345
378
  return path;
346
379
  }
347
380
  }
348
381
 
382
+ /** Upgrade a captured read of `id` to a retained `value` read via the store chain's read
383
+ * collector (duck-typed — a no-op for stores without one, e.g. test doubles or log-walk
384
+ * caches). Used by a point lookup to pin its terminal leaf. */
385
+ private markReadValue(id: BlockId) {
386
+ (this.store as { markReadValue?: (id: BlockId) => void }).markReadValue?.(id);
387
+ }
388
+
349
389
  private indexOfEntry(entries: TEntry[], key: TKey): [on: boolean, index: number] {
350
390
  let lo = 0;
351
391
  let hi = entries.length - 1;
@@ -392,34 +432,35 @@ export class BTree<TKey, TEntry> {
392
432
  if (!path.on) { // Attempt to move off of crack
393
433
  path.on = path.branches.every(branch => branch.index >= 0 && branch.index < branch.node.nodes.length)
394
434
  && path.leafIndex >= 0 && path.leafIndex < path.leafNode.entries.length;
395
- if (path.on) {
396
- return;
397
- }
398
- } else if (path.leafIndex >= path.leafNode.entries.length - 1) {
399
- let popCount = 0;
400
- let found = false;
401
- const last = path.branches.length - 1;
402
- while (popCount <= last && !found) {
403
- const branch = path.branches[last - popCount]!;
404
- if (branch.index === branch.node.partitions.length) // last node in branch
405
- ++popCount;
406
- else
407
- found = true;
408
- }
409
-
410
- if (!found) {
411
- path.leafIndex = path.leafNode.entries.length; // after last row = end crack
412
- path.on = false;
413
- } else {
414
- path.branches.splice(-popCount, popCount);
415
- const branch = path.branches.at(-1)!;
416
- ++branch.index;
417
- this.moveToFirst(await get(this.store, branch.node.nodes[branch.index]!), path);
435
+ if (path.on || path.leafIndex < path.leafNode.entries.length) {
436
+ return; // got on an entry, or an interior crack — nothing to advance into
418
437
  }
419
- }
420
- else {
438
+ // end-of-leaf crack (leafIndex === entries.length): fall through to branch-popping leaf-advance
439
+ } else if (path.leafIndex < path.leafNode.entries.length - 1) {
421
440
  ++path.leafIndex;
422
441
  path.on = true;
442
+ return;
443
+ }
444
+ // on the last entry of the leaf, or off an end-of-leaf crack: advance into the next leaf
445
+ let popCount = 0;
446
+ let found = false;
447
+ const last = path.branches.length - 1;
448
+ while (popCount <= last && !found) {
449
+ const branch = path.branches[last - popCount]!;
450
+ if (branch.index === branch.node.partitions.length) // last node in branch
451
+ ++popCount;
452
+ else
453
+ found = true;
454
+ }
455
+
456
+ if (!found) {
457
+ path.leafIndex = path.leafNode.entries.length; // after last row = end crack
458
+ path.on = false;
459
+ } else {
460
+ path.branches.splice(-popCount, popCount);
461
+ const branch = path.branches.at(-1)!;
462
+ ++branch.index;
463
+ await this.moveToFirst(await get(this.store, branch.node.nodes[branch.index]!), path);
423
464
  }
424
465
  }
425
466
 
@@ -460,7 +501,7 @@ export class BTree<TKey, TEntry> {
460
501
  if (this.compare(oldKey, newKey) !== 0) { // if key changed, delete and re-insert
461
502
  let newPath = await this.internalInsert(newEntry)
462
503
  if (newPath.on) { // insert succeeded
463
- this.internalDelete(await this.find(oldKey)); // Re-find - the prior insert invalidated the path
504
+ await this.internalDelete(await this.find(oldKey)); // Re-find - the prior insert invalidated the path
464
505
  newPath = await this.find(newKey); // Re-find- delete invalidated path
465
506
  }
466
507
  return [newPath, false];
@@ -512,7 +553,7 @@ export class BTree<TKey, TEntry> {
512
553
  }
513
554
  if (split) {
514
555
  const newBranch = newBranchNode(this.store, [split.key], [await this.trunk.getId(), split.right.header.id]);
515
- await this.store.insert(newBranch);
556
+ this.store.insert(newBranch);
516
557
  await this.trunk.set(newBranch);
517
558
  path.branches.unshift(new PathBranch(newBranch, split.indexDelta));
518
559
  }
@@ -577,7 +618,7 @@ export class BTree<TKey, TEntry> {
577
618
 
578
619
  private leafInsert(path: Path<TKey, TEntry>, entry: TEntry): Split<TKey> | undefined {
579
620
  const { leafNode: leaf, leafIndex: index } = path;
580
- if (leaf.entries.length < NodeCapacity) { // No split needed
621
+ if (leaf.entries.length < this.nodeCapacity) { // No split needed
581
622
  apply(this.store, leaf, [entries$, index, 0, [entry]]);
582
623
  return undefined;
583
624
  }
@@ -610,7 +651,7 @@ export class BTree<TKey, TEntry> {
610
651
  const pathBranch = path.branches[branchIndex]!;
611
652
  const { index: splitIndex, node } = pathBranch;
612
653
  pathBranch.index += split.indexDelta;
613
- if (node.nodes.length < NodeCapacity) { // no split needed
654
+ if (node.nodes.length < this.nodeCapacity) { // no split needed
614
655
  apply(this.store, node, [partitions$, splitIndex, 0, [split.key]]);
615
656
  apply(this.store, node, [nodes$, splitIndex + 1, 0, [split.right.header.id]]);
616
657
  return undefined;
@@ -629,6 +670,7 @@ export class BTree<TKey, TEntry> {
629
670
  newNodes.splice(pathBranch.index + 1, 0, split.right.header.id);
630
671
  }
631
672
  const newBranch = newBranchNode(this.store, newPartitions, newNodes);
673
+ this.store.insert(newBranch);
632
674
 
633
675
  // Delete partitions and nodes
634
676
  const newPartition = node.partitions[midIndex - 1]!;
@@ -644,7 +686,7 @@ export class BTree<TKey, TEntry> {
644
686
  }
645
687
 
646
688
  protected async rebalanceLeaf(path: Path<TKey, TEntry>, depth: number): Promise<ITreeNode | undefined> {
647
- if (depth === 0 || path.leafNode.entries.length >= (NodeCapacity >>> 1)) {
689
+ if (depth === 0 || path.leafNode.entries.length >= (this.nodeCapacity >>> 1)) {
648
690
  return undefined;
649
691
  }
650
692
 
@@ -653,19 +695,19 @@ export class BTree<TKey, TEntry> {
653
695
  const pIndex = parent.index;
654
696
  const pNode = parent.node;
655
697
 
656
- const rightSibId = pNode.nodes[pIndex + 1]!;
698
+ const rightSibId = pNode.nodes[pIndex + 1];
657
699
  const rightSib = rightSibId ? (await get(this.store, rightSibId)) as LeafNode<TEntry> : undefined;
658
- if (rightSib && rightSib.entries.length > (NodeCapacity >>> 1)) { // Attempt to borrow from right sibling
700
+ if (rightSib && rightSib.entries.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from right sibling
659
701
  const entry = rightSib.entries[0]!;
660
702
  apply(this.store, rightSib, [entries$, 0, 1, []]);
661
703
  apply(this.store, leaf, [entries$, leaf.entries.length, 0, [entry]]);
662
- this.updatePartition(pIndex + 1, path, depth - 1, this.keyFromEntry(entry));
704
+ this.updatePartition(pIndex + 1, path, depth - 1, this.keyFromEntry(rightSib.entries[0]!));
663
705
  return undefined;
664
706
  }
665
707
 
666
- const leftSibId = pNode.nodes[pIndex - 1]!;
708
+ const leftSibId = pNode.nodes[pIndex - 1];
667
709
  const leftSib = leftSibId ? (await get(this.store, leftSibId)) as LeafNode<TEntry> : undefined;
668
- if (leftSib && leftSib.entries.length > (NodeCapacity >>> 1)) { // Attempt to borrow from left sibling
710
+ if (leftSib && leftSib.entries.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from left sibling
669
711
  const entry = leftSib.entries[leftSib.entries.length - 1]!;
670
712
  apply(this.store, leftSib, [entries$, leftSib.entries.length - 1, 1, []]);
671
713
  apply(this.store, leaf, [entries$, 0, 0, [entry]]);
@@ -674,7 +716,7 @@ export class BTree<TKey, TEntry> {
674
716
  return undefined;
675
717
  }
676
718
 
677
- if (rightSib && rightSib.entries.length + leaf.entries.length <= NodeCapacity) { // Attempt to merge right sibling into leaf (right sib deleted)
719
+ if (rightSib && rightSib.entries.length + leaf.entries.length <= this.nodeCapacity) { // Attempt to merge right sibling into leaf (right sib deleted)
678
720
  apply(this.store, leaf, [entries$, leaf.entries.length, 0, rightSib.entries]);
679
721
  this.deletePartition(pNode, pIndex);
680
722
  if (pIndex === 0) { // 0th node of parent, update parent key
@@ -684,7 +726,12 @@ export class BTree<TKey, TEntry> {
684
726
  return await this.rebalanceBranch(path, depth - 1);
685
727
  }
686
728
 
687
- if (leftSib && leftSib.entries.length + leaf.entries.length <= NodeCapacity) { // Attempt to merge into left sibling (leaf deleted)
729
+ if (leftSib && leftSib.entries.length + leaf.entries.length <= this.nodeCapacity) { // Attempt to merge into left sibling (leaf deleted)
730
+ // NOTE: this fixes leafIndex, but the parent-branch index up the path is left pointing at
731
+ // the now-deleted leaf's old slot (same tolerated-staleness class as rebalanceBranch's
732
+ // left-merge, part c). Harmless today because deleteAt version-bumps and abandons the
733
+ // returned path. A future path-reuse consumer must audit BOTH left-merge sites, not just
734
+ // rebalanceBranch.
688
735
  path.leafNode = leftSib;
689
736
  path.leafIndex += leftSib.entries.length;
690
737
  apply(this.store, leftSib, [entries$, leftSib.entries.length, 0, leaf.entries]);
@@ -701,7 +748,7 @@ export class BTree<TKey, TEntry> {
701
748
  return path.branches[depth + 1]?.node ?? path.leafNode;
702
749
  }
703
750
 
704
- if (depth === 0 || (branch.nodes.length >= NodeCapacity >>> 1)) {
751
+ if (depth === 0 || (branch.nodes.length >= this.nodeCapacity >>> 1)) {
705
752
  return undefined;
706
753
  }
707
754
 
@@ -709,9 +756,9 @@ export class BTree<TKey, TEntry> {
709
756
  const pIndex = parent.index;
710
757
  const pNode = parent.node;
711
758
 
712
- const rightSibId = pNode.nodes[pIndex + 1]!;
759
+ const rightSibId = pNode.nodes[pIndex + 1];
713
760
  const rightSib = rightSibId ? (await get(this.store, rightSibId)) as BranchNode<TKey> : undefined;
714
- if (rightSib && rightSib.nodes.length > (NodeCapacity >>> 1)) { // Attempt to borrow from right sibling
761
+ if (rightSib && rightSib.nodes.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from right sibling
715
762
  const node = rightSib.nodes[0]!;
716
763
  const rightKey = rightSib.partitions[0]!;
717
764
  this.insertPartition(branch, branch.partitions.length, pNode.partitions[pIndex]!, node);
@@ -722,7 +769,7 @@ export class BTree<TKey, TEntry> {
722
769
 
723
770
  const leftSibId = pNode.nodes[pIndex - 1];
724
771
  const leftSib = leftSibId ? (await get(this.store, leftSibId)) as BranchNode<TKey> : undefined;
725
- if (leftSib && leftSib.nodes.length > (NodeCapacity >>> 1)) { // Attempt to borrow from left sibling
772
+ if (leftSib && leftSib.nodes.length > (this.nodeCapacity >>> 1)) { // Attempt to borrow from left sibling
726
773
  const node = leftSib.nodes[leftSib.nodes.length - 1]!;
727
774
  const pKey = leftSib.partitions[leftSib.partitions.length - 1]!;
728
775
  this.insertPartition(branch, 0, pNode.partitions[pIndex - 1]!, node, 0);
@@ -732,27 +779,25 @@ export class BTree<TKey, TEntry> {
732
779
  return undefined;
733
780
  }
734
781
 
735
- if (rightSib && rightSib.nodes.length + branch.nodes.length <= NodeCapacity) { // Attempt to merge right sibling into self
782
+ if (rightSib && rightSib.nodes.length + branch.nodes.length <= this.nodeCapacity) { // Attempt to merge right sibling into self
736
783
  const pKey = pNode.partitions[pIndex]!;
737
784
  this.deletePartition(pNode, pIndex);
738
785
  apply(this.store, branch, [partitions$, branch.partitions.length, 0, [pKey]]);
739
786
  apply(this.store, branch, [partitions$, branch.partitions.length, 0, rightSib.partitions]);
740
787
  apply(this.store, branch, [nodes$, branch.nodes.length, 0, rightSib.nodes]);
741
- if (pIndex === 0 && pNode.partitions.length > 0) { // if parent is left edge, new right sibling is now the first partition
742
- this.updatePartition(pIndex, path, depth - 1, pNode.partitions[0]!);
743
- }
744
788
  this.store.delete(rightSib.header.id);
745
789
  return this.rebalanceBranch(path, depth - 1);
746
790
  }
747
791
 
748
- if (leftSib && leftSib.nodes.length + branch.nodes.length <= NodeCapacity) { // Attempt to merge self into left sibling
792
+ if (leftSib && leftSib.nodes.length + branch.nodes.length <= this.nodeCapacity) { // Attempt to merge self into left sibling
793
+ const leftLen = leftSib.nodes.length; // capture BEFORE the appends below shift it (see leaf path at rebalanceLeaf)
749
794
  const pKey = pNode.partitions[pIndex - 1]!;
750
795
  this.deletePartition(pNode, pIndex - 1);
751
796
  apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, [pKey]]);
752
797
  apply(this.store, leftSib, [partitions$, leftSib.partitions.length, 0, branch.partitions]);
753
798
  apply(this.store, leftSib, [nodes$, leftSib.nodes.length, 0, branch.nodes]);
754
799
  pathBranch.node = leftSib;
755
- pathBranch.index += leftSib.nodes.length;
800
+ pathBranch.index += leftLen; // branch's children now sit after leftSib's original children
756
801
  this.store.delete(branch.header.id);
757
802
  return this.rebalanceBranch(path, depth - 1);
758
803
  }