@optimystic/db-p2p 0.13.4 → 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 (352) 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 +8 -1
  134. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  135. package/dist/src/libp2p-key-network.js +67 -8
  136. package/dist/src/libp2p-key-network.js.map +1 -1
  137. package/dist/src/libp2p-node-base.d.ts +57 -3
  138. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  139. package/dist/src/libp2p-node-base.js +523 -6
  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 +25 -0
  186. package/dist/src/protocol-client.d.ts.map +1 -1
  187. package/dist/src/protocol-client.js +126 -4
  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 -19
  235. package/dist/src/repo/client.js.map +1 -1
  236. package/dist/src/repo/cluster-coordinator.d.ts +9 -0
  237. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  238. package/dist/src/repo/cluster-coordinator.js +65 -22
  239. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  240. package/dist/src/repo/coordinator-repo.d.ts +20 -0
  241. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  242. package/dist/src/repo/coordinator-repo.js +101 -16
  243. package/dist/src/repo/coordinator-repo.js.map +1 -1
  244. package/dist/src/repo/service.d.ts +46 -1
  245. package/dist/src/repo/service.d.ts.map +1 -1
  246. package/dist/src/repo/service.js +79 -45
  247. package/dist/src/repo/service.js.map +1 -1
  248. package/dist/src/rpc-deadline.d.ts +37 -0
  249. package/dist/src/rpc-deadline.d.ts.map +1 -0
  250. package/dist/src/rpc-deadline.js +31 -0
  251. package/dist/src/rpc-deadline.js.map +1 -0
  252. package/dist/src/storage/block-storage.d.ts +2 -0
  253. package/dist/src/storage/block-storage.d.ts.map +1 -1
  254. package/dist/src/storage/block-storage.js +95 -2
  255. package/dist/src/storage/block-storage.js.map +1 -1
  256. package/dist/src/storage/i-block-storage.d.ts +25 -0
  257. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  258. package/dist/src/storage/storage-repo.d.ts +53 -2
  259. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  260. package/dist/src/storage/storage-repo.js +193 -9
  261. package/dist/src/storage/storage-repo.js.map +1 -1
  262. package/dist/src/sync/client.d.ts +4 -1
  263. package/dist/src/sync/client.d.ts.map +1 -1
  264. package/dist/src/sync/client.js +5 -2
  265. package/dist/src/sync/client.js.map +1 -1
  266. package/dist/src/testing/cohort-topic-mesh-harness.d.ts +219 -0
  267. package/dist/src/testing/cohort-topic-mesh-harness.d.ts.map +1 -0
  268. package/dist/src/testing/cohort-topic-mesh-harness.js +467 -0
  269. package/dist/src/testing/cohort-topic-mesh-harness.js.map +1 -0
  270. package/dist/src/testing/matchmaking-mesh-harness.d.ts +187 -0
  271. package/dist/src/testing/matchmaking-mesh-harness.d.ts.map +1 -0
  272. package/dist/src/testing/matchmaking-mesh-harness.js +358 -0
  273. package/dist/src/testing/matchmaking-mesh-harness.js.map +1 -0
  274. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  275. package/dist/src/testing/mesh-harness.js +23 -1
  276. package/dist/src/testing/mesh-harness.js.map +1 -1
  277. package/dist/src/testing/reactivity-mesh-harness.d.ts +298 -0
  278. package/dist/src/testing/reactivity-mesh-harness.d.ts.map +1 -0
  279. package/dist/src/testing/reactivity-mesh-harness.js +663 -0
  280. package/dist/src/testing/reactivity-mesh-harness.js.map +1 -0
  281. package/package.json +7 -4
  282. package/src/cluster/block-transfer-service.ts +133 -68
  283. package/src/cluster/client.ts +64 -45
  284. package/src/cluster/cluster-error.ts +64 -0
  285. package/src/cluster/cluster-repo.ts +405 -55
  286. package/src/cluster/commit-cert.ts +139 -0
  287. package/src/cluster/service.ts +116 -44
  288. package/src/cluster/spread-on-churn.ts +328 -285
  289. package/src/cohort-topic/bootstrap-evidence-builder.ts +122 -0
  290. package/src/cohort-topic/bootstrap-evidence-verifiers.ts +132 -0
  291. package/src/cohort-topic/bootstrap-parent-reference.ts +159 -0
  292. package/src/cohort-topic/change-bridge.ts +109 -0
  293. package/src/cohort-topic/cohort-gossip-driver.ts +144 -0
  294. package/src/cohort-topic/cohort-gossip-transport.ts +74 -0
  295. package/src/cohort-topic/fret-trust-anchor.ts +153 -0
  296. package/src/cohort-topic/host.ts +2175 -0
  297. package/src/cohort-topic/index.ts +13 -0
  298. package/src/cohort-topic/membership-publish-sink.ts +20 -0
  299. package/src/cohort-topic/membership-source.ts +68 -0
  300. package/src/cohort-topic/peer-codec.ts +31 -0
  301. package/src/cohort-topic/peer-sig.ts +86 -0
  302. package/src/cohort-topic/protocols.ts +71 -0
  303. package/src/cohort-topic/reactivity-membership-gate.ts +77 -0
  304. package/src/cohort-topic/size-estimator.ts +16 -0
  305. package/src/cohort-topic/stream-util.ts +87 -0
  306. package/src/cohort-topic/threshold-crypto.ts +239 -0
  307. package/src/cohort-topic/topic-router.ts +77 -0
  308. package/src/dispute/cascade.ts +517 -0
  309. package/src/dispute/client.ts +12 -2
  310. package/src/dispute/dispute-service.ts +171 -24
  311. package/src/dispute/index.ts +42 -0
  312. package/src/dispute/invalidation.ts +587 -0
  313. package/src/dispute/types.ts +14 -0
  314. package/src/index.ts +4 -0
  315. package/src/libp2p-key-network.ts +67 -9
  316. package/src/libp2p-node-base.ts +633 -14
  317. package/src/matchmaking/aggregate-counts.ts +104 -0
  318. package/src/matchmaking/index.ts +20 -0
  319. package/src/matchmaking/module.ts +363 -0
  320. package/src/matchmaking/protocols.ts +51 -0
  321. package/src/matchmaking/provider-manager.ts +95 -0
  322. package/src/matchmaking/query-handler.ts +88 -0
  323. package/src/matchmaking/query-transport.ts +483 -0
  324. package/src/matchmaking/seeker-manager.ts +64 -0
  325. package/src/matchmaking/seeker-walk-client.ts +293 -0
  326. package/src/matchmaking/traffic-validation.ts +195 -0
  327. package/src/network/network-manager-service.ts +9 -2
  328. package/src/protocol-client.ts +119 -5
  329. package/src/reactivity/forwarder-host.ts +438 -0
  330. package/src/reactivity/index.ts +19 -0
  331. package/src/reactivity/notify-transport.ts +144 -0
  332. package/src/reactivity/origination-manager.ts +192 -0
  333. package/src/reactivity/protocols.ts +61 -0
  334. package/src/reactivity/push-state-gossip.ts +291 -0
  335. package/src/reactivity/recover-transport.ts +408 -0
  336. package/src/reactivity/rotation-rereg-scheduler.ts +256 -0
  337. package/src/reactivity/subscriber-registry.ts +96 -0
  338. package/src/reactivity/subscription-manager.ts +450 -0
  339. package/src/reactivity/topic-bytes.ts +37 -0
  340. package/src/repo/client.ts +54 -19
  341. package/src/repo/cluster-coordinator.ts +66 -26
  342. package/src/repo/coordinator-repo.ts +99 -15
  343. package/src/repo/service.ts +90 -42
  344. package/src/rpc-deadline.ts +45 -0
  345. package/src/storage/block-storage.ts +106 -3
  346. package/src/storage/i-block-storage.ts +27 -0
  347. package/src/storage/storage-repo.ts +209 -13
  348. package/src/sync/client.ts +5 -2
  349. package/src/testing/cohort-topic-mesh-harness.ts +613 -0
  350. package/src/testing/matchmaking-mesh-harness.ts +475 -0
  351. package/src/testing/mesh-harness.ts +22 -2
  352. package/src/testing/reactivity-mesh-harness.ts +922 -0
