@optimystic/db-p2p 0.24.1 → 0.25.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 (257) hide show
  1. package/{readme.md → README.md} +688 -668
  2. package/dist/src/cluster/block-transfer-service.d.ts +133 -10
  3. package/dist/src/cluster/block-transfer-service.d.ts.map +1 -1
  4. package/dist/src/cluster/block-transfer-service.js +155 -9
  5. package/dist/src/cluster/block-transfer-service.js.map +1 -1
  6. package/dist/src/cluster/block-transfer.d.ts +67 -7
  7. package/dist/src/cluster/block-transfer.d.ts.map +1 -1
  8. package/dist/src/cluster/block-transfer.js +127 -24
  9. package/dist/src/cluster/block-transfer.js.map +1 -1
  10. package/dist/src/cluster/certified-claims.d.ts +170 -0
  11. package/dist/src/cluster/certified-claims.d.ts.map +1 -0
  12. package/dist/src/cluster/certified-claims.js +200 -0
  13. package/dist/src/cluster/certified-claims.js.map +1 -0
  14. package/dist/src/cluster/client-signature-verifier.d.ts +23 -0
  15. package/dist/src/cluster/client-signature-verifier.d.ts.map +1 -0
  16. package/dist/src/cluster/client-signature-verifier.js +33 -0
  17. package/dist/src/cluster/client-signature-verifier.js.map +1 -0
  18. package/dist/src/cluster/cluster-policy.d.ts +9 -3
  19. package/dist/src/cluster/cluster-policy.d.ts.map +1 -1
  20. package/dist/src/cluster/cluster-policy.js +111 -27
  21. package/dist/src/cluster/cluster-policy.js.map +1 -1
  22. package/dist/src/cluster/cluster-repo.d.ts +140 -11
  23. package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
  24. package/dist/src/cluster/cluster-repo.js +485 -29
  25. package/dist/src/cluster/cluster-repo.js.map +1 -1
  26. package/dist/src/cluster/commit-proof.d.ts +134 -0
  27. package/dist/src/cluster/commit-proof.d.ts.map +1 -0
  28. package/dist/src/cluster/commit-proof.js +263 -0
  29. package/dist/src/cluster/commit-proof.js.map +1 -0
  30. package/dist/src/cluster/quorum-restore.d.ts +95 -8
  31. package/dist/src/cluster/quorum-restore.d.ts.map +1 -1
  32. package/dist/src/cluster/quorum-restore.js +113 -14
  33. package/dist/src/cluster/quorum-restore.js.map +1 -1
  34. package/dist/src/cluster/rebalance-monitor.d.ts +84 -0
  35. package/dist/src/cluster/rebalance-monitor.d.ts.map +1 -1
  36. package/dist/src/cluster/rebalance-monitor.js +207 -5
  37. package/dist/src/cluster/rebalance-monitor.js.map +1 -1
  38. package/dist/src/cluster/reconcile-block.d.ts +27 -7
  39. package/dist/src/cluster/reconcile-block.d.ts.map +1 -1
  40. package/dist/src/cluster/reconcile-block.js +179 -38
  41. package/dist/src/cluster/reconcile-block.js.map +1 -1
  42. package/dist/src/cluster/service.d.ts +21 -4
  43. package/dist/src/cluster/service.d.ts.map +1 -1
  44. package/dist/src/cluster/service.js +28 -17
  45. package/dist/src/cluster/service.js.map +1 -1
  46. package/dist/src/cluster/spread-on-churn.d.ts +8 -2
  47. package/dist/src/cluster/spread-on-churn.d.ts.map +1 -1
  48. package/dist/src/cluster/spread-on-churn.js +7 -7
  49. package/dist/src/cluster/spread-on-churn.js.map +1 -1
  50. package/dist/src/cohort-topic/host.d.ts.map +1 -1
  51. package/dist/src/cohort-topic/host.js +8 -7
  52. package/dist/src/cohort-topic/host.js.map +1 -1
  53. package/dist/src/cohort-topic/stream-util.d.ts +7 -6
  54. package/dist/src/cohort-topic/stream-util.d.ts.map +1 -1
  55. package/dist/src/cohort-topic/stream-util.js +14 -41
  56. package/dist/src/cohort-topic/stream-util.js.map +1 -1
  57. package/dist/src/dispute/cascade.d.ts +7 -8
  58. package/dist/src/dispute/cascade.d.ts.map +1 -1
  59. package/dist/src/dispute/cascade.js +24 -7
  60. package/dist/src/dispute/cascade.js.map +1 -1
  61. package/dist/src/dispute/dispute-service.d.ts +5 -0
  62. package/dist/src/dispute/dispute-service.d.ts.map +1 -1
  63. package/dist/src/dispute/dispute-service.js +13 -3
  64. package/dist/src/dispute/dispute-service.js.map +1 -1
  65. package/dist/src/dispute/invalidation.d.ts +33 -15
  66. package/dist/src/dispute/invalidation.d.ts.map +1 -1
  67. package/dist/src/dispute/invalidation.js +127 -34
  68. package/dist/src/dispute/invalidation.js.map +1 -1
  69. package/dist/src/dispute/service.d.ts.map +1 -1
  70. package/dist/src/dispute/service.js +2 -1
  71. package/dist/src/dispute/service.js.map +1 -1
  72. package/dist/src/index.d.ts +7 -0
  73. package/dist/src/index.d.ts.map +1 -1
  74. package/dist/src/index.js +7 -0
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/src/libp2p-key-network.d.ts +78 -6
  77. package/dist/src/libp2p-key-network.d.ts.map +1 -1
  78. package/dist/src/libp2p-key-network.js +136 -57
  79. package/dist/src/libp2p-key-network.js.map +1 -1
  80. package/dist/src/libp2p-node-base.d.ts +38 -7
  81. package/dist/src/libp2p-node-base.d.ts.map +1 -1
  82. package/dist/src/libp2p-node-base.js +150 -62
  83. package/dist/src/libp2p-node-base.js.map +1 -1
  84. package/dist/src/logger.d.ts +2 -2
  85. package/dist/src/logger.js +2 -2
  86. package/dist/src/network/open-protocol-stream.d.ts +56 -0
  87. package/dist/src/network/open-protocol-stream.d.ts.map +1 -0
  88. package/dist/src/network/open-protocol-stream.js +60 -0
  89. package/dist/src/network/open-protocol-stream.js.map +1 -0
  90. package/dist/src/network/register-protocol-handler.d.ts +66 -0
  91. package/dist/src/network/register-protocol-handler.d.ts.map +1 -0
  92. package/dist/src/network/register-protocol-handler.js +51 -0
  93. package/dist/src/network/register-protocol-handler.js.map +1 -0
  94. package/dist/src/peer-address-book.d.ts +128 -1
  95. package/dist/src/peer-address-book.d.ts.map +1 -1
  96. package/dist/src/peer-address-book.js +198 -15
  97. package/dist/src/peer-address-book.js.map +1 -1
  98. package/dist/src/pend-validation.d.ts +65 -0
  99. package/dist/src/pend-validation.d.ts.map +1 -0
  100. package/dist/src/pend-validation.js +69 -0
  101. package/dist/src/pend-validation.js.map +1 -0
  102. package/dist/src/reactivity/notify-transport.d.ts.map +1 -1
  103. package/dist/src/reactivity/notify-transport.js +2 -1
  104. package/dist/src/reactivity/notify-transport.js.map +1 -1
  105. package/dist/src/reactivity/push-state-gossip.d.ts.map +1 -1
  106. package/dist/src/reactivity/push-state-gossip.js +2 -1
  107. package/dist/src/reactivity/push-state-gossip.js.map +1 -1
  108. package/dist/src/repo/cluster-coordinator.d.ts +32 -6
  109. package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
  110. package/dist/src/repo/cluster-coordinator.js +44 -10
  111. package/dist/src/repo/cluster-coordinator.js.map +1 -1
  112. package/dist/src/repo/coordinator-repo.d.ts +181 -25
  113. package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
  114. package/dist/src/repo/coordinator-repo.js +650 -62
  115. package/dist/src/repo/coordinator-repo.js.map +1 -1
  116. package/dist/src/repo/served-repo-proxy.d.ts +30 -0
  117. package/dist/src/repo/served-repo-proxy.d.ts.map +1 -0
  118. package/dist/src/repo/served-repo-proxy.js +50 -0
  119. package/dist/src/repo/served-repo-proxy.js.map +1 -0
  120. package/dist/src/repo/service.d.ts +22 -1
  121. package/dist/src/repo/service.d.ts.map +1 -1
  122. package/dist/src/repo/service.js +25 -13
  123. package/dist/src/repo/service.js.map +1 -1
  124. package/dist/src/reputation/types.d.ts +3 -1
  125. package/dist/src/reputation/types.d.ts.map +1 -1
  126. package/dist/src/reputation/types.js +3 -1
  127. package/dist/src/reputation/types.js.map +1 -1
  128. package/dist/src/rn.d.ts +24 -2
  129. package/dist/src/rn.d.ts.map +1 -1
  130. package/dist/src/rn.js +33 -4
  131. package/dist/src/rn.js.map +1 -1
  132. package/dist/src/routing/libp2p-known-peers.d.ts.map +1 -1
  133. package/dist/src/routing/libp2p-known-peers.js +5 -0
  134. package/dist/src/routing/libp2p-known-peers.js.map +1 -1
  135. package/dist/src/storage/block-archive.d.ts +153 -0
  136. package/dist/src/storage/block-archive.d.ts.map +1 -0
  137. package/dist/src/storage/block-archive.js +194 -0
  138. package/dist/src/storage/block-archive.js.map +1 -0
  139. package/dist/src/storage/block-latch.d.ts +92 -0
  140. package/dist/src/storage/block-latch.d.ts.map +1 -0
  141. package/dist/src/storage/block-latch.js +132 -0
  142. package/dist/src/storage/block-latch.js.map +1 -0
  143. package/dist/src/storage/block-storage.d.ts +169 -12
  144. package/dist/src/storage/block-storage.d.ts.map +1 -1
  145. package/dist/src/storage/block-storage.js +415 -152
  146. package/dist/src/storage/block-storage.js.map +1 -1
  147. package/dist/src/storage/cached-raw-storage.d.ts +5 -1
  148. package/dist/src/storage/cached-raw-storage.d.ts.map +1 -1
  149. package/dist/src/storage/cached-raw-storage.js +16 -1
  150. package/dist/src/storage/cached-raw-storage.js.map +1 -1
  151. package/dist/src/storage/cached-store-driver.d.ts +14 -4
  152. package/dist/src/storage/cached-store-driver.d.ts.map +1 -1
  153. package/dist/src/storage/cached-store-driver.js +39 -5
  154. package/dist/src/storage/cached-store-driver.js.map +1 -1
  155. package/dist/src/storage/i-block-storage.d.ts +70 -19
  156. package/dist/src/storage/i-block-storage.d.ts.map +1 -1
  157. package/dist/src/storage/i-block-storage.js +21 -1
  158. package/dist/src/storage/i-block-storage.js.map +1 -1
  159. package/dist/src/storage/i-raw-storage.d.ts +38 -0
  160. package/dist/src/storage/i-raw-storage.d.ts.map +1 -1
  161. package/dist/src/storage/kv-raw-storage.d.ts +14 -8
  162. package/dist/src/storage/kv-raw-storage.d.ts.map +1 -1
  163. package/dist/src/storage/kv-raw-storage.js +29 -9
  164. package/dist/src/storage/kv-raw-storage.js.map +1 -1
  165. package/dist/src/storage/memory-store-driver.d.ts +4 -1
  166. package/dist/src/storage/memory-store-driver.d.ts.map +1 -1
  167. package/dist/src/storage/memory-store-driver.js +22 -2
  168. package/dist/src/storage/memory-store-driver.js.map +1 -1
  169. package/dist/src/storage/raw-store-codec.js +2 -2
  170. package/dist/src/storage/raw-store-driver.d.ts +44 -3
  171. package/dist/src/storage/raw-store-driver.d.ts.map +1 -1
  172. package/dist/src/storage/shared-cache-pool.d.ts +60 -3
  173. package/dist/src/storage/shared-cache-pool.d.ts.map +1 -1
  174. package/dist/src/storage/shared-cache-pool.js +68 -4
  175. package/dist/src/storage/shared-cache-pool.js.map +1 -1
  176. package/dist/src/storage/storage-repo.d.ts +204 -26
  177. package/dist/src/storage/storage-repo.d.ts.map +1 -1
  178. package/dist/src/storage/storage-repo.js +422 -119
  179. package/dist/src/storage/storage-repo.js.map +1 -1
  180. package/dist/src/storage/store-identity.d.ts +21 -0
  181. package/dist/src/storage/store-identity.d.ts.map +1 -0
  182. package/dist/src/storage/store-identity.js +33 -0
  183. package/dist/src/storage/store-identity.js.map +1 -0
  184. package/dist/src/storage/struct.d.ts +15 -0
  185. package/dist/src/storage/struct.d.ts.map +1 -1
  186. package/dist/src/storage/with-read-cache.d.ts +92 -0
  187. package/dist/src/storage/with-read-cache.d.ts.map +1 -0
  188. package/dist/src/storage/with-read-cache.js +132 -0
  189. package/dist/src/storage/with-read-cache.js.map +1 -0
  190. package/dist/src/sync/service.d.ts +13 -3
  191. package/dist/src/sync/service.d.ts.map +1 -1
  192. package/dist/src/sync/service.js +7 -30
  193. package/dist/src/sync/service.js.map +1 -1
  194. package/dist/src/testing/mesh-harness.d.ts +75 -2
  195. package/dist/src/testing/mesh-harness.d.ts.map +1 -1
  196. package/dist/src/testing/mesh-harness.js +193 -81
  197. package/dist/src/testing/mesh-harness.js.map +1 -1
  198. package/dist/src/testing/raw-storage-conformance.d.ts +8 -0
  199. package/dist/src/testing/raw-storage-conformance.d.ts.map +1 -1
  200. package/dist/src/testing/raw-storage-conformance.js +97 -2
  201. package/dist/src/testing/raw-storage-conformance.js.map +1 -1
  202. package/package.json +5 -6
  203. package/src/cluster/block-transfer-service.ts +528 -312
  204. package/src/cluster/block-transfer.ts +547 -424
  205. package/src/cluster/certified-claims.ts +319 -0
  206. package/src/cluster/client-signature-verifier.ts +34 -0
  207. package/src/cluster/cluster-policy.ts +294 -203
  208. package/src/cluster/cluster-repo.ts +2501 -2034
  209. package/src/cluster/commit-proof.ts +344 -0
  210. package/src/cluster/quorum-restore.ts +348 -223
  211. package/src/cluster/rebalance-monitor.ts +539 -254
  212. package/src/cluster/reconcile-block.ts +404 -203
  213. package/src/cluster/service.ts +308 -293
  214. package/src/cluster/spread-on-churn.ts +352 -346
  215. package/src/cohort-topic/host.ts +8 -7
  216. package/src/cohort-topic/stream-util.ts +14 -43
  217. package/src/dispute/cascade.ts +31 -15
  218. package/src/dispute/dispute-service.ts +706 -696
  219. package/src/dispute/invalidation.ts +162 -52
  220. package/src/dispute/service.ts +126 -125
  221. package/src/index.ts +7 -0
  222. package/src/libp2p-key-network.ts +142 -58
  223. package/src/libp2p-node-base.ts +1793 -1675
  224. package/src/logger.ts +27 -27
  225. package/src/network/open-protocol-stream.ts +87 -0
  226. package/src/network/register-protocol-handler.ts +85 -0
  227. package/src/peer-address-book.ts +360 -149
  228. package/src/pend-validation.ts +89 -0
  229. package/src/reactivity/notify-transport.ts +145 -144
  230. package/src/reactivity/push-state-gossip.ts +292 -291
  231. package/src/repo/cluster-coordinator.ts +65 -11
  232. package/src/repo/coordinator-repo.ts +729 -71
  233. package/src/repo/served-repo-proxy.ts +55 -0
  234. package/src/repo/service.ts +332 -313
  235. package/src/reputation/types.ts +3 -1
  236. package/src/rn.ts +34 -4
  237. package/src/routing/libp2p-known-peers.ts +31 -26
  238. package/src/storage/block-archive.ts +242 -0
  239. package/src/storage/block-latch.ts +144 -0
  240. package/src/storage/block-storage.ts +787 -498
  241. package/src/storage/cached-raw-storage.ts +21 -1
  242. package/src/storage/cached-store-driver.ts +898 -859
  243. package/src/storage/i-block-storage.ts +172 -116
  244. package/src/storage/i-raw-storage.ts +40 -0
  245. package/src/storage/kv-raw-storage.ts +34 -9
  246. package/src/storage/memory-store-driver.ts +26 -2
  247. package/src/storage/raw-store-codec.ts +42 -42
  248. package/src/storage/raw-store-driver.ts +45 -3
  249. package/src/storage/shared-cache-pool.ts +516 -452
  250. package/src/storage/storage-repo.ts +1421 -1014
  251. package/src/storage/store-identity.ts +41 -0
  252. package/src/storage/struct.ts +52 -34
  253. package/src/storage/with-read-cache.ts +182 -0
  254. package/src/sync/service.ts +178 -198
  255. package/src/testing/cohort-topic-mesh-harness.ts +673 -673
  256. package/src/testing/mesh-harness.ts +524 -344
  257. package/src/testing/raw-storage-conformance.ts +114 -2
