@optimystic/db-p2p 0.13.5 → 0.14.0

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 (342) hide show
  1. package/README.md +6 -6
  2. package/dist/src/cluster/block-transfer-service.d.ts +67 -8
  3. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  4. package/dist/src/cluster/block-transfer-service.js +101 -62
  5. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  6. package/dist/src/cluster/client.d.ts +18 -1
  7. package/dist/src/cluster/client.d.ts.map +1 -1
  8. package/dist/src/cluster/client.js +55 -39
  9. package/dist/src/cluster/client.js.map +1 -1
  10. package/dist/src/cluster/cluster-error.d.ts +38 -0
  11. package/dist/src/cluster/cluster-error.d.ts.map +1 -0
  12. package/dist/src/cluster/cluster-error.js +51 -0
  13. package/dist/src/cluster/cluster-error.js.map +1 -0
  14. package/dist/src/cluster/cluster-repo.d.ts +135 -3
  15. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  16. package/dist/src/cluster/cluster-repo.js +333 -58
  17. package/dist/src/cluster/cluster-repo.js.map +1 -1
  18. package/dist/src/cluster/commit-cert.d.ts +63 -0
  19. package/dist/src/cluster/commit-cert.d.ts.map +1 -0
  20. package/dist/src/cluster/commit-cert.js +108 -0
  21. package/dist/src/cluster/commit-cert.js.map +1 -0
  22. package/dist/src/cluster/service.d.ts +46 -11
  23. package/dist/src/cluster/service.d.ts.map +1 -1
  24. package/dist/src/cluster/service.js +97 -33
  25. package/dist/src/cluster/service.js.map +1 -1
  26. package/dist/src/cluster/spread-on-churn.d.ts +13 -0
  27. package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
  28. package/dist/src/cluster/spread-on-churn.js +34 -4
  29. package/dist/src/cluster/spread-on-churn.js.map +1 -1
  30. package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts +59 -0
  31. package/dist/src/cohort-topic/bootstrap-evidence-builder.d.ts.map +1 -0
  32. package/dist/src/cohort-topic/bootstrap-evidence-builder.js +79 -0
  33. package/dist/src/cohort-topic/bootstrap-evidence-builder.js.map +1 -0
  34. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts +81 -0
  35. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.d.ts.map +1 -0
  36. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js +93 -0
  37. package/dist/src/cohort-topic/bootstrap-evidence-verifiers.js.map +1 -0
  38. package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts +108 -0
  39. package/dist/src/cohort-topic/bootstrap-parent-reference.d.ts.map +1 -0
  40. package/dist/src/cohort-topic/bootstrap-parent-reference.js +108 -0
  41. package/dist/src/cohort-topic/bootstrap-parent-reference.js.map +1 -0
  42. package/dist/src/cohort-topic/change-bridge.d.ts +65 -0
  43. package/dist/src/cohort-topic/change-bridge.d.ts.map +1 -0
  44. package/dist/src/cohort-topic/change-bridge.js +76 -0
  45. package/dist/src/cohort-topic/change-bridge.js.map +1 -0
  46. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts +74 -0
  47. package/dist/src/cohort-topic/cohort-gossip-driver.d.ts.map +1 -0
  48. package/dist/src/cohort-topic/cohort-gossip-driver.js +87 -0
  49. package/dist/src/cohort-topic/cohort-gossip-driver.js.map +1 -0
  50. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts +42 -0
  51. package/dist/src/cohort-topic/cohort-gossip-transport.d.ts.map +1 -0
  52. package/dist/src/cohort-topic/cohort-gossip-transport.js +57 -0
  53. package/dist/src/cohort-topic/cohort-gossip-transport.js.map +1 -0
  54. package/dist/src/cohort-topic/fret-trust-anchor.d.ts +100 -0
  55. package/dist/src/cohort-topic/fret-trust-anchor.d.ts.map +1 -0
  56. package/dist/src/cohort-topic/fret-trust-anchor.js +115 -0
  57. package/dist/src/cohort-topic/fret-trust-anchor.js.map +1 -0
  58. package/dist/src/cohort-topic/host.d.ts +573 -0
  59. package/dist/src/cohort-topic/host.d.ts.map +1 -0
  60. package/dist/src/cohort-topic/host.js +1460 -0
  61. package/dist/src/cohort-topic/host.js.map +1 -0
  62. package/dist/src/cohort-topic/index.d.ts +14 -0
  63. package/dist/src/cohort-topic/index.d.ts.map +1 -0
  64. package/dist/src/cohort-topic/index.js +14 -0
  65. package/dist/src/cohort-topic/index.js.map +1 -0
  66. package/dist/src/cohort-topic/membership-publish-sink.d.ts +14 -0
  67. package/dist/src/cohort-topic/membership-publish-sink.d.ts.map +1 -0
  68. package/dist/src/cohort-topic/membership-publish-sink.js +17 -0
  69. package/dist/src/cohort-topic/membership-publish-sink.js.map +1 -0
  70. package/dist/src/cohort-topic/membership-source.d.ts +36 -0
  71. package/dist/src/cohort-topic/membership-source.d.ts.map +1 -0
  72. package/dist/src/cohort-topic/membership-source.js +58 -0
  73. package/dist/src/cohort-topic/membership-source.js.map +1 -0
  74. package/dist/src/cohort-topic/peer-codec.d.ts +18 -0
  75. package/dist/src/cohort-topic/peer-codec.d.ts.map +1 -0
  76. package/dist/src/cohort-topic/peer-codec.js +26 -0
  77. package/dist/src/cohort-topic/peer-codec.js.map +1 -0
  78. package/dist/src/cohort-topic/peer-sig.d.ts +52 -0
  79. package/dist/src/cohort-topic/peer-sig.d.ts.map +1 -0
  80. package/dist/src/cohort-topic/peer-sig.js +83 -0
  81. package/dist/src/cohort-topic/peer-sig.js.map +1 -0
  82. package/dist/src/cohort-topic/protocols.d.ts +49 -0
  83. package/dist/src/cohort-topic/protocols.d.ts.map +1 -0
  84. package/dist/src/cohort-topic/protocols.js +58 -0
  85. package/dist/src/cohort-topic/protocols.js.map +1 -0
  86. package/dist/src/cohort-topic/reactivity-membership-gate.d.ts +49 -0
  87. package/dist/src/cohort-topic/reactivity-membership-gate.d.ts.map +1 -0
  88. package/dist/src/cohort-topic/reactivity-membership-gate.js +42 -0
  89. package/dist/src/cohort-topic/reactivity-membership-gate.js.map +1 -0
  90. package/dist/src/cohort-topic/size-estimator.d.ts +16 -0
  91. package/dist/src/cohort-topic/size-estimator.d.ts.map +1 -0
  92. package/dist/src/cohort-topic/size-estimator.js +16 -0
  93. package/dist/src/cohort-topic/size-estimator.js.map +1 -0
  94. package/dist/src/cohort-topic/stream-util.d.ts +19 -0
  95. package/dist/src/cohort-topic/stream-util.d.ts.map +1 -0
  96. package/dist/src/cohort-topic/stream-util.js +76 -0
  97. package/dist/src/cohort-topic/stream-util.js.map +1 -0
  98. package/dist/src/cohort-topic/threshold-crypto.d.ts +94 -0
  99. package/dist/src/cohort-topic/threshold-crypto.d.ts.map +1 -0
  100. package/dist/src/cohort-topic/threshold-crypto.js +178 -0
  101. package/dist/src/cohort-topic/threshold-crypto.js.map +1 -0
  102. package/dist/src/cohort-topic/topic-router.d.ts +41 -0
  103. package/dist/src/cohort-topic/topic-router.d.ts.map +1 -0
  104. package/dist/src/cohort-topic/topic-router.js +63 -0
  105. package/dist/src/cohort-topic/topic-router.js.map +1 -0
  106. package/dist/src/dispute/cascade.d.ts +179 -0
  107. package/dist/src/dispute/cascade.d.ts.map +1 -0
  108. package/dist/src/dispute/cascade.js +315 -0
  109. package/dist/src/dispute/cascade.js.map +1 -0
  110. package/dist/src/dispute/client.d.ts +2 -1
  111. package/dist/src/dispute/client.d.ts.map +1 -1
  112. package/dist/src/dispute/client.js +12 -3
  113. package/dist/src/dispute/client.js.map +1 -1
  114. package/dist/src/dispute/dispute-service.d.ts +41 -1
  115. package/dist/src/dispute/dispute-service.d.ts.map +1 -1
  116. package/dist/src/dispute/dispute-service.js +147 -21
  117. package/dist/src/dispute/dispute-service.js.map +1 -1
  118. package/dist/src/dispute/index.d.ts +2 -0
  119. package/dist/src/dispute/index.d.ts.map +1 -1
  120. package/dist/src/dispute/index.js +2 -0
  121. package/dist/src/dispute/index.js.map +1 -1
  122. package/dist/src/dispute/invalidation.d.ts +266 -0
  123. package/dist/src/dispute/invalidation.d.ts.map +1 -0
  124. package/dist/src/dispute/invalidation.js +405 -0
  125. package/dist/src/dispute/invalidation.js.map +1 -0
  126. package/dist/src/dispute/types.d.ts +14 -0
  127. package/dist/src/dispute/types.d.ts.map +1 -1
  128. package/dist/src/dispute/types.js.map +1 -1
  129. package/dist/src/index.d.ts +4 -0
  130. package/dist/src/index.d.ts.map +1 -1
  131. package/dist/src/index.js +4 -0
  132. package/dist/src/index.js.map +1 -1
  133. package/dist/src/libp2p-key-network.d.ts +7 -0
  134. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  135. package/dist/src/libp2p-key-network.js +49 -5
  136. package/dist/src/libp2p-key-network.js.map +1 -1
  137. package/dist/src/libp2p-node-base.d.ts +45 -3
  138. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  139. package/dist/src/libp2p-node-base.js +522 -5
  140. package/dist/src/libp2p-node-base.js.map +1 -1
  141. package/dist/src/matchmaking/aggregate-counts.d.ts +67 -0
  142. package/dist/src/matchmaking/aggregate-counts.d.ts.map +1 -0
  143. package/dist/src/matchmaking/aggregate-counts.js +60 -0
  144. package/dist/src/matchmaking/aggregate-counts.js.map +1 -0
  145. package/dist/src/matchmaking/index.d.ts +20 -0
  146. package/dist/src/matchmaking/index.d.ts.map +1 -0
  147. package/dist/src/matchmaking/index.js +20 -0
  148. package/dist/src/matchmaking/index.js.map +1 -0
  149. package/dist/src/matchmaking/module.d.ts +181 -0
  150. package/dist/src/matchmaking/module.d.ts.map +1 -0
  151. package/dist/src/matchmaking/module.js +221 -0
  152. package/dist/src/matchmaking/module.js.map +1 -0
  153. package/dist/src/matchmaking/protocols.d.ts +37 -0
  154. package/dist/src/matchmaking/protocols.d.ts.map +1 -0
  155. package/dist/src/matchmaking/protocols.js +42 -0
  156. package/dist/src/matchmaking/protocols.js.map +1 -0
  157. package/dist/src/matchmaking/provider-manager.d.ts +52 -0
  158. package/dist/src/matchmaking/provider-manager.d.ts.map +1 -0
  159. package/dist/src/matchmaking/provider-manager.js +74 -0
  160. package/dist/src/matchmaking/provider-manager.js.map +1 -0
  161. package/dist/src/matchmaking/query-handler.d.ts +34 -0
  162. package/dist/src/matchmaking/query-handler.d.ts.map +1 -0
  163. package/dist/src/matchmaking/query-handler.js +62 -0
  164. package/dist/src/matchmaking/query-handler.js.map +1 -0
  165. package/dist/src/matchmaking/query-transport.d.ts +180 -0
  166. package/dist/src/matchmaking/query-transport.d.ts.map +1 -0
  167. package/dist/src/matchmaking/query-transport.js +315 -0
  168. package/dist/src/matchmaking/query-transport.js.map +1 -0
  169. package/dist/src/matchmaking/seeker-manager.d.ts +39 -0
  170. package/dist/src/matchmaking/seeker-manager.d.ts.map +1 -0
  171. package/dist/src/matchmaking/seeker-manager.js +49 -0
  172. package/dist/src/matchmaking/seeker-manager.js.map +1 -0
  173. package/dist/src/matchmaking/seeker-walk-client.d.ts +127 -0
  174. package/dist/src/matchmaking/seeker-walk-client.d.ts.map +1 -0
  175. package/dist/src/matchmaking/seeker-walk-client.js +189 -0
  176. package/dist/src/matchmaking/seeker-walk-client.js.map +1 -0
  177. package/dist/src/matchmaking/traffic-validation.d.ts +128 -0
  178. package/dist/src/matchmaking/traffic-validation.d.ts.map +1 -0
  179. package/dist/src/matchmaking/traffic-validation.js +105 -0
  180. package/dist/src/matchmaking/traffic-validation.js.map +1 -0
  181. package/dist/src/network/network-manager-service.d.ts +4 -2
  182. package/dist/src/network/network-manager-service.d.ts.map +1 -1
  183. package/dist/src/network/network-manager-service.js +9 -3
  184. package/dist/src/network/network-manager-service.js.map +1 -1
  185. package/dist/src/protocol-client.d.ts +13 -0
  186. package/dist/src/protocol-client.d.ts.map +1 -1
  187. package/dist/src/protocol-client.js +74 -2
  188. package/dist/src/protocol-client.js.map +1 -1
  189. package/dist/src/reactivity/forwarder-host.d.ts +198 -0
  190. package/dist/src/reactivity/forwarder-host.d.ts.map +1 -0
  191. package/dist/src/reactivity/forwarder-host.js +355 -0
  192. package/dist/src/reactivity/forwarder-host.js.map +1 -0
  193. package/dist/src/reactivity/index.d.ts +19 -0
  194. package/dist/src/reactivity/index.d.ts.map +1 -0
  195. package/dist/src/reactivity/index.js +19 -0
  196. package/dist/src/reactivity/index.js.map +1 -0
  197. package/dist/src/reactivity/notify-transport.d.ts +70 -0
  198. package/dist/src/reactivity/notify-transport.d.ts.map +1 -0
  199. package/dist/src/reactivity/notify-transport.js +111 -0
  200. package/dist/src/reactivity/notify-transport.js.map +1 -0
  201. package/dist/src/reactivity/origination-manager.d.ts +110 -0
  202. package/dist/src/reactivity/origination-manager.d.ts.map +1 -0
  203. package/dist/src/reactivity/origination-manager.js +129 -0
  204. package/dist/src/reactivity/origination-manager.js.map +1 -0
  205. package/dist/src/reactivity/protocols.d.ts +43 -0
  206. package/dist/src/reactivity/protocols.d.ts.map +1 -0
  207. package/dist/src/reactivity/protocols.js +50 -0
  208. package/dist/src/reactivity/protocols.js.map +1 -0
  209. package/dist/src/reactivity/push-state-gossip.d.ts +132 -0
  210. package/dist/src/reactivity/push-state-gossip.d.ts.map +1 -0
  211. package/dist/src/reactivity/push-state-gossip.js +231 -0
  212. package/dist/src/reactivity/push-state-gossip.js.map +1 -0
  213. package/dist/src/reactivity/recover-transport.d.ts +167 -0
  214. package/dist/src/reactivity/recover-transport.d.ts.map +1 -0
  215. package/dist/src/reactivity/recover-transport.js +308 -0
  216. package/dist/src/reactivity/recover-transport.js.map +1 -0
  217. package/dist/src/reactivity/rotation-rereg-scheduler.d.ts +142 -0
  218. package/dist/src/reactivity/rotation-rereg-scheduler.d.ts.map +1 -0
  219. package/dist/src/reactivity/rotation-rereg-scheduler.js +223 -0
  220. package/dist/src/reactivity/rotation-rereg-scheduler.js.map +1 -0
  221. package/dist/src/reactivity/subscriber-registry.d.ts +47 -0
  222. package/dist/src/reactivity/subscriber-registry.d.ts.map +1 -0
  223. package/dist/src/reactivity/subscriber-registry.js +87 -0
  224. package/dist/src/reactivity/subscriber-registry.js.map +1 -0
  225. package/dist/src/reactivity/subscription-manager.d.ts +221 -0
  226. package/dist/src/reactivity/subscription-manager.d.ts.map +1 -0
  227. package/dist/src/reactivity/subscription-manager.js +302 -0
  228. package/dist/src/reactivity/subscription-manager.js.map +1 -0
  229. package/dist/src/reactivity/topic-bytes.d.ts +32 -0
  230. package/dist/src/reactivity/topic-bytes.d.ts.map +1 -0
  231. package/dist/src/reactivity/topic-bytes.js +34 -0
  232. package/dist/src/reactivity/topic-bytes.js.map +1 -0
  233. package/dist/src/repo/client.d.ts.map +1 -1
  234. package/dist/src/repo/client.js +51 -23
  235. package/dist/src/repo/client.js.map +1 -1
  236. package/dist/src/repo/service.d.ts +46 -1
  237. package/dist/src/repo/service.d.ts.map +1 -1
  238. package/dist/src/repo/service.js +79 -45
  239. package/dist/src/repo/service.js.map +1 -1
  240. package/dist/src/rpc-deadline.d.ts +37 -0
  241. package/dist/src/rpc-deadline.d.ts.map +1 -0
  242. package/dist/src/rpc-deadline.js +31 -0
  243. package/dist/src/rpc-deadline.js.map +1 -0
  244. package/dist/src/storage/block-storage.d.ts +2 -0
  245. package/dist/src/storage/block-storage.d.ts.map +1 -1
  246. package/dist/src/storage/block-storage.js +95 -2
  247. package/dist/src/storage/block-storage.js.map +1 -1
  248. package/dist/src/storage/i-block-storage.d.ts +25 -0
  249. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  250. package/dist/src/storage/storage-repo.d.ts +53 -2
  251. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  252. package/dist/src/storage/storage-repo.js +193 -9
  253. package/dist/src/storage/storage-repo.js.map +1 -1
  254. package/dist/src/sync/client.d.ts +4 -1
  255. package/dist/src/sync/client.d.ts.map +1 -1
  256. package/dist/src/sync/client.js +5 -2
  257. package/dist/src/sync/client.js.map +1 -1
  258. package/dist/src/testing/cohort-topic-mesh-harness.d.ts +219 -0
  259. package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -0
  260. package/dist/src/testing/cohort-topic-mesh-harness.js +467 -0
  261. package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -0
  262. package/dist/src/testing/matchmaking-mesh-harness.d.ts +187 -0
  263. package/dist/src/testing/matchmaking-mesh-harness.d.ts.map +1 -0
  264. package/dist/src/testing/matchmaking-mesh-harness.js +358 -0
  265. package/dist/src/testing/matchmaking-mesh-harness.js.map +1 -0
  266. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  267. package/dist/src/testing/mesh-harness.js +23 -1
  268. package/dist/src/testing/mesh-harness.js.map +1 -1
  269. package/dist/src/testing/reactivity-mesh-harness.d.ts +298 -0
  270. package/dist/src/testing/reactivity-mesh-harness.d.ts.map +1 -0
  271. package/dist/src/testing/reactivity-mesh-harness.js +663 -0
  272. package/dist/src/testing/reactivity-mesh-harness.js.map +1 -0
  273. package/package.json +7 -4
  274. package/src/cluster/block-transfer-service.ts +133 -68
  275. package/src/cluster/client.ts +64 -45
  276. package/src/cluster/cluster-error.ts +64 -0
  277. package/src/cluster/cluster-repo.ts +405 -55
  278. package/src/cluster/commit-cert.ts +139 -0
  279. package/src/cluster/service.ts +116 -44
  280. package/src/cluster/spread-on-churn.ts +328 -285
  281. package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -0
  282. package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -0
  283. package/src/cohort-topic/bootstrap-parent-reference.ts +159 -0
  284. package/src/cohort-topic/change-bridge.ts +109 -0
  285. package/src/cohort-topic/cohort-gossip-driver.ts +144 -0
  286. package/src/cohort-topic/cohort-gossip-transport.ts +74 -0
  287. package/src/cohort-topic/fret-trust-anchor.ts +153 -0
  288. package/src/cohort-topic/host.ts +2175 -0
  289. package/src/cohort-topic/index.ts +13 -0
  290. package/src/cohort-topic/membership-publish-sink.ts +20 -0
  291. package/src/cohort-topic/membership-source.ts +68 -0
  292. package/src/cohort-topic/peer-codec.ts +31 -0
  293. package/src/cohort-topic/peer-sig.ts +86 -0
  294. package/src/cohort-topic/protocols.ts +71 -0
  295. package/src/cohort-topic/reactivity-membership-gate.ts +77 -0
  296. package/src/cohort-topic/size-estimator.ts +16 -0
  297. package/src/cohort-topic/stream-util.ts +87 -0
  298. package/src/cohort-topic/threshold-crypto.ts +239 -0
  299. package/src/cohort-topic/topic-router.ts +77 -0
  300. package/src/dispute/cascade.ts +517 -0
  301. package/src/dispute/client.ts +12 -2
  302. package/src/dispute/dispute-service.ts +171 -24
  303. package/src/dispute/index.ts +42 -0
  304. package/src/dispute/invalidation.ts +587 -0
  305. package/src/dispute/types.ts +14 -0
  306. package/src/index.ts +4 -0
  307. package/src/libp2p-key-network.ts +49 -6
  308. package/src/libp2p-node-base.ts +620 -12
  309. package/src/matchmaking/aggregate-counts.ts +104 -0
  310. package/src/matchmaking/index.ts +20 -0
  311. package/src/matchmaking/module.ts +363 -0
  312. package/src/matchmaking/protocols.ts +51 -0
  313. package/src/matchmaking/provider-manager.ts +95 -0
  314. package/src/matchmaking/query-handler.ts +88 -0
  315. package/src/matchmaking/query-transport.ts +483 -0
  316. package/src/matchmaking/seeker-manager.ts +64 -0
  317. package/src/matchmaking/seeker-walk-client.ts +293 -0
  318. package/src/matchmaking/traffic-validation.ts +195 -0
  319. package/src/network/network-manager-service.ts +9 -2
  320. package/src/protocol-client.ts +64 -3
  321. package/src/reactivity/forwarder-host.ts +438 -0
  322. package/src/reactivity/index.ts +19 -0
  323. package/src/reactivity/notify-transport.ts +144 -0
  324. package/src/reactivity/origination-manager.ts +192 -0
  325. package/src/reactivity/protocols.ts +61 -0
  326. package/src/reactivity/push-state-gossip.ts +291 -0
  327. package/src/reactivity/recover-transport.ts +408 -0
  328. package/src/reactivity/rotation-rereg-scheduler.ts +256 -0
  329. package/src/reactivity/subscriber-registry.ts +96 -0
  330. package/src/reactivity/subscription-manager.ts +450 -0
  331. package/src/reactivity/topic-bytes.ts +37 -0
  332. package/src/repo/client.ts +54 -23
  333. package/src/repo/service.ts +90 -42
  334. package/src/rpc-deadline.ts +45 -0
  335. package/src/storage/block-storage.ts +106 -3
  336. package/src/storage/i-block-storage.ts +27 -0
  337. package/src/storage/storage-repo.ts +209 -13
  338. package/src/sync/client.ts +5 -2
  339. package/src/testing/cohort-topic-mesh-harness.ts +613 -0
  340. package/src/testing/matchmaking-mesh-harness.ts +475 -0
  341. package/src/testing/mesh-harness.ts +22 -2
  342. package/src/testing/reactivity-mesh-harness.ts +922 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Reactivity — subscription manager (db-p2p, wires to the cohort-topic substrate).