@@ -1,285 +1,328 @@
1
- import type { Startable, Libp2p } from '@libp2p/interface'
2
- import type { IRepo, IPeerNetwork } from '@optimystic/db-core'
3
- import { hashKey } from 'p2p-fret'
4
- import type { FretService } from 'p2p-fret'
5
- import { peerIdFromString } from '@libp2p/peer-id'
6
- import type { PartitionDetector } from './partition-detector.js'
7
- import { BlockTransferClient } from './block-transfer-service.js'
8
- import { createLogger } from '../logger.js'
9
-
10
- const log = createLogger('spread-on-churn')
11
- const textEncoder = new TextEncoder()
12
-
13
- // ── Types ────────────────────────────────────────────────────────────
14
-
15
- export interface SpreadOnChurnConfig {
16
- /** Enable the churn-resilient spread protocol. Default: true */
17
- enabled: boolean
18
- /** Number of middle-closest peers eligible to spread (d). Default: 3 */
19
- spreadDistance: number
20
- /** Enable dynamic d scaling based on cluster health. Default: true */
21
- dynamicSpreadDistance: boolean
22
- /** Cluster size ratio below which spread becomes more aggressive. Default: 0.6 */
23
- healthThreshold: number
24
- /** Debounce window for departure detection (ms). Default: 5000 */
25
- departureDebounceMs: number
26
- /** Number of peers beyond cluster boundary to target. Default: 4 */
27
- expansionStep: number
28
- }
29
-
30
- export interface SpreadOnChurnDeps {
31
- libp2p: Libp2p
32
- fret: FretService
33
- partitionDetector: PartitionDetector
34
- repo: IRepo
35
- peerNetwork: IPeerNetwork
36
- clusterSize: number
37
- protocolPrefix?: string
38
- }
39
-
40
- export interface SpreadEvent {
41
- /** Blocks that were spread */
42
- spread: Array<{
43
- blockId: string
44
- targets: string[]
45
- succeeded: string[]
46
- failed: string[]
47
- }>
48
- /** Current effective d */
49
- effectiveD: number
50
- /** Timestamp of the departure that triggered this */
51
- triggeredAt: number
52
- }
53
-
54
- type SpreadHandler = (event: SpreadEvent) => void
55
-
56
- // ── Defaults ─────────────────────────────────────────────────────────
57
-
58
- const DEFAULT_CONFIG: SpreadOnChurnConfig = {
59
- enabled: true,
60
- spreadDistance: 3,
61
- dynamicSpreadDistance: true,
62
- healthThreshold: 0.6,
63
- departureDebounceMs: 5000,
64
- expansionStep: 4,
65
- }
66
-
67
- // ── Monitor ──────────────────────────────────────────────────────────
68
-
69
- export class SpreadOnChurnMonitor implements Startable {
70
- private running = false
71
- private readonly trackedBlocks = new Set<string>()
72
- private readonly handlers: SpreadHandler[] = []
73
- private debounceTimer: ReturnType<typeof setTimeout> | null = null
74
- private departureTimestamps: number[] = []
75
- private departureTimestamp = 0
76
-
77
- private readonly config: SpreadOnChurnConfig
78
- private readonly onConnectionClose: () => void
79
-
80
- constructor(
81
- private readonly deps: SpreadOnChurnDeps,
82
- config: Partial<SpreadOnChurnConfig> = {}
83
- ) {
84
- this.config = { ...DEFAULT_CONFIG, ...config }
85
- this.onConnectionClose = () => this.handleDeparture()
86
- }
87
-
88
- // ── Startable ────────────────────────────────────────────────────
89
-
90
- async start(): Promise<void> {
91
- if (this.running) return
92
- this.running = true
93
-
94
- this.deps.libp2p.addEventListener('connection:close', this.onConnectionClose)
95
-
96
- log('started, tracking %d blocks', this.trackedBlocks.size)
97
- }
98
-
99
- async stop(): Promise<void> {
100
- if (!this.running) return
101
- this.running = false
102
-
103
- this.deps.libp2p.removeEventListener('connection:close', this.onConnectionClose)
104
-
105
- if (this.debounceTimer) {
106
- clearTimeout(this.debounceTimer)
107
- this.debounceTimer = null
108
- }
109
-
110
- log('stopped')
111
- }
112
-
113
- // ── Public API ───────────────────────────────────────────────────
114
-
115
- onSpread(handler: SpreadHandler): void {
116
- this.handlers.push(handler)
117
- }
118
-
119
- trackBlock(blockId: string): void {
120
- this.trackedBlocks.add(blockId)
121
- }
122
-
123
- untrackBlock(blockId: string): void {
124
- this.trackedBlocks.delete(blockId)
125
- }
126
-
127
- getTrackedBlockCount(): number {
128
- return this.trackedBlocks.size
129
- }
130
-
131
- /** Force an immediate spread check (useful for testing). */
132
- async checkNow(): Promise<SpreadEvent | null> {
133
- return this.performSpread(Date.now())
134
- }
135
-
136
- // ── Internal ─────────────────────────────────────────────────────
137
-
138
- private handleDeparture(): void {
139
- if (!this.running) return
140
- if (!this.config.enabled) return
141
-
142
- if (!this.departureTimestamp) {
143
- this.departureTimestamp = Date.now()
144
- }
145
-
146
- // Record for dynamic-d sliding window
147
- this.departureTimestamps.push(Date.now())
148
-
149
- if (this.debounceTimer) {
150
- clearTimeout(this.debounceTimer)
151
- }
152
-
153
- this.debounceTimer = setTimeout(() => {
154
- this.debounceTimer = null
155
- const ts = this.departureTimestamp
156
- this.departureTimestamp = 0
157
- if (this.running) {
158
- this.performSpread(ts).catch(err => {
159
- log('spread error: %O', err)
160
- })
161
- }
162
- }, this.config.departureDebounceMs)
163
- }
164
-
165
- private async performSpread(triggeredAt: number): Promise<SpreadEvent | null> {
166
- if (!this.config.enabled) return null
167
-
168
- if (this.deps.partitionDetector.detectPartition()) {
169
- log('partition detected, suppressing spread')
170
- return null
171
- }
172
-
173
- if (this.trackedBlocks.size === 0) return null
174
-
175
- const selfId = this.deps.libp2p.peerId.toString()
176
- const effectiveD = this.computeEffectiveD()
177
- const spreadResults: SpreadEvent['spread'] = []
178
-
179
- for (const blockId of this.trackedBlocks) {
180
- const key = textEncoder.encode(blockId)
181
- const coord = await hashKey(key)
182
-
183
- // Check eligibility: only middle peers spread
184
- const rank = this.deps.fret.neighborDistance(selfId, coord, this.deps.clusterSize)
185
- if (rank >= effectiveD) continue
186
-
187
- // Get current cohort and expansion targets
188
- const cohort = this.deps.fret.assembleCohort(coord, this.deps.clusterSize)
189
- const cohortSet = new Set(cohort)
190
- const expanded = this.deps.fret.expandCohort(
191
- cohort, coord, this.config.expansionStep
192
- )
193
- const targets = expanded.filter(id => !cohortSet.has(id) && id !== selfId)
194
- if (targets.length === 0) continue
195
-
196
- // Read block data from local storage
197
- const result = await this.deps.repo.get({ blockIds: [blockId] })
198
- const blockResult = result[blockId]
199
- if (!blockResult?.block) {
200
- log('no-local-data block=%s', blockId)
201
- continue
202
- }
203
-
204
- const blockData = textEncoder.encode(JSON.stringify(blockResult.block))
205
-
206
- // Push to each target
207
- const succeeded: string[] = []
208
- const failed: string[] = []
209
-
210
- for (const targetId of targets) {
211
- try {
212
- const peerId = peerIdFromString(targetId)
213
- const client = new BlockTransferClient(
214
- peerId,
215
- this.deps.peerNetwork,
216
- this.deps.protocolPrefix
217
- )
218
- await client.pushBlocks([blockId], [blockData], 'replication')
219
- succeeded.push(targetId)
220
- log('push:ok block=%s target=%s', blockId, targetId)
221
- } catch (err) {
222
- failed.push(targetId)
223
- log('push:fail block=%s target=%s err=%s',
224
- blockId, targetId, (err as Error).message)
225
- }
226
- }
227
-
228
- spreadResults.push({ blockId, targets, succeeded, failed })
229
- }
230
-
231
- if (spreadResults.length === 0) return null
232
-
233
- const event: SpreadEvent = {
234
- spread: spreadResults,
235
- effectiveD,
236
- triggeredAt,
237
- }
238
-
239
- this.emitEvent(event)
240
- return event
241
- }
242
-
243
- private computeEffectiveD(): number {
244
- const d = this.config.spreadDistance
245
- if (!this.config.dynamicSpreadDistance) return d
246
-
247
- const maxD = Math.max(d, Math.floor(this.deps.clusterSize / 2))
248
- const windowMs = this.config.departureDebounceMs * 4
249
- const now = Date.now()
250
-
251
- // Prune old departure timestamps
252
- this.departureTimestamps = this.departureTimestamps.filter(
253
- ts => now - ts < windowMs
254
- )
255
-
256
- // Rapid churn: 3+ departures in window increase d by 1
257
- if (this.departureTimestamps.length >= 3) {
258
- return Math.min(d + 1, maxD)
259
- }
260
-
261
- // Low cluster health: observed cohort shrunk relative to expected
262
- // We approximate observed cohort size from FRET diagnostics
263
- const diag: any = (this.deps.fret as any).getDiagnostics?.()
264
- const estimate = diag?.estimate ?? diag?.n
265
- if (typeof estimate === 'number' && Number.isFinite(estimate) && estimate > 0) {
266
- const ratio = estimate / this.deps.clusterSize
267
- if (ratio < this.config.healthThreshold) {
268
- const scaled = Math.ceil(d * (this.deps.clusterSize / estimate))
269
- return Math.min(scaled, maxD)
270
- }
271
- }
272
-
273
- return d
274
- }
275
-
276
- private emitEvent(event: SpreadEvent): void {
277
- for (const handler of this.handlers) {
278
- try {
279
- handler(event)
280
- } catch (err) {
281
- log('handler error: %O', err)
282
- }
283
- }
284
- }
285
- }
1
+ import type { Startable, Libp2p } from '@libp2p/interface'
2
+ import type { IRepo, IPeerNetwork } from '@optimystic/db-core'
3
+ import { hashKey } from 'p2p-fret'
4
+ import type { FretService } from 'p2p-fret'
5
+ import { peerIdFromString } from '@libp2p/peer-id'
6
+ import type { PartitionDetector } from './partition-detector.js'
7
+ import { BlockTransferClient } from './block-transfer-service.js'
8
+ import { createLogger } from '../logger.js'
9
+
10
+ const log = createLogger('spread-on-churn')
11
+ const textEncoder = new TextEncoder()
12
+
13
+ // ── Types ────────────────────────────────────────────────────────────
14
+
15
+ export interface SpreadOnChurnConfig {
16
+ /** Enable the churn-resilient spread protocol. Default: true */
17
+ enabled: boolean
18
+ /** Number of middle-closest peers eligible to spread (d). Default: 3 */
19
+ spreadDistance: number
20
+ /** Enable dynamic d scaling based on cluster health. Default: true */
21
+ dynamicSpreadDistance: boolean
22
+ /** Cluster size ratio below which spread becomes more aggressive. Default: 0.6 */
23
+ healthThreshold: number
24
+ /** Debounce window for departure detection (ms). Default: 5000 */
25
+ departureDebounceMs: number
26
+ /** Number of peers beyond cluster boundary to target. Default: 4 */
27
+ expansionStep: number
28
+ /**
29
+ * Per-target dial deadline (ms) for churn pushes. A target that never accepts
30
+ * the connection fails fast instead of stalling the sequential spread pass.
31
+ * Default: 3000 (matches the codebase's other dial caps).
32
+ */
33
+ pushDialTimeoutMs: number
34
+ /**
35
+ * Per-target response deadline (ms) for churn pushes. A target that dials OK but
36
+ * never replies (connects, then goes silent) is given up on — the push throws
37
+ * `ResponseTimeoutError`, is recorded as failed, and the loop continues to the
38
+ * next target/block rather than hanging the whole pass. Default: 10000.
39
+ */
40
+ pushResponseTimeoutMs: number
41
+ }
42
+
43
+ export interface SpreadOnChurnDeps {
44
+ libp2p: Libp2p
45
+ fret: FretService
46
+ partitionDetector: PartitionDetector
47
+ repo: IRepo
48
+ peerNetwork: IPeerNetwork
49
+ clusterSize: number
50
+ protocolPrefix?: string
51
+ }
52
+
53
+ export interface SpreadEvent {
54
+ /** Blocks that were spread */
55
+ spread: Array<{
56
+ blockId: string
57
+ targets: string[]
58
+ succeeded: string[]
59
+ failed: string[]
60
+ }>
61
+ /** Current effective d */
62
+ effectiveD: number
63
+ /** Timestamp of the departure that triggered this */
64
+ triggeredAt: number
65
+ }
66
+
67
+ type SpreadHandler = (event: SpreadEvent) => void
68
+
69
+ // ── Defaults ─────────────────────────────────────────────────────────
70
+
71
+ const DEFAULT_CONFIG: SpreadOnChurnConfig = {
72
+ enabled: true,
73
+ spreadDistance: 3,
74
+ dynamicSpreadDistance: true,
75
+ healthThreshold: 0.6,
76
+ departureDebounceMs: 5000,
77
+ expansionStep: 4,
78
+ pushDialTimeoutMs: 3000,
79
+ pushResponseTimeoutMs: 10000,
80
+ }
81
+
82
+ // ── Monitor ──────────────────────────────────────────────────────────
83
+
84
+ export class SpreadOnChurnMonitor implements Startable {
85
+ private running = false
86
+ private readonly trackedBlocks = new Set<string>()
87
+ private readonly handlers: SpreadHandler[] = []
88
+ private debounceTimer: ReturnType<typeof setTimeout> | null = null
89
+ private departureTimestamps: number[] = []
90
+ private departureTimestamp = 0
91
+
92
+ private readonly config: SpreadOnChurnConfig
93
+ private readonly onConnectionClose: () => void
94
+
95
+ constructor(
96
+ private readonly deps: SpreadOnChurnDeps,
97
+ config: Partial<SpreadOnChurnConfig> = {}
98
+ ) {
99
+ this.config = { ...DEFAULT_CONFIG, ...config }
100
+ this.onConnectionClose = () => this.handleDeparture()
101
+ }
102
+
103
+ // ── Startable ────────────────────────────────────────────────────
104
+
105
+ async start(): Promise<void> {
106
+ if (this.running) return
107
+ this.running = true
108
+
109
+ this.deps.libp2p.addEventListener('connection:close', this.onConnectionClose)
110
+
111
+ log('started, tracking %d blocks', this.trackedBlocks.size)
112
+ }
113
+
114
+ async stop(): Promise<void> {
115
+ if (!this.running) return
116
+ this.running = false
117
+
118
+ this.deps.libp2p.removeEventListener('connection:close', this.onConnectionClose)
119
+
120
+ if (this.debounceTimer) {
121
+ clearTimeout(this.debounceTimer)
122
+ this.debounceTimer = null
123
+ }
124
+
125
+ log('stopped')
126
+ }
127
+
128
+ // ── Public API ───────────────────────────────────────────────────
129
+
130
+ onSpread(handler: SpreadHandler): void {
131
+ this.handlers.push(handler)
132
+ }
133
+
134
+ trackBlock(blockId: string): void {
135
+ this.trackedBlocks.add(blockId)
136
+ }
137
+
138
+ untrackBlock(blockId: string): void {
139
+ this.trackedBlocks.delete(blockId)
140
+ }
141
+
142
+ getTrackedBlockCount(): number {
143
+ return this.trackedBlocks.size
144
+ }
145
+
146
+ /** Force an immediate spread check (useful for testing). */
147
+ async checkNow(): Promise<SpreadEvent | null> {
148
+ return this.performSpread(Date.now())
149
+ }
150
+
151
+ // ── Internal ─────────────────────────────────────────────────────
152
+
153
+ private handleDeparture(): void {
154
+ if (!this.running) return
155
+ if (!this.config.enabled) return
156
+
157
+ if (!this.departureTimestamp) {
158
+ this.departureTimestamp = Date.now()
159
+ }
160
+
161
+ // Record for dynamic-d sliding window
162
+ this.departureTimestamps.push(Date.now())
163
+
164
+ if (this.debounceTimer) {
165
+ clearTimeout(this.debounceTimer)
166
+ }
167
+
168
+ this.debounceTimer = setTimeout(() => {
169
+ this.debounceTimer = null
170
+ const ts = this.departureTimestamp
171
+ this.departureTimestamp = 0
172
+ if (this.running) {
173
+ this.performSpread(ts).catch(err => {
174
+ log('spread error: %O', err)
175
+ })
176
+ }
177
+ }, this.config.departureDebounceMs)
178
+ }
179
+
180
+ private async performSpread(triggeredAt: number): Promise<SpreadEvent | null> {
181
+ if (!this.config.enabled) return null
182
+
183
+ if (this.deps.partitionDetector.detectPartition()) {
184
+ log('partition detected, suppressing spread')
185
+ return null
186
+ }
187
+
188
+ if (this.trackedBlocks.size === 0) return null
189
+
190
+ const selfId = this.deps.libp2p.peerId.toString()
191
+ const effectiveD = this.computeEffectiveD()
192
+ const spreadResults: SpreadEvent['spread'] = []
193
+
194
+ for (const blockId of this.trackedBlocks) {
195
+ const key = textEncoder.encode(blockId)
196
+ const coord = await hashKey(key)
197
+
198
+ // Check eligibility: only middle peers spread
199
+ const rank = this.deps.fret.neighborDistance(selfId, coord, this.deps.clusterSize)
200
+ if (rank >= effectiveD) continue
201
+
202
+ // Get current cohort and expansion targets
203
+ const cohort = this.deps.fret.assembleCohort(coord, this.deps.clusterSize)
204
+ const cohortSet = new Set(cohort)
205
+ const expanded = this.deps.fret.expandCohort(
206
+ cohort, coord, this.config.expansionStep
207
+ )
208
+ const targets = expanded.filter(id => !cohortSet.has(id) && id !== selfId)
209
+ if (targets.length === 0) continue
210
+
211
+ // Read block data from local storage
212
+ const result = await this.deps.repo.get({ blockIds: [blockId] })
213
+ const blockResult = result[blockId]
214
+ if (!blockResult?.block) {
215
+ // The block has left local storage. No deletion event exists today to evict it
216
+ // from the tracked set, so prune here. Deleting the current element of a Set mid
217
+ // for...of is safe - it does not disturb the rest of the iteration. A later
218
+ // re-commit re-adds the block via the owned-block feed.
219
+ log('no-local-data block=%s (untracking)', blockId)
220
+ this.trackedBlocks.delete(blockId)
221
+ continue
222
+ }
223
+
224
+ const blockData = textEncoder.encode(JSON.stringify(blockResult.block))
225
+
226
+ // Carry the source's revision metadata so the replica's `latest` matches the
227
+ // source instead of being fabricated as rev 1 on the receiver.
228
+ const latest = blockResult.state?.latest
229
+ const blockMeta = latest
230
+ ? { [blockId]: { rev: latest.rev, actionId: latest.actionId } }
231
+ : undefined
232
+
233
+ // Push to each target
234
+ const succeeded: string[] = []
235
+ const failed: string[] = []
236
+
237
+ for (const targetId of targets) {
238
+ try {
239
+ const peerId = peerIdFromString(targetId)
240
+ const client = new BlockTransferClient(
241
+ peerId,
242
+ this.deps.peerNetwork,
243
+ this.deps.protocolPrefix
244
+ )
245
+ // Bound both the dial and the response read. A target that connects but
246
+ // never replies would otherwise hang this sequential loop forever during
247
+ // churn (exactly when slow/dying peers are common); the deadline makes the
248
+ // push throw, which the catch below records as `failed` so the pass advances.
249
+ const response = await client.pushBlocks([blockId], [blockData], 'replication', blockMeta, {
250
+ dialTimeoutMs: this.config.pushDialTimeoutMs,
251
+ responseTimeoutMs: this.config.pushResponseTimeoutMs,
252
+ })
253
+ // A round-trip that does not throw still does not mean the replica
254
+ // landed: handlePush reports a block in `missing` when it could not
255
+ // parse or persist it. Treat that as a failed push so the resilience
256
+ // mechanism does not falsely count the new owner as holding the block.
257
+ if (response.missing.includes(blockId)) {
258
+ failed.push(targetId)
259
+ log('push:rejected block=%s target=%s (receiver did not persist)', blockId, targetId)
260
+ } else {
261
+ succeeded.push(targetId)
262
+ log('push:ok block=%s target=%s', blockId, targetId)
263
+ }
264
+ } catch (err) {
265
+ failed.push(targetId)
266
+ log('push:fail block=%s target=%s err=%s',
267
+ blockId, targetId, (err as Error).message)
268
+ }
269
+ }
270
+
271
+ spreadResults.push({ blockId, targets, succeeded, failed })
272
+ }
273
+
274
+ if (spreadResults.length === 0) return null
275
+
276
+ const event: SpreadEvent = {
277
+ spread: spreadResults,
278
+ effectiveD,
279
+ triggeredAt,
280
+ }
281
+
282
+ this.emitEvent(event)
283
+ return event
284
+ }
285
+
286
+ private computeEffectiveD(): number {
287
+ const d = this.config.spreadDistance
288
+ if (!this.config.dynamicSpreadDistance) return d
289
+
290
+ const maxD = Math.max(d, Math.floor(this.deps.clusterSize / 2))
291
+ const windowMs = this.config.departureDebounceMs * 4
292
+ const now = Date.now()
293
+
294
+ // Prune old departure timestamps
295
+ this.departureTimestamps = this.departureTimestamps.filter(
296
+ ts => now - ts < windowMs
297
+ )
298
+
299
+ // Rapid churn: 3+ departures in window → increase d by 1
300
+ if (this.departureTimestamps.length >= 3) {
301
+ return Math.min(d + 1, maxD)
302
+ }
303
+
304
+ // Low cluster health: observed cohort shrunk relative to expected
305
+ // We approximate observed cohort size from FRET diagnostics
306
+ const diag: any = (this.deps.fret as any).getDiagnostics?.()
307
+ const estimate = diag?.estimate ?? diag?.n
308
+ if (typeof estimate === 'number' && Number.isFinite(estimate) && estimate > 0) {
309
+ const ratio = estimate / this.deps.clusterSize
310
+ if (ratio < this.config.healthThreshold) {
311
+ const scaled = Math.ceil(d * (this.deps.clusterSize / estimate))
312
+ return Math.min(scaled, maxD)
313
+ }
314
+ }
315
+
316
+ return d
317
+ }
318
+
319
+ private emitEvent(event: SpreadEvent): void {
320
+ for (const handler of this.handlers) {
321
+ try {
322
+ handler(event)
323
+ } catch (err) {
324
+ log('handler error: %O', err)
325
+ }
326
+ }
327
+ }
328
+ }