package/src/logger.ts CHANGED
@@ -1,27 +1,27 @@
1
- import debug from 'debug'
2
-
3
- const BASE_NAMESPACE = 'optimystic:db-p2p'
4
-
5
- /**
6
- * Build a `debug` logger under `optimystic:db-p2p:<subNamespace>`, optionally suffixed with the
7
- * owning node's peer id (`:<first 12 chars>`) so lines from several nodes sharing one process —
8
- * every integration test — are attributable. Omit `peerId` and the namespace is byte-for-byte the
9
- * un-suffixed one, so callers that don't know their peer id are unaffected.
10
- *
11
- * NOTE: 12 chars matches the truncation the rest of this package already uses in log payloads, but
12
- * every Ed25519 peer id starts with the constant `12D3KooW`, so only ~4 base58 characters actually
13
- * distinguish nodes (~11M combinations — ample for the handful of nodes a test process runs).
14
- * Widen this only if a run ever needs to match a namespace against a full peer id.
15
- *
16
- * NOTE: only the two classes the diagnosability ticket named pass a peer id today
17
- * (`Libp2pKeyPeerNetwork`, `CoordinatorRepo`); the package's other ~30 `createLogger` call sites
18
- * still log under a flat namespace. Thread a peer id through any of them if a future diagnosis
19
- * needs per-node attribution from that subsystem — the mechanism is already here.
20
- */
21
- export function createLogger(subNamespace: string, peerId?: string): debug.Debugger {
22
- const suffix = peerId ? `:${peerId.substring(0, 12)}` : ''
23
- return debug(`${BASE_NAMESPACE}:${subNamespace}${suffix}`)
24
- }
25
-
26
- export const verbose = typeof process !== 'undefined'
27
- && (process.env.OPTIMYSTIC_VERBOSE === '1' || process.env.OPTIMYSTIC_VERBOSE === 'true');
1
+ import debug from 'debug'
2
+
3
+ const BASE_NAMESPACE = 'optimystic:db-p2p'
4
+
5
+ /**
6
+ * Build a `debug` logger under `optimystic:db-p2p:<subNamespace>`, optionally suffixed with the
7
+ * owning node's peer id (`:<first 12 chars>`) so lines from several nodes sharing one process —
8
+ * every integration test — are attributable. Omit `peerId` and the namespace is byte-for-byte the
9
+ * un-suffixed one, so callers that don't know their peer id are unaffected.
10
+ *
11
+ * NOTE: 12 chars matches the truncation the rest of this package already uses in log payloads, but
12
+ * every Ed25519 peer id starts with the constant `12D3KooW`, so only ~4 base58 characters actually
13
+ * distinguish nodes (~11M combinations — ample for the handful of nodes a test process runs).
14
+ * Widen this only if a run ever needs to match a namespace against a full peer id.
15
+ *
16
+ * NOTE: only a few call sites pass a peer id today (`Libp2pKeyPeerNetwork`, `CoordinatorRepo`, and
17
+ * the three `peer-address-book` sinks); the package's other ~30 `createLogger` call sites
18
+ * still log under a flat namespace. Thread a peer id through any of them if a future diagnosis
19
+ * needs per-node attribution from that subsystem — the mechanism is already here.
20
+ */
21
+ export function createLogger(subNamespace: string, peerId?: string): debug.Debugger {
22
+ const suffix = peerId ? `:${peerId.substring(0, 12)}` : ''
23
+ return debug(`${BASE_NAMESPACE}:${subNamespace}${suffix}`)
24
+ }
25
+
26
+ export const verbose = typeof process !== 'undefined'
27
+ && (process.env.OPTIMYSTIC_VERBOSE === '1' || process.env.OPTIMYSTIC_VERBOSE === 'true');
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The single place in `db-p2p` that opens a libp2p protocol stream.
3
+ *
4
+ * libp2p refuses to open a protocol stream over a *limited* (circuit-relay) connection unless the
5
+ * caller opts in with `runOnLimitedConnection: true`. Omitting it produces no compile error and no
6
+ * obvious failure — only "that peer never answers" — so every peer reachable only through a relay
7
+ * (the steady state for browsers, phones, and NATed peers) silently drops out. The flag is
8
+ * deliberately NOT an option here: a new call site gets relay support without its author needing to
9
+ * know the flag exists, and `test/dial-options-single-site.spec.ts` fails the build if a second
10
+ * source file calls `dialProtocol` / `newStream` directly.
11
+ *
12
+ * NOTE: accepted tradeoff — this duplicates FRET's `rpc/protocols.ts#openRpcStream` (exported since
13
+ * `p2p-fret@1.0.0-beta.3`) rather than delegating to it. FRET's helper pins `negotiateFully: false`
14
+ * with no way to opt out, and `cohort-topic/stream-util.ts` deliberately does not set that option
15
+ * (see the NOTE at its call sites); adopting FRET's would silently reverse a decision a human
16
+ * already made. It also has no hook for the pre-dial check `libp2p-key-network.ts#connect` runs.
17
+ * Revisit — and delete this module in favour of `openRpcStream` — if FRET ever parameterizes
18
+ * `negotiateFully`.
19
+ *
20
+ * Imports here are type-only on purpose: this module is reachable from the react-native entry
21
+ * (`src/rn.ts`) via `libp2p-key-network.ts`, which must not pull node-specific code.
22
+ */
23
+
24
+ import type { Libp2p } from "libp2p";
25
+ import type { Connection, PeerId, Stream } from "@libp2p/interface";
26
+
27
+ export interface OpenProtocolStreamOptions {
28
+ /** Forwarded to libp2p so a caller's deadline cancels both the connection reuse and the dial. */
29
+ signal?: AbortSignal;
30
+ /**
31
+ * Omit for libp2p's default (full multistream-select negotiation at stream-open).
32
+ * Pass `false` to save the round trip, accepting that an unsupported-protocol failure is
33
+ * deferred to the first read — only safe when the caller always reads a reply.
34
+ */
35
+ negotiateFully?: boolean;
36
+ /**
37
+ * Runs immediately before a FRESH dial, and never on the connection-reuse path.
38
+ * Throwing aborts the open. This is the seam for checks that are only meaningful when no
39
+ * connection exists yet (see `libp2p-key-network.ts#assertNotSelfRelayOnly`).
40
+ */
41
+ beforeDial?: () => Promise<void> | void;
42
+ }
43
+
44
+ /**
45
+ * True for a circuit-relay ("limited") connection: libp2p stamps one with per-circuit `limits`
46
+ * (data/duration caps); sniffing `/p2p-circuit` in the remote multiaddr covers transports and
47
+ * versions that leave `limits` unpopulated.
48
+ */
49
+ export function isLimitedConnection(c: Connection): boolean {
50
+ if (c.limits != null) return true;
51
+ return c.remoteAddr?.toString?.().includes("/p2p-circuit") ?? false;
52
+ }
53
+
54
+ /**
55
+ * Open `protocol` to `peer`, reusing a healthy existing connection when there is one.
56
+ *
57
+ * Skips connections libp2p has not yet evicted from its index but that are no longer open, and
58
+ * prefers a direct connection over a relayed one — a relayed connection can be reset once the
59
+ * relay's per-circuit cap or reservation lapses, and after DCUtR upgrades a link to direct both
60
+ * briefly coexist. Falls back to the relayed connection when it is the only open path.
61
+ */
62
+ export async function openProtocolStream(
63
+ node: Libp2p,
64
+ peer: PeerId,
65
+ protocol: string,
66
+ options?: OpenProtocolStreamOptions,
67
+ ): Promise<Stream> {
68
+ // Before touching connections: a caller that has already given up is owed its own reason,
69
+ // not whatever libp2p would report several layers down.
70
+ options?.signal?.throwIfAborted();
71
+
72
+ const conns = node.getConnections?.(peer) ?? [];
73
+ const open = conns.filter(c => c?.status === "open" && typeof c?.newStream === "function");
74
+ const chosen = open.find(c => !isLimitedConnection(c)) ?? open[0];
75
+
76
+ // Keys are OMITTED rather than set to `undefined` when the caller did not supply them, so
77
+ // libp2p applies its own defaults instead of seeing an explicit `undefined`.
78
+ const streamOptions = {
79
+ runOnLimitedConnection: true,
80
+ ...(options?.negotiateFully !== undefined ? { negotiateFully: options.negotiateFully } : {}),
81
+ ...(options?.signal !== undefined ? { signal: options.signal } : {}),
82
+ };
83
+
84
+ if (chosen) return await chosen.newStream([protocol], streamOptions);
85
+ await options?.beforeDial?.();
86
+ return await node.dialProtocol(peer, [protocol], streamOptions);
87
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The single place in `db-p2p` that registers a libp2p protocol handler.
3
+ *
4
+ * The mirror image of `./open-protocol-stream.ts`. Opening a stream over a *limited* (circuit-relay)
5
+ * connection needs BOTH sides to opt in, and libp2p checks each side against its own options:
6
+ *
7
+ * - the dialer's `newStream` / `dialProtocol` options (`libp2p/src/connection.ts`, outbound path), and
8
+ * - the options the *answering* peer passed when it registered the handler
9
+ * (`libp2p/src/connection.ts`, incoming path — it reads back
10
+ * `registrar.getHandler(protocol).options.runOnLimitedConnection`).
11
+ *
12
+ * Miss either one and libp2p throws `LimitedConnectionError`. On the answering side it does so
13
+ * *after* multistream-select has already acknowledged the protocol, so the dialer's stream open
14
+ * appears to succeed and the stream is then reset with no reply — indistinguishable, from the
15
+ * dialer's seat, from a peer that simply does not hold the data. Every peer reachable only through
16
+ * a capped relay (phones, browsers, machines behind a home router) silently drops out.
17
+ *
18
+ * `openProtocolStream` fixed the dialling half; this fixes the answering half. As there, the flag is
19
+ * deliberately NOT an option: a new protocol gets relay support without its author needing to know
20
+ * the flag exists, and `test/dial-options-single-site.spec.ts` fails the build if a second source
21
+ * file calls `.handle(...)` directly.
22
+ *
23
+ * Accepting the stream is necessary but not sufficient. A stock relay also caps the *whole* relayed
24
+ * connection — `applyDefaultLimit: true` stamps `Limit { data: 128 KiB, duration: 2 min }` on every
25
+ * reservation — so a relay-only peer now answers, but the circuit is reset once either cap is hit,
26
+ * which one cohort frame (`DEFAULT_STREAM_MAX_BYTES`, 512 KiB) can do on its own. Lifting that is
27
+ * the relay operator's knob, not this one: see `NodeOptions.relayServerInit` in `libp2p-node-base.ts`.
28
+ *
29
+ * Imports here are type-only on purpose: this module is reachable from the react-native entry
30
+ * (`src/rn.ts`), which must not pull node-specific code.
31
+ */
32
+
33
+ import type { StreamHandler, StreamHandlerOptions, StreamMiddleware } from "@libp2p/interface";
34
+
35
+ /**
36
+ * Anything that can register a libp2p protocol handler.
37
+ *
38
+ * Both shapes in this package satisfy it: a `Libp2p` node (`node.handle(...)`) and the `registrar`
39
+ * component the service classes are constructed with (`components.registrar.handle(...)`).
40
+ */
41
+ export interface ProtocolRegistrar {
42
+ handle(protocol: string, handler: StreamHandler, options?: StreamHandlerOptions): Promise<void>;
43
+ }
44
+
45
+ /**
46
+ * The per-protocol settings that legitimately vary. `runOnLimitedConnection` is absent on purpose —
47
+ * it is a constant of this helper, not a caller's choice.
48
+ */
49
+ export interface RegisterProtocolHandlerOptions {
50
+ /** Concurrent inbound streams allowed per connection. Omit for libp2p's default (32). */
51
+ maxInboundStreams?: number;
52
+ /** Concurrent outbound streams allowed per connection. Omit for libp2p's default (64). */
53
+ maxOutboundStreams?: number;
54
+ /** Stream middleware, run around the handler. Omit for none. */
55
+ middleware?: StreamMiddleware[];
56
+ /** Replace an existing registration for this protocol instead of rejecting. */
57
+ force?: true;
58
+ /** Forwarded to libp2p so a caller's deadline cancels the registration. */
59
+ signal?: AbortSignal;
60
+ }
61
+
62
+ /**
63
+ * Register `handler` for `protocol`, accepting streams over limited (relay) connections.
64
+ *
65
+ * Rejects if the registrar rejects — a duplicate protocol id, or an aborted signal. Callers that
66
+ * register fire-and-forget (`void registerProtocolHandler(...)`) keep that behaviour; see the NOTE
67
+ * in `libp2p-node-base.ts` about the reactivity handlers.
68
+ */
69
+ export async function registerProtocolHandler(
70
+ target: ProtocolRegistrar,
71
+ protocol: string,
72
+ handler: StreamHandler,
73
+ options?: RegisterProtocolHandlerOptions,
74
+ ): Promise<void> {
75
+ // Keys are OMITTED rather than set to `undefined` when the caller did not supply them, so
76
+ // libp2p applies its own defaults instead of seeing an explicit `undefined`.
77
+ await target.handle(protocol, handler, {
78
+ runOnLimitedConnection: true,
79
+ ...(options?.maxInboundStreams !== undefined ? { maxInboundStreams: options.maxInboundStreams } : {}),
80
+ ...(options?.maxOutboundStreams !== undefined ? { maxOutboundStreams: options.maxOutboundStreams } : {}),
81
+ ...(options?.middleware !== undefined ? { middleware: options.middleware } : {}),
82
+ ...(options?.force !== undefined ? { force: options.force } : {}),
83
+ ...(options?.signal !== undefined ? { signal: options.signal } : {}),
84
+ });
85
+ }