3
+ *
4
+ * Drives a subscriber's lifecycle against the participant-facing {@link CohortTopicService}: register at
5
+ * cohort-topic tier **T3 (luxury)** with the reactivity `appPayload`, renew to keep the registration
6
+ * alive within its TTL (Edge 60 s / Core 90 s), and withdraw by ceasing renewal — all the cohort-topic
7
+ * standard (`docs/reactivity.md` §Subscription). The reactivity-specific shape lives in db-core: the
8
+ * tail-anchored `topicId = H(tailId ‖ "reactivity")`, the {@link SubscribeAppPayloadV1}, and the
9
+ * subscriber-side verify/deliver path ({@link ReactivitySubscriber}).
10
+ *
11
+ * Inbound notifications are handed to {@link ReactivitySubscriptionManager.onNotification}, which runs
12
+ * the db-core delivery path (verify against the cached tail-cohort `MembershipCertV1` with one
13
+ * fetch-and-retry, revision-contiguity, gap → backfill seam, `(collectionId, revision)` dedupe, surface).
14
+ * The notification transport (the reactivity application protocol that delivers `NotificationV1` frames
15
+ * to a subscriber's primary) is the sibling tickets' concern; this manager owns attach + delivery logic.
16
+ */
17
+ import { Tier, reactivityTopicId, subscribeAppPayloadBytes, subscriberTtlForProfile, deltaMaxForProfile, createNotificationVerifier, createReactivitySubscriber, createBackfillRequester, createStickyCohortHintCache, createRejoinJitter, applyResumeReply, detectRotation, planReRegistration, bytesToB64url, } from "@optimystic/db-core";
18
+ import { RotationRedirectError } from "./recover-transport.js";
19
+ import { createLogger } from "../logger.js";
20
+ const log = createLogger("reactivity-subscription");
21
+ /** Wires one reactivity subscription to the cohort-topic substrate at tier T3. */
22
+ export class ReactivitySubscriptionManager {
23
+ service;
24
+ collectionId;
25
+ collectionIdB64;
26
+ tailIdAtAttach;
27
+ topicId;
28
+ ttlMs;
29
+ deltaMaxBytes;
30
+ lastKnownRev;
31
+ subscriber;
32
+ verifier;
33
+ options;
34
+ cohortHintCache;
35
+ clock;
36
+ tailIdAtAttachB64;
37
+ rejoinJitter;
38
+ /** Resolved ring coordinate signed into a {@link ResumeV1} (real coord, or the collectionId placeholder). */
39
+ subscriberCoord;
40
+ /** True iff {@link subscriberCoord} fell back to the collectionId placeholder (no real coord supplied). */
41
+ subscriberCoordIsFallback;
42
+ /** The successor tail a rotation has already been surfaced for, so the notice fires once per rotation. */
43
+ rotationHandledFor;
44
+ /** Memoized db-core backfill driver (built on first gap, once `this.subscriber` is assigned). */
45
+ backfillRequester;
46
+ handle;
47
+ constructor(options) {
48
+ this.options = options;
49
+ this.service = options.service;
50
+ this.collectionId = options.collectionId;
51
+ this.collectionIdB64 = bytesToB64url(options.collectionId);
52
+ this.tailIdAtAttach = options.tailIdAtAttach;
53
+ this.topicId = reactivityTopicId(options.tailIdAtAttach);
54
+ this.ttlMs = options.ttlMs ?? (options.profile !== undefined ? subscriberTtlForProfile(options.profile) : undefined) ?? DEFAULT_SUBSCRIBER_TTL_MS;
55
+ this.deltaMaxBytes = options.deltaMaxBytes ?? (options.profile !== undefined ? deltaMaxForProfile(options.profile) : DEFAULT_EDGE_SAFE_DELTA_MAX);
56
+ this.lastKnownRev = options.lastKnownRev ?? 0;
57
+ this.cohortHintCache = options.cohortHintCache ?? createStickyCohortHintCache();
58
+ this.clock = options.clock ?? (() => Date.now());
59
+ this.tailIdAtAttachB64 = bytesToB64url(options.tailIdAtAttach);
60
+ this.rejoinJitter = options.rejoinJitter ?? createRejoinJitter();
61
+ this.subscriberCoordIsFallback = options.subscriberCoord === undefined;
62
+ this.subscriberCoord = options.subscriberCoord ?? this.collectionIdB64;
63
+ // Verify against the tail cohort's membership cert (the verifier owns the one fetch-and-retry).
64
+ this.verifier = createNotificationVerifier({ verifier: this.service.verifier(), tier: Tier.T3 });
65
+ this.subscriber = createReactivitySubscriber({
66
+ collectionId: this.collectionIdB64,
67
+ verifier: this.verifier,
68
+ deliver: options.deliver,
69
+ // Bind the seam to a method so it resolves the (possibly transport-backed) driver lazily —
70
+ // `this.subscriber` is not yet assigned during this very call.
71
+ requestBackfill: (from, to) => this.onBackfillGap(from, to),
72
+ lastKnownRev: this.lastKnownRev,
73
+ });
74
+ }
75
+ /**
76
+ * The subscriber detected a revision gap. When a {@link ReactivitySubscriptionManagerOptions.backfillTransport}
77
+ * + signer are configured, drive the db-core {@link createBackfillRequester} (build → sign → send →
78
+ * replay reply through delivery → underflow escalation, built lazily once); otherwise fall back to the
79
+ * explicit {@link ReactivitySubscriptionManagerOptions.requestBackfill} callback (or no-op).
80
+ */
81
+ onBackfillGap(from, to) {
82
+ const { backfillTransport, signBackfill } = this.options;
83
+ if (backfillTransport !== undefined && signBackfill !== undefined) {
84
+ if (this.backfillRequester === undefined) {
85
+ this.backfillRequester = createBackfillRequester({
86
+ collectionId: this.collectionIdB64,
87
+ sign: signBackfill,
88
+ transport: backfillTransport,
89
+ subscriber: this.subscriber,
90
+ clock: this.clock,
91
+ onUnderflow: this.options.onBackfillUnderflow,
92
+ });
93
+ }
94
+ // Fire-and-forget off the gap seam (NOT the deliver path — backfill is hint-only and must never
95
+ // block or fault commit/delivery). The driver resolves (no throw) on an `available`-window
96
+ // underflow — that path is handled by `onBackfillUnderflow`; only a genuine **transport failure**
97
+ // rejects, which escalates here. `escalateBackfill` never rejects, so nothing leaks as an
98
+ // unhandled rejection.
99
+ void this.backfillRequester(from, to).catch(() => { void this.escalateBackfill(from, to); });
100
+ return;
101
+ }
102
+ this.options.requestBackfill?.(from, to);
103
+ }
104
+ /**
105
+ * A backfill RPC failed at the transport (the sticky-hint dial + cohort-walk fallback inside the
106
+ * transport were already exhausted). Re-attempt up to {@link ReactivitySubscriptionManagerOptions.backfillMaxRetries}
107
+ * times, then escalate to {@link resume} (when a resume transport is configured) and finally to
108
+ * {@link ReactivitySubscriptionManagerOptions.onChainRead}. Never rejects (it runs detached off the gap
109
+ * seam) and never touches the commit/delivery path.
110
+ */
111
+ async escalateBackfill(from, to) {
112
+ const max = this.options.backfillMaxRetries ?? DEFAULT_BACKFILL_MAX_RETRIES;
113
+ for (let attempt = 1; attempt <= max; attempt++) {
114
+ try {
115
+ await this.backfillRequester(from, to);
116
+ return; // a re-attempt closed (or underflow-escalated) the gap
117
+ }
118
+ catch (err) {
119
+ if (err instanceof RotationRedirectError) {
120
+ // The serving cohort's outgoing tail rotated: move to the new tree (no chain-read fallback).
121
+ this.honorRotationRedirect(err);
122
+ return;
123
+ }
124
+ log("backfill retry %d/%d for [%d,%d] failed: %o", attempt, max, from, to, err);
125
+ }
126
+ }
127
+ // Still failing after the bounded retries: fall back to a resume (a wider recovery window) when one is
128
+ // wired, else signal a chain read. Distinct from the underflow seam, which carries the held window.
129
+ if (this.options.resumeTransport !== undefined && this.options.signResume !== undefined) {
130
+ try {
131
+ await this.resume();
132
+ return;
133
+ }
134
+ catch (err) {
135
+ log("backfill escalation to resume() failed for [%d,%d]: %o", from, to, err);
136
+ }
137
+ }
138
+ this.options.onChainRead?.(undefined, undefined);
139
+ }
140
+ /** The live registration handle, or `undefined` before the first {@link register}. */
141
+ get registration() {
142
+ return this.handle;
143
+ }
144
+ /** Last contiguously-delivered revision. */
145
+ get lastRevision() {
146
+ return this.subscriber.lastRevision;
147
+ }
148
+ /** Register the subscriber at tier T3 with the reactivity `appPayload`. */
149
+ async register() {
150
+ const appPayload = subscribeAppPayloadBytes({
151
+ collectionId: bytesToB64url(this.collectionId),
152
+ tailIdAtAttach: bytesToB64url(this.tailIdAtAttach),
153
+ lastKnownRev: this.lastKnownRev,
154
+ deltaMaxBytes: this.deltaMaxBytes,
155
+ });
156
+ this.handle = await this.service.register({
157
+ topicId: this.topicId,
158
+ tier: Tier.T3,
159
+ appPayload,
160
+ ttl: this.ttlMs,
161
+ });
162
+ return this.handle;
163
+ }
164
+ /** Run one renewal cycle (keep-alive touch). No-op before the first {@link register}. */
165
+ async renew() {
166
+ if (this.handle === undefined) {
167
+ return;
168
+ }
169
+ await this.service.renew(this.handle);
170
+ }
171
+ /** Withdraw: stop renewing and send a best-effort signed tombstone so the cohort frees the
172
+ * registration immediately (TTL expiry remains the fallback if the primary is unreachable). */
173
+ async withdraw() {
174
+ if (this.handle !== undefined) {
175
+ await this.service.withdraw(this.handle);
176
+ }
177
+ }
178
+ /**
179
+ * Resume after a sleep/flap (`docs/reactivity.md` §Resume). Sends one {@link ResumeV1} from
180
+ * `lastRevision + 1` to the serving cohort over the injected {@link ResumeTransport} and applies the
181
+ * classified reply via the db-core {@link applyResumeReply}: a `backfill` / `checkpoint_window` reply
182
+ * replays its entries through the delivery path (verified, deduped); `out_of_window` and an untrusted
183
+ * checkpoint escalate to {@link ReactivitySubscriptionManagerOptions.onChainRead}; `tail_rotated`
184
+ * escalates to {@link ReactivitySubscriptionManagerOptions.onTailRotated} and invalidates the sticky
185
+ * cohort-hint cache (the cached primary is under the old tree). Throws if no resume transport/signer
186
+ * was configured.
187
+ *
188
+ * The sticky cohort-hint cache (Edge) lets a resume after a brief flap dial the cached primary directly
189
+ * for a one-RT recovery instead of re-walking from `d_max`; it is the transport's to consult via
190
+ * {@link cohortHint}.
191
+ */
192
+ async resume() {
193
+ const { resumeTransport, signResume } = this.options;
194
+ if (resumeTransport === undefined || signResume === undefined) {
195
+ throw new Error("ReactivitySubscriptionManager.resume: no resumeTransport/signResume configured");
196
+ }
197
+ if (this.subscriberCoordIsFallback) {
198
+ log("resume: no real ring coordinate supplied; signing ResumeV1 with the collectionId as a placeholder subscriberCoord (collection=%s)", this.collectionIdB64);
199
+ }
200
+ const unsigned = {
201
+ v: 1,
202
+ collectionId: this.collectionIdB64,
203
+ fromRevision: this.subscriber.lastRevision + 1,
204
+ latestKnownTailId: bytesToB64url(this.tailIdAtAttach),
205
+ subscriberCoord: this.subscriberCoord,
206
+ timestamp: this.clock(),
207
+ };
208
+ const req = { ...unsigned, signature: signResume(unsigned) };
209
+ let reply;
210
+ try {
211
+ reply = await resumeTransport(req);
212
+ }
213
+ catch (err) {
214
+ if (err instanceof RotationRedirectError) {
215
+ // The resume reached the serving cohort's outgoing (draining) tail: honor the redirect (surface
216
+ // the rotation through onRotation, invalidate the sticky cache) and resolve as a tail rotation —
217
+ // never throw the redirect out to the caller / the gap seam's commit-delivery path.
218
+ this.honorRotationRedirect(err);
219
+ return "tail_rotated";
220
+ }
221
+ throw err;
222
+ }
223
+ return applyResumeReply(reply, {
224
+ subscriber: this.subscriber,
225
+ verifier: this.verifier,
226
+ onCheckpointDigest: this.options.onCheckpointDigest,
227
+ onChainRead: this.options.onChainRead,
228
+ onTailRotated: (newTailId, newRevisionAtRotation) => {
229
+ // The cached primary is under the now-stale tree; drop it so the re-registration re-walks.
230
+ this.cohortHintCache.invalidate(this.collectionIdB64);
231
+ this.options.onTailRotated?.(newTailId, newRevisionAtRotation);
232
+ },
233
+ });
234
+ }
235
+ /** The sticky cohort-hint cache backing one-RT resume after a flap (Edge). */
236
+ get cohortHint() {
237
+ return this.cohortHintCache;
238
+ }
239
+ /**
240
+ * Run the db-core delivery path for one inbound notification, then check for tail rotation
241
+ * (`docs/reactivity.md` §Tail rotation): a delivered `tailId` that differs from `tailIdAtAttach`, or a
242
+ * `rotationHint` pre-announce, invalidates the sticky cohort-hint cache (the cached primary is under the
243
+ * old tree) and surfaces a jittered re-registration plan via {@link ReactivitySubscriptionManagerOptions.onRotation}.
244
+ * Fired at most once per successor tail.
245
+ */
246
+ async onNotification(n) {
247
+ const outcome = await this.subscriber.onNotification(n);
248
+ this.checkRotation(n);
249
+ return outcome;
250
+ }
251
+ /** Detect a tail rotation from an inbound notification and surface it once per successor tail. */
252
+ checkRotation(n) {
253
+ const detection = detectRotation(this.tailIdAtAttachB64, n);
254
+ if (!detection.rotated || detection.newTailId === undefined) {
255
+ return;
256
+ }
257
+ this.surfaceRotation(detection.newTailId, detection.preAnnounced);
258
+ }
259
+ /**
260
+ * Surface a rotation to the host **once per successor tail** (`docs/reactivity.md` §Tail rotation):
261
+ * invalidate the sticky cohort-hint cache (the cached primary is under the now-stale tree, so a later
262
+ * resume re-walks) and — when an {@link ReactivitySubscriptionManagerOptions.onRotation} observer is
263
+ * configured — hand it a jittered re-registration plan carrying `lastRevision` (continuous across the
264
+ * rotation). The single seam both the notification-driven detection ({@link checkRotation}) and the
265
+ * recover-driven {@link RotationRedirectError} ({@link honorRotationRedirect}) end in; the
266
+ * {@link rotationHandledFor} guard self-corrects across a chained OLD→A→B rotation.
267
+ */
268
+ surfaceRotation(newTailId, preAnnounced) {
269
+ if (newTailId === this.rotationHandledFor) {
270
+ return; // already surfaced this successor
271
+ }
272
+ this.rotationHandledFor = newTailId;
273
+ // The cached primary is under the now-stale tree; drop it so the re-registration re-walks.
274
+ this.cohortHintCache.invalidate(this.collectionIdB64);
275
+ if (this.options.onRotation === undefined) {
276
+ return;
277
+ }
278
+ const plan = planReRegistration({
279
+ hint: { newTailId },
280
+ lastRevision: this.subscriber.lastRevision,
281
+ now: this.clock(),
282
+ jitter: this.rejoinJitter,
283
+ });
284
+ this.options.onRotation({ newTailId, preAnnounced, plan });
285
+ }
286
+ /**
287
+ * Honor a recover-surfaced {@link RotationRedirectError}: the serving cohort's outgoing tail rotated and
288
+ * bounced this request to the new tree. Route it through the **same** {@link surfaceRotation} seam a
289
+ * delivered pre-announce uses (`preAnnounced: false`), so both the notify-driven and recover-driven
290
+ * rotation paths converge on one `RotationNotice` for the host's re-registration scheduler to consume.
291
+ */
292
+ honorRotationRedirect(err) {
293
+ this.surfaceRotation(err.redirect.newTailId, false);
294
+ }
295
+ }
296
+ /** Default application-level backfill re-attempts after a transport failure before escalating to resume/chain. */
297
+ const DEFAULT_BACKFILL_MAX_RETRIES = 1;
298
+ /** Fallback subscriber TTL when neither `ttlMs` nor `profile` is supplied (Core default). */
299
+ const DEFAULT_SUBSCRIBER_TTL_MS = 90_000;
300
+ /** Edge-safe delta budget when neither `deltaMaxBytes` nor `profile` is supplied: decline deltas. */
301
+ const DEFAULT_EDGE_SAFE_DELTA_MAX = 0;
302
+ //# sourceMappingURL=subscription-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager.js","sourceRoot":"","sources":["../../../src/reactivity/subscription-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Reactivity — the one pinned `BlockId` → raw tail-bytes encoding, shared by origination and subscription.
3
+ *
4
+ * `reactivityTopicId` (db-core) hashes `H(tailBytes ‖ "reactivity")` to derive the topic's `coord_0`
5
+ * cohort. Origination (the cohort-change membership gate, {@link
6
+ * import("../cohort-topic/reactivity-membership-gate.js").createReactivitySelfMembershipGate}) and the
7
+ * subscriber side (the production subscribe factory that converts a `BlockId` `tailIdAtAttach` to the bytes
8
+ * {@link import("./subscription-manager.js").ReactivitySubscriptionManager} feeds `reactivityTopicId`) MUST
9
+ * feed it the **same** bytes for a given tail, or they resolve different coords and origination silently
10
+ * never reaches subscribers (green tests, dead feature).
11
+ *
12
+ * This module is that single source of truth: `reactivityTailBytes(tailId) = TextEncoder().encode(tailId)`,
13
+ * the synchronous block-id→bytes convention the rest of db-p2p already uses for ring hashing of tail ids
14
+ * (`cluster/client.ts`, `repo/client.ts`). db-core's async `blockIdToBytes` (which `sha256`s the utf8 bytes
15
+ * first) is deliberately NOT used: it would (a) double-hash relative to the spec's `H(tailId ‖ "reactivity")`
16
+ * and (b) force the synchronous origination gate to become async.
17
+ *
18
+ * It lives in the reactivity surface (not buried in the gate) so the subscribe path and the gate import the
19
+ * exact same function rather than re-deriving the encoding independently. The
20
+ * `cohort-topic/reactivity-membership-gate.ts` module re-exports it for its existing callers.
21
+ */
22
+ import type { BlockId } from "@optimystic/db-core";
23
+ /**
24
+ * The pinned `BlockId` → raw tail bytes encoding fed into `reactivityTopicId`: the **raw** utf8 bytes of the
25
+ * tail block-id string (NOT a pre-hashed routing key, NOT db-core's double-hashing `blockIdToBytes`).
26
+ *
27
+ * Load-bearing: origination and the subscriber side must call this **same** function for a given tail (see
28
+ * the module doc) — a mismatch resolves different `coord_0`s and origination silently never reaches
29
+ * subscribers. The `topic-bytes-encoding` spec pins the coord-equality both ways.
30
+ */
31
+ export declare function reactivityTailBytes(tailId: BlockId): Uint8Array;
32
+ //# sourceMappingURL=topic-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-bytes.d.ts","sourceRoot":"","sources":["../../../src/reactivity/topic-bytes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAInD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,UAAU,CAE/D"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Reactivity — the one pinned `BlockId` → raw tail-bytes encoding, shared by origination and subscription.
3
+ *
4
+ * `reactivityTopicId` (db-core) hashes `H(tailBytes ‖ "reactivity")` to derive the topic's `coord_0`
5
+ * cohort. Origination (the cohort-change membership gate, {@link
6
+ * import("../cohort-topic/reactivity-membership-gate.js").createReactivitySelfMembershipGate}) and the
7
+ * subscriber side (the production subscribe factory that converts a `BlockId` `tailIdAtAttach` to the bytes
8
+ * {@link import("./subscription-manager.js").ReactivitySubscriptionManager} feeds `reactivityTopicId`) MUST
9
+ * feed it the **same** bytes for a given tail, or they resolve different coords and origination silently
10
+ * never reaches subscribers (green tests, dead feature).
11
+ *
12
+ * This module is that single source of truth: `reactivityTailBytes(tailId) = TextEncoder().encode(tailId)`,
13
+ * the synchronous block-id→bytes convention the rest of db-p2p already uses for ring hashing of tail ids
14
+ * (`cluster/client.ts`, `repo/client.ts`). db-core's async `blockIdToBytes` (which `sha256`s the utf8 bytes
15
+ * first) is deliberately NOT used: it would (a) double-hash relative to the spec's `H(tailId ‖ "reactivity")`
16
+ * and (b) force the synchronous origination gate to become async.
17
+ *
18
+ * It lives in the reactivity surface (not buried in the gate) so the subscribe path and the gate import the
19
+ * exact same function rather than re-deriving the encoding independently. The
20
+ * `cohort-topic/reactivity-membership-gate.ts` module re-exports it for its existing callers.
21
+ */
22
+ const utf8 = new TextEncoder();
23
+ /**
24
+ * The pinned `BlockId` → raw tail bytes encoding fed into `reactivityTopicId`: the **raw** utf8 bytes of the
25
+ * tail block-id string (NOT a pre-hashed routing key, NOT db-core's double-hashing `blockIdToBytes`).
26
+ *
27
+ * Load-bearing: origination and the subscriber side must call this **same** function for a given tail (see
28
+ * the module doc) — a mismatch resolves different `coord_0`s and origination silently never reaches
29
+ * subscribers. The `topic-bytes-encoding` spec pins the coord-equality both ways.
30
+ */
31
+ export function reactivityTailBytes(tailId) {
32
+ return utf8.encode(tailId);
33
+ }
34
+ //# sourceMappingURL=topic-bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-bytes.js","sourceRoot":"","sources":["../../../src/reactivity/topic-bytes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAE/B;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IAClD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAC7F,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAC3D,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qBAAa,UAAW,SAAQ,cAAe,YAAW,KAAK;IACC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9F,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAO5E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC;IAOxF,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAOpF,OAAO,CAAC,oBAAoB;YASd,kBAAkB;IA6ChC,OAAO,CAAC,wBAAwB;IAoBhC,OAAO,CAAC,kCAAkC;CAQ1C"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAC7F,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAC3D,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qBAAa,UAAW,SAAQ,cAAe,YAAW,KAAK;IACC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM;IAA/F,OAAO;IAIP,mCAAmC;WACrB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9F,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAO5E,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,GAAG,YAAY,CAAC;IAOxF,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAOpF,OAAO,CAAC,oBAAoB;YASd,kBAAkB;YAkElB,wBAAwB;YA6BxB,kCAAkC;CAQhD"}
@@ -1,3 +1,4 @@
1
+ import { blockIdsForTransforms, blockIdToBytes } from "@optimystic/db-core";
1
2
  import { ProtocolClient } from "../protocol-client.js";
