@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
@@ -1,8 +1,9 @@
1
1
  import type {
2
2
  IRepo, MessageOptions, BlockId, CommitRequest, CommitResult, GetBlockResults, PendRequest, PendResult, ActionBlocks,
3
3
  ActionId, BlockGets, ActionPending, PendSuccess, ActionTransform, ActionTransforms,
4
- GetBlockResult,
5
- PendValidationHook
4
+ GetBlockResult, IBlock, ActionRev,
5
+ PendValidationHook,
6
+ CollectionId, IBlockChangeNotifier, CollectionChangeListener, CollectionChangeEvent
6
7
  } from "@optimystic/db-core";
7
8
  import {
8
9
  Latches, transformForBlockId, applyTransform, groupBy, concatTransform, emptyTransforms,
@@ -10,6 +11,7 @@ import {
10
11
  } from "@optimystic/db-core";
11
12
  import { asyncIteratorToArray } from "../it-utility.js";
12
13
  import type { IBlockStorage } from "./i-block-storage.js";
14
+ import type { IBlockReplicaStore } from "../cluster/block-transfer-service.js";
13
15
  import { createLogger } from "../logger.js";
14
16
 
15
17
  const log = createLogger('storage-repo');
@@ -19,8 +21,12 @@ export type StorageRepoOptions = {
19
21
  validatePend?: PendValidationHook;
20
22
  };
21
23
 
22
- export class StorageRepo implements IRepo {
24
+ export class StorageRepo implements IRepo, IBlockChangeNotifier, IBlockReplicaStore {
23
25
  private readonly validatePend?: PendValidationHook;
26
+ /** Per-collection change listeners; empty sets are pruned on unsubscribe. */
27
+ private readonly changeListeners = new Map<CollectionId, Set<CollectionChangeListener>>();
28
+ /** Catch-all change listeners — fire for EVERY collection's commit on this node. */
29
+ private readonly anyChangeListeners = new Set<CollectionChangeListener>();
24
30
 
25
31
  constructor(
26
32
  private readonly createBlockStorage: (blockId: BlockId) => IBlockStorage,
@@ -29,9 +35,96 @@ export class StorageRepo implements IRepo {
29
35
  this.validatePend = options?.validatePend;
30
36
  }
31
37
 
38
+ /**
39
+ * Subscribe to commits that mutate `collectionId`'s blocks on this node.
40
+ * Returns an idempotent unsubscribe. See {@link IBlockChangeNotifier}.
41
+ */
42
+ onCollectionChange(collectionId: CollectionId, listener: CollectionChangeListener): () => void {
43
+ let set = this.changeListeners.get(collectionId);
44
+ if (!set) {
45
+ set = new Set();
46
+ this.changeListeners.set(collectionId, set);
47
+ }
48
+ set.add(listener);
49
+ let unsubscribed = false;
50
+ return () => {
51
+ if (unsubscribed) return;
52
+ unsubscribed = true;
53
+ const current = this.changeListeners.get(collectionId);
54
+ if (current) {
55
+ current.delete(listener);
56
+ if (current.size === 0) {
57
+ this.changeListeners.delete(collectionId);
58
+ }
59
+ }
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Subscribe to commits mutating ANY collection on this node — the catch-all feed the
65
+ * cohort-topic origination bridge consumes (it cannot enumerate collection ids ahead of time,
66
+ * so a per-collection {@link onCollectionChange} subscription cannot see every commit). Fires for
67
+ * the same `(pending → committed)` transitions as {@link onCollectionChange}, but across every
68
+ * collection. Returns an idempotent unsubscribe; a throwing listener is isolated + logged.
69
+ */
70
+ onAnyCollectionChange(listener: CollectionChangeListener): () => void {
71
+ this.anyChangeListeners.add(listener);
72
+ let unsubscribed = false;
73
+ return () => {
74
+ if (unsubscribed) return;
75
+ unsubscribed = true;
76
+ this.anyChangeListeners.delete(listener);
77
+ };
78
+ }
79
+
80
+ /**
81
+ * Fire one {@link CollectionChangeEvent} per distinct collection that was
82
+ * newly committed. Called AFTER the commit critical section (locks released),
83
+ * fire-and-forget synchronous; a throwing listener is isolated and logged. Each event reaches
84
+ * both that collection's {@link onCollectionChange} subscribers and every
85
+ * {@link onAnyCollectionChange} catch-all subscriber.
86
+ *
87
+ * `tailId` is the `CommitRequest.tailId` on the commit path; `undefined` on read-driven
88
+ * promotions (the get/emitPromotions path has no commit request). A single commit is for one
89
+ * collection's chain in practice, so all events from one commit share the same `tailId`.
90
+ */
91
+ private emitCollectionChanges(collectionBlocks: Map<CollectionId, BlockId[]>, actionId: ActionId, rev: number, tailId?: BlockId): void {
92
+ const hasCatchAll = this.anyChangeListeners.size > 0;
93
+ for (const [collectionId, blockIds] of collectionBlocks) {
94
+ const listeners = this.changeListeners.get(collectionId);
95
+ if ((!listeners || listeners.size === 0) && !hasCatchAll) {
96
+ continue;
97
+ }
98
+ const event: CollectionChangeEvent = { collectionId, blockIds, actionId, rev, tailId };
99
+ if (listeners && listeners.size > 0) {
100
+ this.fireChangeListeners(listeners, event);
101
+ }
102
+ if (hasCatchAll) {
103
+ this.fireChangeListeners(this.anyChangeListeners, event);
104
+ }
105
+ }
106
+ }
107
+
108
+ /** Dispatch `event` to a snapshot of `listeners` (safe under mid-emit (un)subscribe), isolating + logging any throw. */
109
+ private fireChangeListeners(listeners: Set<CollectionChangeListener>, event: CollectionChangeEvent): void {
110
+ for (const listener of Array.from(listeners)) {
111
+ try {
112
+ listener(event);
113
+ } catch (err) {
114
+ log('onCollectionChange listener threw for collection=%s: %o', event.collectionId, err);
115
+ }
116
+ }
117
+ }
118
+
32
119
  async get({ blockIds, context }: BlockGets, _options?: MessageOptions): Promise<GetBlockResults> {
33
120
  const distinctBlockIds = Array.from(new Set(blockIds));
34
121
  log('get blockIds=%d', distinctBlockIds.length);
122
+ // Read-driven promotions that land durably here, captured so we can emit a
123
+ // change event per durable landing after the parallel reads complete (mirrors
124
+ // commit's "emit after the work" ordering). The array is shared across the
125
+ // parallel map closures below — safe because each push happens synchronously
126
+ // between awaits (single-threaded), never concurrently.
127
+ const promotions: { collectionId: CollectionId, blockId: BlockId, actionId: ActionId, rev: number }[] = [];
35
128
  const results = await Promise.all(distinctBlockIds.map(async (blockId) => {
36
129
  const blockStorage = this.createBlockStorage(blockId);
37
130
 
@@ -44,7 +137,10 @@ export class StorageRepo implements IRepo {
44
137
  for (const { actionId, rev } of missing.sort((a, b) => a.rev - b.rev)) {
45
138
  const pending = await blockStorage.getPendingTransaction(actionId);
46
139
  if (pending) {
47
- await this.internalCommit(blockId, actionId, rev, blockStorage);
140
+ const collectionId = await this.internalCommit(blockId, actionId, rev, blockStorage);
141
+ if (collectionId !== undefined) {
142
+ promotions.push({ collectionId, blockId, actionId, rev });
143
+ }
48
144
  }
49
145
  }
50
146
  }
@@ -82,9 +178,42 @@ export class StorageRepo implements IRepo {
82
178
  }
83
179
  }];
84
180
  }));
181
+
182
+ // Emit per durable read-driven landing (Option A — emit eagerly). Done after the
183
+ // parallel reads complete so emission stays outside the per-block work, matching
184
+ // commit's ordering. No-op when nothing was promoted.
185
+ this.emitPromotions(promotions);
186
+
85
187
  return Object.fromEntries(results);
86
188
  }
87
189
 
190
+ /**
191
+ * Emit a {@link CollectionChangeEvent} for each read-driven promotion that landed
192
+ * during a {@link get}. A single get() can promote multiple distinct actions, each
193
+ * at its own `(actionId, rev)`, so group by `(actionId, rev)` and route each group
194
+ * through {@link emitCollectionChanges} once.
195
+ */
196
+ private emitPromotions(promotions: { collectionId: CollectionId, blockId: BlockId, actionId: ActionId, rev: number }[]): void {
197
+ if (promotions.length === 0) {
198
+ return;
199
+ }
200
+ const groups = new Map<string, { actionId: ActionId, rev: number, collectionBlocks: Map<CollectionId, BlockId[]> }>();
201
+ for (const { collectionId, blockId, actionId, rev } of promotions) {
202
+ const key = `${actionId} ${rev}`;
203
+ let group = groups.get(key);
204
+ if (!group) {
205
+ group = { actionId, rev, collectionBlocks: new Map() };
206
+ groups.set(key, group);
207
+ }
208
+ const list = group.collectionBlocks.get(collectionId) ?? [];
209
+ list.push(blockId);
210
+ group.collectionBlocks.set(collectionId, list);
211
+ }
212
+ for (const { actionId, rev, collectionBlocks } of groups.values()) {
213
+ this.emitCollectionChanges(collectionBlocks, actionId, rev);
214
+ }
215
+ }
216
+
88
217
  async pend(request: PendRequest, _options?: MessageOptions): Promise<PendResult> {
89
218
  // Validate transaction if present and validation hook is configured
90
219
  if (this.validatePend && request.transaction && request.operationsHash) {
@@ -194,6 +323,14 @@ export class StorageRepo implements IRepo {
194
323
  log('commit actionId=%s rev=%d blockIds=%d', request.actionId, request.rev, request.blockIds.length);
195
324
  const uniqueBlockIds = Array.from(new Set(request.blockIds)).sort();
196
325
  const releases: (() => void)[] = [];
326
+ // Collects the blocks newly committed in this call, grouped by collection,
327
+ // so we can emit change events once locks are released. Blocks that land before
328
+ // a mid-loop failure stay here and are still emitted (Option A — emit eagerly):
329
+ // they are durably committed and a retry rolls the remainder forward.
330
+ const collectionBlocks = new Map<CollectionId, BlockId[]>();
331
+ // Captured when internalCommit throws mid-loop; we break (rather than return)
332
+ // so locks release and accumulated landings still emit before we report failure.
333
+ let failure: { reason: string } | undefined;
197
334
 
198
335
  try {
199
336
  // Acquire locks sequentially based on sorted IDs to prevent deadlocks
@@ -273,14 +410,19 @@ export class StorageRepo implements IRepo {
273
410
  for (const { blockId, storage } of toCommit) {
274
411
  try {
275
412
  // internalCommit will throw if it encounters an issue
276
- await this.internalCommit(blockId, request.actionId, request.rev, storage);
413
+ const collectionId = await this.internalCommit(blockId, request.actionId, request.rev, storage);
414
+ if (collectionId !== undefined) {
415
+ const list = collectionBlocks.get(collectionId) ?? [];
416
+ list.push(blockId);
417
+ collectionBlocks.set(collectionId, list);
418
+ }
277
419
  } catch (err) {
278
- // Partial-commit recovery: a retry with the same (actionId, rev) will treat
279
- // already-done blocks as idempotent no-ops and advance the remainder.
280
- return {
281
- success: false,
282
- reason: err instanceof Error ? err.message : 'Unknown error during commit'
283
- };
420
+ // Partial-commit recovery: blocks already in collectionBlocks DID land
421
+ // durably and must still emit; a retry with the same (actionId, rev)
422
+ // treats them as idempotent no-ops and advances the remainder. Break
423
+ // instead of returning so locks release and those landings emit below.
424
+ failure = { reason: err instanceof Error ? err.message : 'Unknown error during commit' };
425
+ break;
284
426
  }
285
427
  }
286
428
  }
@@ -289,7 +431,12 @@ export class StorageRepo implements IRepo {
289
431
  releases.reverse().forEach(release => release());
290
432
  }
291
433
 
292
- return { success: true };
434
+ // Notify after the critical section, for every block newly committed here —
435
+ // including those that landed before a mid-loop failure (alreadyDone / stale
436
+ // partitions never reach `collectionBlocks`).
437
+ this.emitCollectionChanges(collectionBlocks, request.actionId, request.rev, request.tailId);
438
+
439
+ return failure ? { success: false, reason: failure.reason } : { success: true };
293
440
  }
294
441
 
295
442
  /**
@@ -305,7 +452,50 @@ export class StorageRepo implements IRepo {
305
452
  await storage.recover();
306
453
  }
307
454
 
308
- private async internalCommit(blockId: BlockId, actionId: ActionId, rev: number, storage: IBlockStorage): Promise<void> {
455
+ /**
456
+ * Persist a replica of a block received out-of-band (churn re-replication) into
457
+ * local storage. Distinct from the {@link IRepo} commit funnel: the block arrives
458
+ * already materialized from a departing owner, not as a pend/commit. See
459
+ * {@link IBlockStorage.saveReplica} for the durability/monotonicity contract.
460
+ *
461
+ * Held under the same `StorageRepo.commit:<id>` latch as {@link commit} so the
462
+ * replica's read-modify-write of `latest` is mutually exclusive with a concurrent
463
+ * local commit on the same block — otherwise `saveReplica`'s monotonic guard could
464
+ * read a stale `latest` and clobber a commit that advanced it in between.
465
+ */
466
+ async saveReplicatedBlock(blockId: BlockId, block: IBlock, source?: ActionRev): Promise<void> {
467
+ log('saveReplicatedBlock blockId=%s rev=%s', blockId, source?.rev);
468
+ const storage = this.createBlockStorage(blockId);
469
+ const release = await Latches.acquire(`StorageRepo.commit:${blockId}`);
470
+ // Captured under the latch; emitted after release to match commit's ordering.
471
+ let landed: { collectionId: CollectionId, actionId: ActionId, rev: number } | undefined;
472
+ try {
473
+ const priorLatest = await storage.getLatest();
474
+ const effective = await storage.saveReplica(block, source);
475
+ // Advanced iff there was no prior revision or the effective rev moved past it. On the
476
+ // monotonic no-op, saveReplica returns the held latest unchanged → effective.rev === priorLatest.rev.
477
+ const advanced = priorLatest === undefined || effective.rev > priorLatest.rev;
478
+ const collectionId = block.header?.collectionId;
479
+ if (advanced && collectionId !== undefined) {
480
+ landed = { collectionId, actionId: effective.actionId, rev: effective.rev };
481
+ }
482
+ } finally {
483
+ release();
484
+ }
485
+ // Replica-persist has no CommitRequest, hence no tailId — like a read-driven promotion,
486
+ // this wakes local onCollectionChange watchers but is cert-gated out of cohort-topic
487
+ // re-origination downstream (change-bridge selfIsCohortMember treats a tail-less event as
488
+ // never a member).
489
+ if (landed) {
490
+ this.emitCollectionChanges(
491
+ new Map([[landed.collectionId, [blockId]]]),
492
+ landed.actionId,
493
+ landed.rev,
494
+ );
495
+ }
496
+ }
497
+
498
+ private async internalCommit(blockId: BlockId, actionId: ActionId, rev: number, storage: IBlockStorage): Promise<CollectionId | undefined> {
309
499
  // Note: This method is called within the locked critical section of commit()
310
500
  // So, operations like getPendingTransaction, getLatest, getBlock, saveMaterializedBlock,
311
501
  // saveRevision, promotePendingTransaction, setLatest are protected against
@@ -340,6 +530,12 @@ export class StorageRepo implements IRepo {
340
530
 
341
531
  // Update latest revision *last*
342
532
  await storage.setLatest({ actionId, rev });
533
+
534
+ // Report the affected collection for change-event routing. For a delete the
535
+ // materialized block is undefined, so fall back to the prior block's header.
536
+ // Either may be absent only for a malformed/headerless block — return
537
+ // undefined so the caller skips it rather than emitting a bogus event.
538
+ return newBlock?.header.collectionId ?? priorBlock?.header.collectionId;
343
539
  }
344
540
  }
345
541
 
@@ -2,6 +2,7 @@ import type { PeerId } from '@libp2p/interface';
2
2
  import type { IPeerNetwork } from '@optimystic/db-core';
3
3
  import { ProtocolClient } from '../protocol-client.js';
4
4
  import { buildSyncProtocol, type SyncRequest, type SyncResponse } from './protocol.js';
5
+ import { withRpcDeadlineDefaults, type RpcDeadlineOptions } from '../rpc-deadline.js';
5
6
 
6
7
  /**
7
8
  * Client for sending sync requests to remote peers.
@@ -25,11 +26,13 @@ export class SyncClient extends ProtocolClient {
25
26
  * Request a block from the remote peer.
26
27
  *
27
28
  * @param request - Sync request specifying block and options
29
+ * @param options - Optional per-call deadlines/cancellation. Absent keys fall
30
+ * back to the client-level defaults so a silent peer can't hang the caller.
28
31
  * @returns Response with archive if successful
29
32
  * @throws Error if request fails or times out
30
33
  */
31
- async requestBlock(request: SyncRequest): Promise<SyncResponse> {
32
- return await this.processMessage<SyncResponse>(request, this.protocol);
34
+ async requestBlock(request: SyncRequest, options?: RpcDeadlineOptions): Promise<SyncResponse> {
35
+ return await this.processMessage<SyncResponse>(request, this.protocol, withRpcDeadlineDefaults(options));
33
36
  }
34
37
 
35
38
  /**