@serfab/cadre-core 1.6.0 → 1.8.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 (179) hide show
  1. package/README.md +8 -6
  2. package/dist/cadre-node.d.ts +548 -137
  3. package/dist/cadre-node.js +1208 -383
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/control-authorization.d.ts +2 -2
  6. package/dist/control-authorization.js +1 -0
  7. package/dist/control-authorization.js.map +1 -1
  8. package/dist/control-cohort.d.ts +6 -0
  9. package/dist/control-cohort.js +6 -0
  10. package/dist/control-cohort.js.map +1 -1
  11. package/dist/control-database.d.ts +46 -8
  12. package/dist/control-database.js +97 -18
  13. package/dist/control-database.js.map +1 -1
  14. package/dist/control-formation-recorder.d.ts +37 -14
  15. package/dist/control-formation-recorder.js +60 -10
  16. package/dist/control-formation-recorder.js.map +1 -1
  17. package/dist/control-read-retry.d.ts +13 -12
  18. package/dist/control-read-retry.js +14 -12
  19. package/dist/control-read-retry.js.map +1 -1
  20. package/dist/control-schema.d.ts +1 -1
  21. package/dist/control-schema.js +67 -5
  22. package/dist/control-schema.js.map +1 -1
  23. package/dist/control-stream.d.ts +9 -1
  24. package/dist/control-stream.js +24 -1
  25. package/dist/control-stream.js.map +1 -1
  26. package/dist/control-write-retry.d.ts +12 -2
  27. package/dist/control-write-retry.js +13 -2
  28. package/dist/control-write-retry.js.map +1 -1
  29. package/dist/delegate-admission.d.ts +11 -8
  30. package/dist/delegate-admission.js +19 -11
  31. package/dist/delegate-admission.js.map +1 -1
  32. package/dist/diagnostics/connection-path.d.ts +0 -7
  33. package/dist/diagnostics/connection-path.js +0 -7
  34. package/dist/diagnostics/connection-path.js.map +1 -1
  35. package/dist/formation-approval.d.ts +7 -0
  36. package/dist/formation-approval.js +9 -3
  37. package/dist/formation-approval.js.map +1 -1
  38. package/dist/fs-atomic.d.ts +11 -2
  39. package/dist/fs-atomic.js +13 -3
  40. package/dist/fs-atomic.js.map +1 -1
  41. package/dist/hibernation-manager.d.ts +111 -8
  42. package/dist/hibernation-manager.js +234 -49
  43. package/dist/hibernation-manager.js.map +1 -1
  44. package/dist/index.d.ts +13 -6
  45. package/dist/index.js +27 -5
  46. package/dist/index.js.map +1 -1
  47. package/dist/joined-strand-store.d.ts +177 -0
  48. package/dist/joined-strand-store.js +431 -0
  49. package/dist/joined-strand-store.js.map +1 -0
  50. package/dist/key-store-file.js +14 -5
  51. package/dist/key-store-file.js.map +1 -1
  52. package/dist/key-store.d.ts +6 -0
  53. package/dist/key-store.js.map +1 -1
  54. package/dist/link-budget.d.ts +367 -69
  55. package/dist/link-budget.js +375 -72
  56. package/dist/link-budget.js.map +1 -1
  57. package/dist/membership-connection-gater.d.ts +30 -43
  58. package/dist/membership-connection-gater.js +31 -42
  59. package/dist/membership-connection-gater.js.map +1 -1
  60. package/dist/node-local-snapshot.d.ts +5 -4
  61. package/dist/node-local-snapshot.js +6 -3
  62. package/dist/node-local-snapshot.js.map +1 -1
  63. package/dist/peer-dial.d.ts +24 -4
  64. package/dist/peer-dial.js +74 -5
  65. package/dist/peer-dial.js.map +1 -1
  66. package/dist/peer-join-backfill.d.ts +35 -15
  67. package/dist/peer-join-backfill.js +115 -55
  68. package/dist/peer-join-backfill.js.map +1 -1
  69. package/dist/push-fanout.d.ts +6 -0
  70. package/dist/push-fanout.js +6 -0
  71. package/dist/push-fanout.js.map +1 -1
  72. package/dist/relay-reservation.d.ts +3 -1
  73. package/dist/relay-reservation.js +3 -1
  74. package/dist/relay-reservation.js.map +1 -1
  75. package/dist/relay-server.d.ts +79 -0
  76. package/dist/relay-server.js +74 -0
  77. package/dist/relay-server.js.map +1 -0
  78. package/dist/seed-bootstrap.d.ts +57 -4
  79. package/dist/seed-bootstrap.js +107 -83
  80. package/dist/seed-bootstrap.js.map +1 -1
  81. package/dist/storage-scope.d.ts +33 -17
  82. package/dist/storage-scope.js +44 -23
  83. package/dist/storage-scope.js.map +1 -1
  84. package/dist/strand-addr-protocol.d.ts +58 -21
  85. package/dist/strand-addr-protocol.js +133 -85
  86. package/dist/strand-addr-protocol.js.map +1 -1
  87. package/dist/strand-database.d.ts +20 -2
  88. package/dist/strand-database.js +42 -5
  89. package/dist/strand-database.js.map +1 -1
  90. package/dist/strand-first-sync-gate.d.ts +59 -21
  91. package/dist/strand-first-sync-gate.js +58 -19
  92. package/dist/strand-first-sync-gate.js.map +1 -1
  93. package/dist/strand-formation-deadlines.d.ts +151 -0
  94. package/dist/strand-formation-deadlines.js +171 -0
  95. package/dist/strand-formation-deadlines.js.map +1 -0
  96. package/dist/strand-formation-manager.d.ts +63 -30
  97. package/dist/strand-formation-manager.js +67 -41
  98. package/dist/strand-formation-manager.js.map +1 -1
  99. package/dist/strand-formation-protocol.d.ts +45 -35
  100. package/dist/strand-formation-protocol.js +59 -122
  101. package/dist/strand-formation-protocol.js.map +1 -1
  102. package/dist/strand-instance-manager.d.ts +152 -6
  103. package/dist/strand-instance-manager.js +331 -42
  104. package/dist/strand-instance-manager.js.map +1 -1
  105. package/dist/strand-membership-writer.d.ts +6 -0
  106. package/dist/strand-membership-writer.js +11 -0
  107. package/dist/strand-membership-writer.js.map +1 -1
  108. package/dist/strand-peer-book-file.d.ts +12 -0
  109. package/dist/strand-peer-book-file.js +37 -0
  110. package/dist/strand-peer-book-file.js.map +1 -0
  111. package/dist/strand-peer-book-protocol.d.ts +168 -0
  112. package/dist/strand-peer-book-protocol.js +356 -0
  113. package/dist/strand-peer-book-protocol.js.map +1 -0
  114. package/dist/strand-peer-book-swap.d.ts +104 -0
  115. package/dist/strand-peer-book-swap.js +284 -0
  116. package/dist/strand-peer-book-swap.js.map +1 -0
  117. package/dist/strand-peer-book.d.ts +159 -0
  118. package/dist/strand-peer-book.js +361 -0
  119. package/dist/strand-peer-book.js.map +1 -0
  120. package/dist/strand-peer-observer.d.ts +88 -0
  121. package/dist/strand-peer-observer.js +180 -0
  122. package/dist/strand-peer-observer.js.map +1 -0
  123. package/dist/strand-revocation-enforcer.js +2 -1
  124. package/dist/strand-revocation-enforcer.js.map +1 -1
  125. package/dist/strand-solicitation.d.ts +36 -20
  126. package/dist/strand-solicitation.js +4 -4
  127. package/dist/strand-solicitation.js.map +1 -1
  128. package/dist/strand-wake-protocol.d.ts +80 -23
  129. package/dist/strand-wake-protocol.js +89 -64
  130. package/dist/strand-wake-protocol.js.map +1 -1
  131. package/dist/types.d.ts +181 -33
  132. package/dist/types.js +4 -3
  133. package/dist/types.js.map +1 -1
  134. package/package.json +11 -7
  135. package/src/cadre-node.ts +1316 -398
  136. package/src/control-authorization.ts +2 -1
  137. package/src/control-cohort.ts +6 -0
  138. package/src/control-database.ts +122 -18
  139. package/src/control-formation-recorder.ts +354 -305
  140. package/src/control-read-retry.ts +14 -12
  141. package/src/control-schema.ts +67 -5
  142. package/src/control-stream.ts +25 -1
  143. package/src/control-write-retry.ts +13 -2
  144. package/src/delegate-admission.ts +23 -13
  145. package/src/diagnostics/connection-path.ts +0 -7
  146. package/src/formation-approval.ts +610 -604
  147. package/src/fs-atomic.ts +14 -4
  148. package/src/hibernation-manager.ts +638 -437
  149. package/src/index.ts +91 -6
  150. package/src/joined-strand-store.ts +498 -0
  151. package/src/key-store-file.ts +14 -5
  152. package/src/key-store.ts +6 -0
  153. package/src/link-budget.ts +393 -74
  154. package/src/membership-connection-gater.ts +31 -45
  155. package/src/node-local-snapshot.ts +293 -289
  156. package/src/peer-dial.ts +81 -7
  157. package/src/peer-join-backfill.ts +120 -57
  158. package/src/push-fanout.ts +6 -0
  159. package/src/relay-reservation.ts +3 -1
  160. package/src/relay-server.ts +98 -0
  161. package/src/seed-bootstrap.ts +133 -91
  162. package/src/storage-scope.ts +44 -23
  163. package/src/strand-addr-protocol.ts +547 -458
  164. package/src/strand-database.ts +287 -242
  165. package/src/strand-first-sync-gate.ts +58 -19
  166. package/src/strand-formation-deadlines.ts +227 -0
  167. package/src/strand-formation-manager.ts +700 -647
  168. package/src/strand-formation-protocol.ts +103 -150
  169. package/src/strand-instance-manager.ts +387 -45
  170. package/src/strand-membership-writer.ts +12 -0
  171. package/src/strand-peer-book-file.ts +39 -0
  172. package/src/strand-peer-book-protocol.ts +466 -0
  173. package/src/strand-peer-book-swap.ts +338 -0
  174. package/src/strand-peer-book.ts +475 -0
  175. package/src/strand-peer-observer.ts +235 -0
  176. package/src/strand-revocation-enforcer.ts +2 -1
  177. package/src/strand-solicitation.ts +519 -500
  178. package/src/strand-wake-protocol.ts +401 -355
  179. package/src/types.ts +185 -33