2
3
  import { peerIdFromString } from "@libp2p/peer-id";
3
4
  export class RepoClient extends ProtocolClient {
@@ -41,20 +42,36 @@ export class RepoClient extends ProtocolClient {
41
42
  };
42
43
  const correlationId = this.extractCorrelationId(operations);
43
44
  const deadline = options.expiration ?? (Date.now() + 30_000);
44
- const msLeft = Math.max(1, deadline - Date.now());
45
- const withTimeout = async (fn) => {
46
- return await Promise.race([
47
- fn(),
48
- new Promise((_, reject) => setTimeout(() => reject(new Error('RepoClient timeout')), msLeft))
49
- ]);
50
- };
51
- let response;
45
+ const deadlineMs = Math.max(1, deadline - Date.now());
52
46
  const preferred = (this.protocolPrefix ?? '/db-p2p') + '/repo/1.0.0';
53
- response = await withTimeout(() => super.processMessage(message, preferred, {
54
- signal: options?.signal,
55
- correlationId,
56
- dialTimeoutMs: options?.dialTimeoutMs,
57
- }));
47
+ // Drive the remaining `expiration` budget through an AbortController whose
48
+ // abort *reason* is the caller-facing `'RepoClient timeout'` Error, combined
49
+ // with any caller signal. processMessage forwards `signal` to both the dial
50
+ // and the response-read and calls `stream.abort(signal.reason)` on abort, so —
51
+ // unlike the old `Promise.race`, whose losing branch left the inner read
52
+ // running and leaked a pending read + stream on every timed-out RPC to a silent
53
+ // peer — the deadline now genuinely cancels the inner read while the caller
54
+ // still observes an error whose `.message === 'RepoClient timeout'`.
55
+ //
56
+ // Intentionally no `responseTimeoutMs`: the combined signal already bounds the
57
+ // read at `deadlineMs`. A second, shorter cap would surface as
58
+ // ResponseTimeoutError and mask the caller-facing 'RepoClient timeout' message.
59
+ const deadlineController = new AbortController();
60
+ const timer = setTimeout(() => deadlineController.abort(new Error('RepoClient timeout')), deadlineMs);
61
+ const combinedSignal = options?.signal
62
+ ? AbortSignal.any([options.signal, deadlineController.signal])
63
+ : deadlineController.signal;
64
+ let response;
65
+ try {
66
+ response = await super.processMessage(message, preferred, {
67
+ signal: combinedSignal,
68
+ correlationId,
69
+ dialTimeoutMs: options?.dialTimeoutMs,
70
+ });
71
+ }
72
+ finally {
73
+ clearTimeout(timer);
74
+ }
58
75
  if (response?.redirect?.peers?.length) {
59
76
  if (hop >= 2) {
60
77
  throw new Error('Redirect loop detected in RepoClient (max hops reached)');
@@ -65,35 +82,46 @@ export class RepoClient extends ProtocolClient {
65
82
  if (next.id === currentIdStr) {
66
83
  throw new Error('Redirect loop detected in RepoClient (same peer)');
67
84
  }
68
- // cache hint
69
- this.recordCoordinatorForOpsIfSupported(operations, nextId);
85
+ // cache hint — await so the recorded key bytes match what findCoordinator
86
+ // later looks up (blockIdToBytes is async); deterministic ordering also
87
+ // keeps the hint testable. The redirect retry below is async anyway.
88
+ await this.recordCoordinatorForOpsIfSupported(operations, nextId);
70
89
  // single-hop retry against target peer using repo protocol
71
90
  const nextClient = RepoClient.create(nextId, this.peerNetwork, this.protocolPrefix);
72
91
  return await nextClient.processRepoMessage(operations, options, hop + 1);
73
92
  }
74
93
  return response;
75
94
  }
76
- extractKeyFromOperations(ops) {
95
+ async extractKeyFromOperations(ops) {
77
96
  const op = ops[0];
97
+ // The recorded key MUST be the sha256 digest produced by blockIdToBytes — the
98
+ // exact bytes findCoordinator/recordCoordinator key the coordinator cache on
99
+ // (NetworkTransactor passes blockIdToBytes(blockId)). Raw utf8 of the id would
100
+ // never match, so the hint would silently never be retrieved.
78
101
  if ('get' in op) {
79
102
  const id = op.get.blockIds[0];
80
- return id ? new TextEncoder().encode(id) : undefined;
103
+ return id ? await blockIdToBytes(id) : undefined;
81
104
  }
82
105
  if ('pend' in op) {
83
- const id = Object.keys(op.pend.transforms)[0];
84
- return id ? new TextEncoder().encode(id) : undefined;
106
+ // Key on a real block id the pend touches, NOT a structural transforms field
107
+ // name ('inserts'/'updates'/'deletes'); see RepoService.deriveBlockKey.
108
+ const id = blockIdsForTransforms(op.pend.transforms)[0];
109
+ return id ? await blockIdToBytes(id) : undefined;
85
110
  }
86
111
  if ('commit' in op) {
87
- return new TextEncoder().encode(op.commit.tailId);
112
+ // Anchor on blockIds[0] (where CoordinatorRepo.commit runs consensus +
113
+ // verifyResponsibility), NOT tailId — they differ for a non-tail batch.
114
+ const id = op.commit.blockIds[0];
115
+ return id ? await blockIdToBytes(id) : undefined;
88
116
  }
89
117
  if ('cancel' in op) {
90
118
  const id = op.cancel.actionRef.blockIds[0];
91
- return id ? new TextEncoder().encode(id) : undefined;
119
+ return id ? await blockIdToBytes(id) : undefined;
92
120
  }
93
121
  return undefined;
94
122
  }
95
- recordCoordinatorForOpsIfSupported(ops, peerId) {
96
- const keyBytes = this.extractKeyFromOperations(ops);
123
+ async recordCoordinatorForOpsIfSupported(ops, peerId) {
124
+ const keyBytes = await this.extractKeyFromOperations(ops);
97
125
  const pn = this.peerNetwork;
98
126
  if (keyBytes != null && typeof pn?.recordCoordinator === 'function') {
99
127
  pn.recordCoordinator(keyBytes, peerId);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/repo/client.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Startable, Logger, StreamHandler, PeerId } from '@libp2p/interface';
1
+ import type { Startable, Logger, StreamHandler, PeerId, Libp2p } from '@libp2p/interface';
2
2
  import type { IRepo, RepoMessage } from '@optimystic/db-core';
3
3
  import { type RedirectPayload } from './redirect.js';
4
4
  interface BaseComponents {
@@ -18,6 +18,13 @@ export type RepoServiceComponents = BaseComponents & {
18
18
  networkManager?: NetworkManagerLike;
19
19
  peerId?: PeerId;
20
20
  getConnectionAddrs?: (peerId: PeerId) => string[];
21
+ /**
22
+ * Optional libp2p node. The production wiring injects the node post-construction
23
+ * via {@link RepoService.setLibp2p} (the `components.libp2p` proxy does not
24
+ * reliably resolve from inside a service at request time); this field is a
25
+ * best-effort fallback resolver used only when no node has been injected.
26
+ */
27
+ libp2p?: Libp2p;
21
28
  };
22
29
  export type RepoServiceInit = {
23
30
  protocol?: string;
@@ -50,8 +57,23 @@ export declare class RepoService implements Startable {
50
57
  private running;
51
58
  /** Responsibility K - how many peers are responsible for a key (for redirect decisions) */
52
59
  private readonly responsibilityK;
60
+ /**
61
+ * The libp2p node, injected post-construction by the node wiring (see
62
+ * libp2p-node-base.ts, mirroring how `networkManager`/`fret` receive theirs).
63
+ * The libp2p `components.libp2p` proxy does NOT reliably resolve from inside a
64
+ * service at request time, so the redirect path resolves the network manager,
65
+ * self identity, and connection addrs through this explicitly-set reference.
66
+ */
67
+ private libp2pRef;
53
68
  constructor(components: RepoServiceComponents, init?: RepoServiceInit);
54
69
  readonly [Symbol.toStringTag] = "@libp2p/repo-service";
70
+ /**
71
+ * Inject the running libp2p node. Called once post-construction by the node
72
+ * wiring so the redirect path can resolve the network manager / self id / addrs.
73
+ */
74
+ setLibp2p(libp2p: Libp2p): void;
75
+ /** Resolve the libp2p node: the injected ref first, then the (best-effort) components proxy. */
76
+ private getLibp2p;
55
77
  /**
56
78
  * Start the service
57
79
  */
@@ -63,6 +85,29 @@ export declare class RepoService implements Startable {
63
85
  private getNetworkManager;
64
86
  private getSelfId;
65
87
  private getPeerAddrs;
88
+ /**
89
+ * Derive the redirect routing key and op name for a single operation.
90
+ *
91
+ * The key MUST be the block the corresponding handler actually coordinates and
92
+ * verifies responsibility on, so redirect routing stays consistent with where the
93
+ * op is executed:
94
+ * - get → blockIds[0]
95
+ * - pend → blockIdsForTransforms(transforms)[0]
96
+ * - cancel → actionRef.blockIds[0]
97
+ * - commit → blockIds[0] (CoordinatorRepo.commit anchors consensus on
98
+ * getClusterSize(blockIds[0]) / executeClusterTransaction(blockIds[0]) and guards
99
+ * with verifyResponsibility(blockIds) — NOT tailId; for a per-block commit batch
100
+ * whose blockIds[0] !== tailId, keying on tailId redirected the commit to the
101
+ * collection tail's cluster, which then fails verifyResponsibility for the non-tail block.)
102
+ *
103
+ * Returns blockKey === undefined when the op carries no routable key (e.g. a cancel
104
+ * with an empty blockIds list), in which case the caller handles it locally without a
105
+ * redirect check.
106
+ */
107
+ deriveBlockKey(operation: RepoMessage['operations'][number]): {
108
+ blockKey: string | undefined;
109
+ opName: string;
110
+ };
66
111
  /**
67
112
  * Check if this node should redirect the request for a given key.
68
113
  * Returns a RedirectPayload if not responsible, null if should handle locally.
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/repo/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAsB,aAAa,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AACrG,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAG7D,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAOjE,UAAU,cAAc;IACvB,MAAM,EAAE;QAAE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;KAAE,CAAC;IACnD,SAAS,EAAE;QACV,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;QACjF,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAC7C,CAAA;CACD;AAED,MAAM,WAAW,kBAAkB;IAClC,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;CAC9C;AAED,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACpD,IAAI,EAAE,KAAK,CAAA;IACX,cAAc,CAAC,EAAE,kBAAkB,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,EAAE,CAAA;CACjD,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB,CAAA;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,eAAoB,GAAG,CAAC,UAAU,EAAE,qBAAqB,KAAK,WAAW,CAE1G;AAED;;GAEG;AACH,qBAAa,WAAY,YAAW,SAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;gBAE5B,UAAU,EAAE,qBAAqB,EAAE,IAAI,GAAE,eAAoB;IAYzE,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,0BAAyB;IAEtD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,YAAY;IAapB;;;;OAIG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA2B5G;;OAEG;IACH,OAAO,CAAC,oBAAoB;CA0E5B"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/repo/service.ts"],"names":[],"mappings":"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"}