@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,13 @@
1
+ export * from "./protocols.js";
2
+ export * from "./peer-codec.js";
3
+ export * from "./peer-sig.js";
4
+ export * from "./stream-util.js";
5
+ export * from "./topic-router.js";
6
+ export * from "./cohort-gossip-transport.js";
7
+ export * from "./cohort-gossip-driver.js";
8
+ export * from "./membership-source.js";
9
+ export * from "./membership-publish-sink.js";
10
+ export * from "./threshold-crypto.js";
11
+ export * from "./size-estimator.js";
12
+ export * from "./host.js";
13
+ export * from "./change-bridge.js";
@@ -0,0 +1,20 @@
1
+ import type { IMembershipPublishSink } from "@optimystic/db-core";
2
+
3
+ /**
4
+ * FRET-backed {@link IMembershipPublishSink}: holds the cohort's latest threshold-signed
5
+ * `MembershipCertV1` (already encoded) and serves it over `/optimystic/cohort-topic/1.0.0/membership`.
6
+ * A node publishes only its own cohort's cert, so the most-recent encoded cert is all the host's
7
+ * membership protocol handler needs to answer inbound requests.
8
+ */
9
+ export class FretMembershipPublishSink implements IMembershipPublishSink {
10
+ private latestCert: Uint8Array | undefined;
11
+
12
+ publish(encodedCert: Uint8Array): void {
13
+ this.latestCert = encodedCert;
14
+ }
15
+
16
+ /** The most recently published encoded cert, or `undefined` if none yet (host serves this). */
17
+ latest(): Uint8Array | undefined {
18
+ return this.latestCert;
19
+ }
20
+ }
@@ -0,0 +1,68 @@
1
+ import type { IMembershipSource, RingCoord } from "@optimystic/db-core";
2
+ import { bytesToB64url } from "@optimystic/db-core";
3
+ import { peerIdFromString } from "@libp2p/peer-id";
4
+ import type { Libp2p } from "libp2p";
5
+ import type { CohortPeerResolver } from "./cohort-gossip-transport.js";
6
+ import { requestResponse, DEFAULT_STREAM_MAX_BYTES } from "./stream-util.js";
7
+ import { PROTOCOL_COHORT_MEMBERSHIP } from "./protocols.js";
8
+
9
+ export interface FretMembershipSourceOptions {
10
+ readonly membershipProtocol?: string;
11
+ /** Cohort fan-out probed on a `fetch`. Default 16. */
12
+ readonly wants?: number;
13
+ readonly maxBytes?: number;
14
+ }
15
+
16
+ /**
17
+ * FRET-backed {@link IMembershipSource}: cohort membership snapshots over
18
+ * `/optimystic/cohort-topic/1.0.0/membership`. `current` serves the locally-cached encoded
19
+ * `MembershipCertV1`; `fetch` forces one refresh by requesting the cert from an assembled cohort
20
+ * member (the stale-cache retry the participant-side verifier drives). The host feeds inbound certs
21
+ * into the cache via {@link cache}.
22
+ */
23
+ export class FretMembershipSource implements IMembershipSource {
24
+ private readonly byCoord = new Map<string, Uint8Array>();
25
+ private readonly membershipProtocol: string;
26
+ private readonly wants: number;
27
+ private readonly maxBytes: number;
28
+
29
+ constructor(private readonly node: Libp2p, private readonly resolver: CohortPeerResolver, options: FretMembershipSourceOptions = {}) {
30
+ this.membershipProtocol = options.membershipProtocol ?? PROTOCOL_COHORT_MEMBERSHIP;
31
+ this.wants = options.wants ?? 16;
32
+ this.maxBytes = options.maxBytes ?? DEFAULT_STREAM_MAX_BYTES;
33
+ }
34
+
35
+ current(coord: RingCoord): Promise<Uint8Array | undefined> {
36
+ return Promise.resolve(this.byCoord.get(bytesToB64url(coord)));
37
+ }
38
+
39
+ /**
40
+ * Synchronous local existence read over the in-memory cache: true iff a `MembershipCertV1` is cached for
41
+ * `coord` (no network I/O). The parent-reference bootstrap-evidence verifier's existence view consults
42
+ * this — an admission gate must never dial — so it reads the same `byCoord` map `current()` resolves from.
43
+ */
44
+ has(coord: RingCoord): boolean {
45
+ return this.byCoord.has(bytesToB64url(coord));
46
+ }
47
+
48
+ async fetch(coord: RingCoord): Promise<Uint8Array | undefined> {
49
+ const request = coord; // the membership request frame is the raw coord bytes
50
+ for (const peerStr of this.resolver.cohortPeers(coord, this.wants)) {
51
+ try {
52
+ const reply = await requestResponse(this.node, peerIdFromString(peerStr), this.membershipProtocol, request, this.maxBytes);
53
+ if (reply.length > 0) {
54
+ this.cache(coord, reply);
55
+ return reply;
56
+ }
57
+ } catch {
58
+ // Try the next member; a stale-cache refetch tolerates an unreachable holder.
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+
64
+ /** Cache an encoded cert for its coord (host feeds inbound/served certs here). */
65
+ cache(coord: RingCoord, encodedCert: Uint8Array): void {
66
+ this.byCoord.set(bytesToB64url(coord), encodedCert);
67
+ }
68
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Cohort-topic peer-id ↔ bytes bridge.
3
+ *
4
+ * db-core's substrate logic references peers as opaque `Uint8Array` ids ({@link PeerRef}`.id`); FRET +
5
+ * libp2p reference them as `PeerId` / peer-id strings. The cohort-member ids the substrate carries on
6
+ * the wire (a reply's `primary` / `backups` / `cohortMembers`) must round-trip back to a *dialable*
7
+ * libp2p peer, so this module pins one unambiguous encoding for them: the UTF-8 bytes of the canonical
8
+ * peer-id string. (The participant's own addressing coordinate `P` is a separate ring-coord value — see
9
+ * the host — so this encoding never needs to feed the ring hash.)
10
+ */
11
+
12
+ import { peerIdFromString } from "@libp2p/peer-id";
13
+ import type { PeerId } from "@libp2p/interface";
14
+
15
+ const utf8Encoder = new TextEncoder();
16
+ const utf8Decoder = new TextDecoder("utf-8", { fatal: true });
17
+
18
+ /** A cohort-member id as the substrate's opaque bytes: UTF-8 of the canonical peer-id string. */
19
+ export function peerIdToBytes(peerId: PeerId | string): Uint8Array {
20
+ return utf8Encoder.encode(typeof peerId === "string" ? peerId : peerId.toString());
21
+ }
22
+
23
+ /** Reverse of {@link peerIdToBytes}: decode member bytes back to the canonical peer-id string. */
24
+ export function bytesToPeerIdString(bytes: Uint8Array): string {
25
+ return utf8Decoder.decode(bytes);
26
+ }
27
+
28
+ /** Reverse of {@link peerIdToBytes}: decode member bytes back to a dialable {@link PeerId}. */
29
+ export function bytesToPeerId(bytes: Uint8Array): PeerId {
30
+ return peerIdFromString(bytesToPeerIdString(bytes));
31
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Cohort-topic shared Ed25519 sign/verify primitive (libp2p peer keys).
3
+ *
4
+ * Mirrors the established peer-key signing pattern in `cluster-repo.ts` / `dispute-service.ts`
5
+ * (`PrivateKey.sign` → base64url; verify against the peer's public key), specialized for the
6
+ * cohort-topic substrate:
7
+ *
8
+ * - **Signing** uses the node's libp2p `PrivateKey.sign` (async — fine on the participant outbound
9
+ * path) and is the seam the threshold-assembly ticket reuses for per-member partial signatures.
10
+ * - **Verification is SYNCHRONOUS**, because the db-core verify ports (e.g. the participant-signature
11
+ * predicates and `ICohortThresholdCrypto.verify`) are synchronous. libp2p's
12
+ * `publicKeyFromRaw(raw).verify` is async, so this verifies with `@noble/curves/ed25519` directly
13
+ * over the raw 32-byte key. noble's `ed25519.verify` (ZIP215) is a strict superset of the RFC8032
14
+ * signatures the libp2p signer (Node/WebCrypto Ed25519) produces, so it accepts them.
15
+ *
16
+ * The signer id on the cohort wire is the UTF-8 bytes of the peer-id string (see `peer-codec.ts`).
17
+ * For an Ed25519 identity the public key is embedded in the identity multihash, so no network lookup
18
+ * is needed — `peerIdFromString(str).publicKey.raw` yields the raw key. Verification is **total**: any
19
+ * non-Ed25519 id, missing key, or malformed input returns `false` (it never throws). The cohort-topic
20
+ * substrate therefore assumes Ed25519 identities (the libp2p default; `generateKeyPair('Ed25519')`).
21
+ */
22
+
23
+ import type { PrivateKey } from "@libp2p/interface";
24
+ import { peerIdFromString } from "@libp2p/peer-id";
25
+ import { ed25519 } from "@noble/curves/ed25519.js";
26
+ import { bytesToPeerIdString } from "./peer-codec.js";
27
+
28
+ /** Sign `payload` with the node's libp2p peer key. Async — libp2p `PrivateKey.sign` is async. */
29
+ export async function signPeer(privateKey: PrivateKey, payload: Uint8Array): Promise<Uint8Array> {
30
+ return privateKey.sign(payload);
31
+ }
32
+
33
+ /**
34
+ * Sign `payload` with a libp2p Ed25519 peer key **synchronously** — the mirror of the synchronous
35
+ * {@link verifyPeerSig}. Use this where the signer seam is synchronous and the async {@link signPeer}
36
+ * cannot be awaited: e.g. the reactivity recover `signBackfill` / `signResume` `(unsigned) => string`
37
+ * ports, whose db-core driver builds the unsigned image internally (so a pre-signed value is impossible)
38
+ * and whose seam shape is `=> string`, not `=> Promise<string>`.
39
+ *
40
+ * libp2p's own `PrivateKey.sign` is async (Node / WebCrypto Ed25519), so this signs directly with
41
+ * `@noble/curves/ed25519` over the raw 32-byte seed. libp2p stores an Ed25519 private key as 64 bytes
42
+ * (`raw` = 32-byte seed ‖ 32-byte public key); noble's `ed25519.sign(message, secretKey)` takes the
43
+ * 32-byte seed. noble's signatures are RFC8032-compliant and deterministic, so both verify paths accept
44
+ * them: the libp2p `publicKeyFromRaw(raw).verify` (Node / WebCrypto) and the synchronous
45
+ * {@link verifyPeerSig} (noble, ZIP215) — symmetric with the verify direction's cross-acceptance, and
46
+ * byte-identical to what the async {@link signPeer} would produce for the same key + payload.
47
+ *
48
+ * Assumes an Ed25519 identity (the cohort-topic substrate's standing assumption). Throws on a
49
+ * non-Ed25519 key or an unexpected raw length — a programming error on the node's own key, never
50
+ * attacker-reachable input (the verify side, by contrast, is total and returns `false`).
51
+ */
52
+ export function signPeerSig(privateKey: PrivateKey, payload: Uint8Array): Uint8Array {
53
+ if (privateKey.type !== "Ed25519") {
54
+ throw new Error(`signPeerSig: expected an Ed25519 private key, got "${privateKey.type}"`);
55
+ }
56
+ const raw = privateKey.raw;
57
+ // 64-byte libp2p form = seed ‖ public key; accept a bare 32-byte seed too.
58
+ const seed = raw.length === 64 ? raw.subarray(0, 32) : raw;
59
+ if (seed.length !== 32) {
60
+ throw new Error(`signPeerSig: expected a 32- or 64-byte Ed25519 raw key, got ${raw.length} bytes`);
61
+ }
62
+ return ed25519.sign(payload, seed);
63
+ }
64
+
65
+ /**
66
+ * Verify an Ed25519 peer-key signature synchronously. `signer` is the cohort-wire member id — the
67
+ * UTF-8 bytes of the peer-id string (see {@link bytesToPeerIdString}) — or that peer-id string
68
+ * directly. Returns `false` (never throws) on a non-Ed25519 id, a missing/short key, a malformed
69
+ * signature, or any decode failure.
70
+ */
71
+ export function verifyPeerSig(signer: string | Uint8Array, payload: Uint8Array, sig: Uint8Array): boolean {
72
+ try {
73
+ const peerIdStr = typeof signer === "string" ? signer : bytesToPeerIdString(signer);
74
+ const peerId = peerIdFromString(peerIdStr);
75
+ if (peerId.type !== "Ed25519" || peerId.publicKey === undefined) {
76
+ return false;
77
+ }
78
+ const rawPub = peerId.publicKey.raw;
79
+ if (rawPub.length !== 32) {
80
+ return false;
81
+ }
82
+ return ed25519.verify(sig, payload, rawPub);
83
+ } catch {
84
+ return false;
85
+ }
86
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Cohort-topic libp2p protocol IDs (`docs/cohort-topic.md` §FRET integration L432-460).
3
+ *
4
+ * Five protocols ride the same FRET/libp2p node:
5
+ *
6
+ * - `register` — Register, renew, re-attach (`RegisterV1` / `RenewV1`, routed via `RouteAndMaybeAct`).
7
+ * - `cohort-gossip` — record replication, willingness, load barometers (`CohortGossipV1`).
8
+ * - `promote` — threshold-signed promotion / demotion notices.
9
+ * - `membership` — membership certificates (`MembershipCertV1`).
10
+ * - `sign` — intra-cohort per-member endorsement for `k − x` threshold-signature assembly
11
+ * (`SignRequestV1` / `SignReplyV1`); a member collecting a threshold signature dials
12
+ * each cohort member here and concatenates the returned per-member Ed25519 sigs.
13
+ *
14
+ * The default (network-agnostic) IDs match the doc verbatim; {@link makeCohortTopicProtocols}
15
+ * mirrors FRET's `makeProtocols(networkName)` so a named network namespaces its cohort-topic
16
+ * protocols the same way FRET namespaces its routing protocols.
17
+ */
18
+
19
+ /** Base path for the cohort-topic protocol family. */
20
+ export const COHORT_TOPIC_BASE = "/optimystic/cohort-topic/1.0.0" as const;
21
+
22
+ /** `RegisterV1` / `RenewV1` — register, renew, re-attach. */
23
+ export const PROTOCOL_COHORT_REGISTER = `${COHORT_TOPIC_BASE}/register` as const;
24
+ /** `CohortGossipV1` — record replication, willingness, load barometers. */
25
+ export const PROTOCOL_COHORT_GOSSIP = `${COHORT_TOPIC_BASE}/cohort-gossip` as const;
26
+ /** Threshold-signed promotion / demotion notices. */
27
+ export const PROTOCOL_COHORT_PROMOTE = `${COHORT_TOPIC_BASE}/promote` as const;
28
+ /** `MembershipCertV1` — membership certificates. */
29
+ export const PROTOCOL_COHORT_MEMBERSHIP = `${COHORT_TOPIC_BASE}/membership` as const;
30
+ /** `SignRequestV1` / `SignReplyV1` — intra-cohort per-member endorsement for threshold-signature assembly. */
31
+ export const PROTOCOL_COHORT_SIGN = `${COHORT_TOPIC_BASE}/sign` as const;
32
+
33
+ /** The five cohort-topic protocol IDs in registration order. */
34
+ export interface CohortTopicProtocols {
35
+ readonly register: string;
36
+ readonly gossip: string;
37
+ readonly promote: string;
38
+ readonly membership: string;
39
+ readonly sign: string;
40
+ }
41
+
42
+ /** Default (network-agnostic) protocol IDs, matching `docs/cohort-topic.md` §FRET integration. */
43
+ export const DEFAULT_COHORT_TOPIC_PROTOCOLS: CohortTopicProtocols = {
44
+ register: PROTOCOL_COHORT_REGISTER,
45
+ gossip: PROTOCOL_COHORT_GOSSIP,
46
+ promote: PROTOCOL_COHORT_PROMOTE,
47
+ membership: PROTOCOL_COHORT_MEMBERSHIP,
48
+ sign: PROTOCOL_COHORT_SIGN,
49
+ };
50
+
51
+ /**
52
+ * Namespaced cohort-topic protocol IDs for `networkName` (mirrors FRET's `makeProtocols`, which
53
+ * inserts the network segment even for `"default"` → `/optimystic/default/...`). Note this does NOT
54
+ * equal {@link DEFAULT_COHORT_TOPIC_PROTOCOLS}: the canonical, network-agnostic IDs omit the segment
55
+ * entirely (`/optimystic/cohort-topic/1.0.0/...`); use those unless you need per-network namespacing.
56
+ */
57
+ export function makeCohortTopicProtocols(networkName = "default"): CohortTopicProtocols {
58
+ const base = `/optimystic/${networkName}/cohort-topic/1.0.0`;
59
+ return {
60
+ register: `${base}/register`,
61
+ gossip: `${base}/cohort-gossip`,
62
+ promote: `${base}/promote`,
63
+ membership: `${base}/membership`,
64
+ sign: `${base}/sign`,
65
+ };
66
+ }
67
+
68
+ /** All five protocol IDs as an array (for `node.handle` / `unhandle` over the set). */
69
+ export function cohortTopicProtocolList(p: CohortTopicProtocols): string[] {
70
+ return [p.register, p.gossip, p.promote, p.membership, p.sign];
71
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Reactivity origination membership gate (`docs/reactivity.md` §Anchor, `docs/internals.md`
3
+ * §Cohort-Topic Origination Bridge).
4
+ *
5
+ * Builds the `selfIsCohortMember(event)` predicate the change-notifier bridge gates each member commit
6
+ * on: this node is responsible for a collection's reactivity-topic fan-out iff it sits in the FRET
7
+ * cohort around `coord_0(H(currentTailId ‖ "reactivity"))`. The tail comes from `event.tailId` (the seam
8
+ * ticket put the committed `CommitRequest.tailId` on the change event), so the decision is synchronous —
9
+ * no async storage read, no per-collection registry. A tail-less event (a read-driven promotion) is
10
+ * never a member; those never originate and are cert-gated out downstream anyway.
11
+ *
12
+ * Extracted from the node assembly so the encoding + coord derivation are unit-testable in isolation and
13
+ * reusable by the future reactivity origination wiring.
14
+ */
15
+
16
+ import {
17
+ createReactivityTopicAnchor,
18
+ createTierAddressing,
19
+ createRingHash,
20
+ type ReactivityTopicAnchor,
21
+ type TierAddressing,
22
+ type CollectionChangeEvent,
23
+ } from "@optimystic/db-core";
24
+ import type { FretService } from "p2p-fret";
25
+
26
+ // The pinned `BlockId` → raw tail-bytes encoding now lives in the reactivity surface so the origination
27
+ // gate (here) and the subscriber-side subscribe factory import the SAME function — see `reactivity/
28
+ // topic-bytes.ts` for the load-bearing rationale. Re-exported so this module's existing callers (tests,
29
+ // node wiring) keep importing `reactivityTailBytes` from the gate.
30
+ export { reactivityTailBytes } from "../reactivity/topic-bytes.js";
31
+ import { reactivityTailBytes } from "../reactivity/topic-bytes.js";
32
+
33
+ /** Construction inputs for {@link createReactivitySelfMembershipGate}. */
34
+ export interface ReactivitySelfMembershipGateDeps {
35
+ /** FRET membership read — the cohort assembler around a served coord (returns peer-id strings). */
36
+ readonly fret: Pick<FretService, "assembleCohort">;
37
+ /** This node's peer-id string, compared against the assembled cohort. */
38
+ readonly selfPeerId: string;
39
+ /**
40
+ * Requested cohort size `wantK`. MUST equal the cohort-topic host's `wantK`, so the gate checks the
41
+ * exact cohort the host serves; a mismatch silently breaks origination.
42
+ */
43
+ readonly wantK: number;
44
+ /**
45
+ * Reactivity topic anchor. Default db-core's {@link createReactivityTopicAnchor} (256-bit SHA-256),
46
+ * byte-identical to the host's internal `new RingHash()` and the subscriber-side anchor.
47
+ */
48
+ readonly anchor?: ReactivityTopicAnchor;
49
+ /**
50
+ * Tier addressing. Default `createTierAddressing(createRingHash())`. `coord_0` is fan-out independent
51
+ * (`H(0x00 ‖ topicId)`), so the default fan-out is irrelevant to the tier-0 reactivity coord.
52
+ */
53
+ readonly addressing?: TierAddressing;
54
+ }
55
+
56
+ /**
57
+ * Build the synchronous `selfIsCohortMember(event)` gate for {@link attachCohortChangeBridge}.
58
+ *
59
+ * Returns `false` for a tail-less event; otherwise resolves `coord_0(H(event.tailId ‖ "reactivity"))`
60
+ * via the shared anchor + tier addressing and returns whether `fret.assembleCohort(coord, wantK)`
61
+ * includes this node's peer id. Pure aside from the live FRET read; membership churn between commits is
62
+ * fine because reactivity is hint-only.
63
+ */
64
+ export function createReactivitySelfMembershipGate(
65
+ deps: ReactivitySelfMembershipGateDeps,
66
+ ): (event: CollectionChangeEvent) => boolean {
67
+ const anchor = deps.anchor ?? createReactivityTopicAnchor();
68
+ const addressing = deps.addressing ?? createTierAddressing(createRingHash());
69
+ return (event: CollectionChangeEvent): boolean => {
70
+ if (event.tailId === undefined) {
71
+ return false; // promotion / tail-less event never originates
72
+ }
73
+ const topicId = anchor.topicId(reactivityTailBytes(event.tailId));
74
+ const coord = addressing.coord0(topicId);
75
+ return deps.fret.assembleCohort(coord, deps.wantK).includes(deps.selfPeerId);
76
+ };
77
+ }
@@ -0,0 +1,16 @@
1
+ import type { ISizeEstimator } from "@optimystic/db-core";
2
+ import type { FretService } from "p2p-fret";
3
+
4
+ /**
5
+ * FRET-backed {@link ISizeEstimator}: feeds `d_max` from FRET's network-size estimate
6
+ * (`FretService.getNetworkSizeEstimate`). A clean, total binding — db-core's `d_max` computer applies
7
+ * the low-confidence clamp itself, so this adapter only forwards FRET's `(size_estimate, confidence)`.
8
+ */
9
+ export class FretSizeEstimator implements ISizeEstimator {
10
+ constructor(private readonly fret: FretService) {}
11
+
12
+ estimate(): { nEst: number; confidence: number } {
13
+ const { size_estimate, confidence } = this.fret.getNetworkSizeEstimate();
14
+ return { nEst: size_estimate, confidence };
15
+ }
16
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Cohort-topic libp2p stream helpers.
3
+ *
4
+ * The cohort-topic protocols exchange a single self-delimiting cohort frame each way (the db-core wire
5
+ * codec already length-prefixes the body), so request/response is one `send` + one bounded read. This
6
+ * mirrors FRET's `rpc/maybe-act.ts` exactly and reuses FRET's exported `readAllBounded`, keeping the
7
+ * stream lifecycle (open → send → close-write → read → close) consistent across both protocol families.
8
+ */
9
+
10
+ import type { Libp2p } from "libp2p";
11
+ import type { Connection, PeerId, Stream } from "@libp2p/interface";
12
+ import { readAllBounded } from "p2p-fret";
13
+
14
+ /** Default per-frame ceiling — matches FRET's 512 KiB maybe-act bound. */
15
+ export const DEFAULT_STREAM_MAX_BYTES = 512 * 1024;
16
+
17
+ /** Open `protocol` to `peer`, send `frame`, and read the bounded reply frame. */
18
+ export async function requestResponse(
19
+ node: Libp2p,
20
+ peer: PeerId,
21
+ protocol: string,
22
+ frame: Uint8Array,
23
+ maxBytes = DEFAULT_STREAM_MAX_BYTES,
24
+ ): Promise<Uint8Array> {
25
+ const conns = node.getConnections(peer);
26
+ let stream: Stream | undefined;
27
+ try {
28
+ stream = conns.length > 0 ? await conns[0]!.newStream([protocol]) : await node.dialProtocol(peer, [protocol]);
29
+ stream.send(frame);
30
+ await stream.close();
31
+ return await readAllBounded(stream, maxBytes);
32
+ } finally {
33
+ if (stream != null) {
34
+ try {
35
+ await stream.close();
36
+ } catch {
37
+ /* already closed */
38
+ }
39
+ }
40
+ }
41
+ }
42
+
43
+ /** Open `protocol` to `peer` and send `frame` without awaiting a reply (fire-and-forget gossip). */
44
+ export async function sendOneWay(node: Libp2p, peer: PeerId, protocol: string, frame: Uint8Array): Promise<void> {
45
+ const conns = node.getConnections(peer);
46
+ let stream: Stream | undefined;
47
+ try {
48
+ stream = conns.length > 0 ? await conns[0]!.newStream([protocol]) : await node.dialProtocol(peer, [protocol]);
49
+ stream.send(frame);
50
+ await stream.close();
51
+ } finally {
52
+ if (stream != null) {
53
+ try {
54
+ await stream.close();
55
+ } catch {
56
+ /* already closed */
57
+ }
58
+ }
59
+ }
60
+ }
61
+
62
+ /** Register a request/response handler for `protocol`: read one bounded frame, reply with one frame. */
63
+ export function handleRequestResponse(
64
+ node: Libp2p,
65
+ protocol: string,
66
+ handle: (frame: Uint8Array, from: PeerId) => Promise<Uint8Array | undefined>,
67
+ maxBytes = DEFAULT_STREAM_MAX_BYTES,
68
+ ): void {
69
+ void node.handle(protocol, (stream: Stream, connection: Connection) => {
70
+ void (async (): Promise<void> => {
71
+ try {
72
+ const frame = await readAllBounded(stream, maxBytes);
73
+ const reply = await handle(frame, connection.remotePeer);
74
+ if (reply !== undefined) {
75
+ stream.send(reply);
76
+ }
77
+ await stream.close();
78
+ } catch {
79
+ try {
80
+ stream.abort(new Error("cohort-topic stream handler error"));
81
+ } catch {
82
+ /* already aborted */
83
+ }
84
+ }
85
+ })();
86
+ });
87
+ }