@@ -85,7 +85,10 @@
85
85
  * infra outright, and admits peers it cannot place only within a bounded
86
86
  * budget ({@link UnauthorizedReservationBudget}) — a member whose row is in
87
87
  * flight always finds a slot under any sane cap, while outsiders cannot
88
- * annex the party's relay capacity.
88
+ * annex the party's relay capacity. COUNT and lifetime are the only bounds
89
+ * on such a peer: a party-run relay forwards without libp2p's per-connection
90
+ * data and duration limit by default (`relay-server.ts`), so what a granted
91
+ * slot carries is not capped.
89
92
  * - An `'admit-for-relay'` connection that is NOT reserving is dropped: it has
90
93
  * {@link RELAY_ADMISSION_RESERVE_DEADLINE_MS} to get a reservation ADMITTED
91
94
  * at that hook, after which the gate CLOSES the underlying connection so
@@ -160,6 +163,8 @@ import type { ConnectionGater, PeerId, MultiaddrConnection } from '@libp2p/inter
160
163
  import { SEED_PROTOCOL } from './seed-bootstrap.js';
161
164
  import { FORMATION_PROTOCOL } from './strand-formation-protocol.js';
162
165
  import { withDeadline } from './control-stream.js';
166
+ import { PARTY_RELAY_RESERVATION_TTL_MS } from './relay-server.js';
167
+ import { ADMISSION_DECISION_TIMEOUT_MS, relayAdmissionReserveDeadlineMs } from './link-budget.js';
163
168
 
164
169
  const log = debug('sereus:cadre:connection-gater');
165
170
 
@@ -180,22 +185,6 @@ export const STRANGER_OPEN_PROTOCOLS: readonly string[] = [SEED_PROTOCOL, FORMAT
180
185
  */
181
186
  export const DEFAULT_ENROLLMENT_WINDOW_MS = 30 * 60 * 1000;
182
187
 
183
- /**
184
- * Deadline for one admission decision, after which the fail-open outcome is
185
- * used (connection admitted / reservation admitted).
186
- *
187
- * libp2p awaits `denyInboundEncryptedConnection` inside the inbound upgrade
188
- * WITHOUT racing its inbound-upgrade timeout signal (unlike the pre-encryption
189
- * `denyInboundConnection` hook), so a decision that never settles wedges that
190
- * upgrade forever — the connection-manager's inbound-upgrade slot is taken by
191
- * `acceptIncomingConnection` and released in the `finally` that never runs. The
192
- * real policy reads the control DB (`listAuthorizedMembers`), which can pull
193
- * over the network, so "never settles" is reachable. Bounding it here keeps the
194
- * fail-open contract honest: a slow decision admits rather than silently
195
- * failing closed (or not at all).
196
- */
197
- export const ADMISSION_DECISION_TIMEOUT_MS = 2_000;
198
-
199
188
  /**
200
189
  * How long an `'admit-for-relay'` connection may exist without a relay
201
190
  * reservation being ADMITTED at the `denyInboundRelayReservation` hook, after
@@ -204,8 +193,13 @@ export const ADMISSION_DECISION_TIMEOUT_MS = 2_000;
204
193
  * dials and requests in one drive; a strand node's configured circuit listener
205
194
  * does the same from inside its own `listen()`), so a connection idle past this
206
195
  * deadline is not reserving.
196
+ *
197
+ * Derived from the link ({@link relayAdmissionReserveDeadlineMs}): one link round trip for the
198
+ * request to arrive plus one admission decision on it. This is the value at the default
199
+ * declaration; `CadreNode` passes the one derived from the relay's OWN declaration, because the
200
+ * relay is the machine that decides.
207
201
  */
208
- export const RELAY_ADMISSION_RESERVE_DEADLINE_MS = 5_000;
202
+ export const RELAY_ADMISSION_RESERVE_DEADLINE_MS = relayAdmissionReserveDeadlineMs();
209
203
 
210
204
  /**
211
205
  * Bound on the graceful close of an expired relay-only connection. It exists
@@ -218,6 +212,7 @@ export const RELAY_ADMISSION_RESERVE_DEADLINE_MS = 5_000;
218
212
  * Applied through {@link withDeadline}, not `AbortSignal.timeout`: the latter is
219
213
  * not reliably present on React Native/Hermes, which loads this same module.
220
214
  */
215
+ // eslint-disable-next-line no-restricted-syntax -- link-independent: bounds a local connection close inside a timer callback, and expiry aborts the connection instead
221
216
  export const RELAY_ADMISSION_CLOSE_TIMEOUT_MS = 2_000;
222
217
 
223
218
  /**
@@ -228,31 +223,17 @@ export const RELAY_ADMISSION_CLOSE_TIMEOUT_MS = 2_000;
228
223
  * `network.unauthorizedRelayReservationCap` (0 refuses every unauthorized
229
224
  * reservation — the strict pre-seam posture).
230
225
  *
231
- * NOTE: this cap shares the relay server's own reservation store, whose default
232
- * size is 15 (`@libp2p/circuit-relay-v2`'s `DEFAULT_MAX_RESERVATION_STORE_SIZE`);
233
- * unplaced peers may therefore occupy up to this many of those slots, and the
234
- * rest are what members and delegates compete for. This module cannot read the
235
- * server's size, so the two are kept apart by hand — if either is raised, keep
236
- * this one well under the store's, or a fleet of unplaceable peers can crowd
237
- * genuine members out of the server's own store (which the gate cannot override).
226
+ * NOTE: this cap shares the relay server's own reservation store, whose
227
+ * party-run default size is `PARTY_RELAY_MAX_RESERVATIONS` (128,
228
+ * `relay-server.ts`); unplaced peers may therefore occupy up to this many of
229
+ * those slots, and the rest are what members and delegates compete for. The two
230
+ * are kept apart by hand — if this is raised, or an embedder shrinks the store
231
+ * through `network.relayServerInit.reservations.maxReservations`, keep this one
232
+ * well under the store's, or a fleet of unplaceable peers can crowd genuine
233
+ * members out of the server's own store (which the gate cannot override).
238
234
  */
239
235
  export const MAX_UNAUTHORIZED_RELAY_RESERVATIONS = 8;
240
236
 
241
- /**
242
- * How long one {@link UnauthorizedReservationBudget} entry occupies a slot
243
- * without a refresh. Mirrors the relay server's own default reservation TTL
244
- * (`@libp2p/circuit-relay-v2`'s `DEFAULT_MAX_RESERVATION_TTL`, 2 h): the server
245
- * holds an unrefreshed reservation exactly that long, and a live reserver
246
- * re-requests (re-hitting the admission hook, refreshing its entry) well before
247
- * expiry — so the live entry count tracks the server's own occupancy without
248
- * this module reaching into the server's reservation store.
249
- *
250
- * NOTE: a mirror, not a live coupling — if the relay server is ever configured
251
- * with a non-default `reservationTtl` (db-p2p's `relayServerInit`), update this
252
- * constant alongside it or the budget's occupancy drifts from the server's.
253
- */
254
- export const UNAUTHORIZED_RESERVATION_TTL_MS = 2 * 60 * 60 * 1000;
255
-
256
237
  /**
257
238
  * The connection-level outcome of the admission policy:
258
239
  * - `'admit'` — a peer with a legitimate claim on the connection (member,
@@ -295,9 +276,13 @@ export interface InboundAdmissionPolicy {
295
276
  * Bounded budget of concurrent relay reservations for peers the membership
296
277
  * check could not place. `tryAdmit` is the whole surface: an already-admitted
297
278
  * peer refreshes its entry (a reservation refresh never double-counts), a new
298
- * peer takes a free slot or is refused. Entries expire after `ttlMs` (see
299
- * {@link UNAUTHORIZED_RESERVATION_TTL_MS} for why that mirrors the relay
300
- * server's own hold). Injectable `now` keeps expiry testable without fake
279
+ * peer takes a free slot or is refused. Entries expire after `ttlMs`, which
280
+ * `CadreNode` passes as the relay server's own resolved `reservationTtl`
281
+ * (`relay-server.ts`): the server holds an unrefreshed reservation exactly that
282
+ * long, and a live reserver re-requests (re-hitting the admission hook,
283
+ * refreshing its entry) well before expiry — so the live entry count tracks the
284
+ * server's own occupancy without this module reaching into the server's
285
+ * reservation store. Injectable `now` keeps expiry testable without fake
301
286
  * timers. Authorized members and delegates are never run through this — the
302
287
  * policy admits them before consulting the budget, and `release`s the slot such
303
288
  * a peer took while it was still unplaceable, so the boot-ordering window a
@@ -307,8 +292,9 @@ export class UnauthorizedReservationBudget {
307
292
  private readonly admitted = new Map<string, number>();
308
293
 
309
294
  constructor(
310
- private readonly cap: number = MAX_UNAUTHORIZED_RELAY_RESERVATIONS,
311
- private readonly ttlMs: number = UNAUTHORIZED_RESERVATION_TTL_MS
295
+ /** Most peers admitted at once — `network.unauthorizedRelayReservationCap`, resolved. */
296
+ readonly cap: number = MAX_UNAUTHORIZED_RELAY_RESERVATIONS,
297
+ private readonly ttlMs: number = PARTY_RELAY_RESERVATION_TTL_MS
312
298
  ) {}
313
299
 
314
300
  /** Number of live (unexpired at last prune) entries — test/diagnostic surface. */