@serfab/cadre-core 1.17.0 → 1.19.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 (148) hide show
  1. package/README.md +3 -2
  2. package/dist/cadre-invite-protocol.d.ts +35 -13
  3. package/dist/cadre-invite-protocol.js +90 -25
  4. package/dist/cadre-invite-protocol.js.map +1 -1
  5. package/dist/cadre-node.d.ts +586 -255
  6. package/dist/cadre-node.js +1182 -566
  7. package/dist/cadre-node.js.map +1 -1
  8. package/dist/control-cohort.d.ts +66 -9
  9. package/dist/control-cohort.js +67 -9
  10. package/dist/control-cohort.js.map +1 -1
  11. package/dist/control-database.d.ts +451 -193
  12. package/dist/control-database.js +701 -359
  13. package/dist/control-database.js.map +1 -1
  14. package/dist/control-formation-recorder.d.ts +46 -43
  15. package/dist/control-formation-recorder.js +77 -78
  16. package/dist/control-formation-recorder.js.map +1 -1
  17. package/dist/control-protocol-guard.d.ts +6 -0
  18. package/dist/control-protocol-guard.js +14 -2
  19. package/dist/control-protocol-guard.js.map +1 -1
  20. package/dist/control-schema-version.d.ts +48 -31
  21. package/dist/control-schema-version.js +67 -45
  22. package/dist/control-schema-version.js.map +1 -1
  23. package/dist/control-schema.d.ts +8 -8
  24. package/dist/control-schema.js +16 -16
  25. package/dist/control-schema.js.map +1 -1
  26. package/dist/control-write-retry.d.ts +42 -7
  27. package/dist/control-write-retry.js +87 -19
  28. package/dist/control-write-retry.js.map +1 -1
  29. package/dist/enrolled-machine-store.d.ts +3 -3
  30. package/dist/enrolled-machine-store.js +3 -3
  31. package/dist/formation-token.d.ts +48 -0
  32. package/dist/formation-token.js +26 -0
  33. package/dist/formation-token.js.map +1 -0
  34. package/dist/index.d.ts +15 -14
  35. package/dist/index.js +17 -14
  36. package/dist/index.js.map +1 -1
  37. package/dist/joined-strand-store.d.ts +26 -9
  38. package/dist/joined-strand-store.js +63 -24
  39. package/dist/joined-strand-store.js.map +1 -1
  40. package/dist/link-budget.d.ts +9 -7
  41. package/dist/link-budget.js +9 -7
  42. package/dist/link-budget.js.map +1 -1
  43. package/dist/member-redemption.d.ts +15 -9
  44. package/dist/member-redemption.js +13 -8
  45. package/dist/member-redemption.js.map +1 -1
  46. package/dist/membership-view.d.ts +91 -0
  47. package/dist/membership-view.js +110 -0
  48. package/dist/membership-view.js.map +1 -0
  49. package/dist/owner-grant-protocol.d.ts +11 -7
  50. package/dist/owner-grant-protocol.js +31 -17
  51. package/dist/owner-grant-protocol.js.map +1 -1
  52. package/dist/peer-addr-book.d.ts +10 -1
  53. package/dist/peer-addr-book.js +4 -3
  54. package/dist/peer-addr-book.js.map +1 -1
  55. package/dist/peer-join-backfill.d.ts +96 -30
  56. package/dist/peer-join-backfill.js +272 -128
  57. package/dist/peer-join-backfill.js.map +1 -1
  58. package/dist/pending-join-runner.d.ts +48 -18
  59. package/dist/pending-join-runner.js +74 -56
  60. package/dist/pending-join-runner.js.map +1 -1
  61. package/dist/seed-bootstrap.d.ts +47 -40
  62. package/dist/seed-bootstrap.js +66 -61
  63. package/dist/seed-bootstrap.js.map +1 -1
  64. package/dist/self-address-update.d.ts +13 -0
  65. package/dist/self-address-update.js +19 -0
  66. package/dist/self-address-update.js.map +1 -0
  67. package/dist/strand-database.d.ts +23 -2
  68. package/dist/strand-database.js +26 -6
  69. package/dist/strand-database.js.map +1 -1
  70. package/dist/strand-first-sync-gate.d.ts +176 -89
  71. package/dist/strand-first-sync-gate.js +288 -122
  72. package/dist/strand-first-sync-gate.js.map +1 -1
  73. package/dist/strand-formation-deadlines.d.ts +9 -9
  74. package/dist/strand-formation-deadlines.js +9 -9
  75. package/dist/strand-formation-manager.d.ts +23 -17
  76. package/dist/strand-formation-manager.js +46 -44
  77. package/dist/strand-formation-manager.js.map +1 -1
  78. package/dist/strand-formation-protocol.d.ts +5 -8
  79. package/dist/strand-formation-protocol.js +101 -16
  80. package/dist/strand-formation-protocol.js.map +1 -1
  81. package/dist/strand-instance-manager.d.ts +26 -17
  82. package/dist/strand-instance-manager.js +119 -50
  83. package/dist/strand-instance-manager.js.map +1 -1
  84. package/dist/strand-membership-reconciler.d.ts +16 -13
  85. package/dist/strand-membership-reconciler.js +28 -22
  86. package/dist/strand-membership-reconciler.js.map +1 -1
  87. package/dist/strand-membership-writer.d.ts +40 -28
  88. package/dist/strand-membership-writer.js +212 -153
  89. package/dist/strand-membership-writer.js.map +1 -1
  90. package/dist/strand-move.js +5 -2
  91. package/dist/strand-move.js.map +1 -1
  92. package/dist/strand-revocation-enforcer.d.ts +134 -60
  93. package/dist/strand-revocation-enforcer.js +144 -71
  94. package/dist/strand-revocation-enforcer.js.map +1 -1
  95. package/dist/strand-solicitation.d.ts +50 -39
  96. package/dist/strand-solicitation.js +10 -3
  97. package/dist/strand-solicitation.js.map +1 -1
  98. package/dist/strand-watcher.d.ts +80 -13
  99. package/dist/strand-watcher.js +152 -48
  100. package/dist/strand-watcher.js.map +1 -1
  101. package/dist/table-change-watch.d.ts +63 -0
  102. package/dist/table-change-watch.js +209 -0
  103. package/dist/table-change-watch.js.map +1 -0
  104. package/dist/timeout-scheduler.d.ts +4 -3
  105. package/dist/timeout-scheduler.js +4 -3
  106. package/dist/timeout-scheduler.js.map +1 -1
  107. package/dist/types.d.ts +90 -49
  108. package/dist/types.js +4 -4
  109. package/dist/types.js.map +1 -1
  110. package/package.json +8 -8
  111. package/src/cadre-invite-protocol.ts +119 -31
  112. package/src/cadre-node.ts +1289 -588
  113. package/src/control-cohort.ts +86 -9
  114. package/src/control-database.ts +848 -403
  115. package/src/control-formation-recorder.ts +359 -353
  116. package/src/control-protocol-guard.ts +16 -2
  117. package/src/control-schema-version.ts +101 -51
  118. package/src/control-schema.ts +16 -16
  119. package/src/control-write-retry.ts +91 -19
  120. package/src/delegate-admission.ts +351 -351
  121. package/src/enrolled-machine-store.ts +3 -3
  122. package/src/formation-token.ts +63 -0
  123. package/src/index.ts +30 -18
  124. package/src/joined-strand-store.ts +69 -24
  125. package/src/link-budget.ts +9 -7
  126. package/src/member-redemption.ts +20 -13
  127. package/src/membership-view.ts +144 -0
  128. package/src/owner-grant-protocol.ts +33 -18
  129. package/src/peer-addr-book.ts +4 -3
  130. package/src/peer-join-backfill.ts +961 -761
  131. package/src/pending-join-runner.ts +76 -53
  132. package/src/seed-bootstrap.ts +72 -67
  133. package/src/self-address-update.ts +19 -0
  134. package/src/strand-database.ts +352 -322
  135. package/src/strand-first-sync-gate.ts +334 -134
  136. package/src/strand-formation-deadlines.ts +227 -227
  137. package/src/strand-formation-manager.ts +731 -725
  138. package/src/strand-formation-protocol.ts +122 -24
  139. package/src/strand-instance-manager.ts +2092 -2026
  140. package/src/strand-membership-reconciler.ts +31 -25
  141. package/src/strand-membership-writer.ts +2093 -2019
  142. package/src/strand-move.ts +5 -2
  143. package/src/strand-revocation-enforcer.ts +740 -654
  144. package/src/strand-solicitation.ts +61 -34
  145. package/src/strand-watcher.ts +175 -56
  146. package/src/table-change-watch.ts +285 -0
  147. package/src/timeout-scheduler.ts +29 -28
  148. package/src/types.ts +89 -51
@@ -9,13 +9,21 @@
9
9
  * every `Strand.MemberPeer.PeerId` whose `MemberKey` has no live `Strand.Member`
10
10
  * row. `MemberPeer.MemberExists` runs on insert, so an orphaned binding can only
11
11
  * mean "this member existed and was removed" — it is exactly the durable,
12
- * replicated record of a removed party's machines. Everything NOT in the set is
13
- * admitted. Deliberate consequences:
12
+ * replicated record of a removed party's machines. That holds on the network
13
+ * only because every writer commits a party's `Member` row before its
14
+ * `MemberPeer` row, as separate commits (the membership reconciler does, and
15
+ * `registerMemberPeer` requires an existing member): Optimystic can save a
16
+ * multi-collection transaction's tables separately, and remaining members can
17
+ * apply them in either order. The one exception is the founder's bootstrap,
18
+ * which writes its own `Member` and `MemberPeer` in one transaction; that is
19
+ * acceptable because it commits before any other party has joined, so no other
20
+ * party's enforcer is reading yet. Everything NOT in the set is admitted.
21
+ * Deliberate consequences:
14
22
  *
15
23
  * - **Open strands are untouched.** `Member`/`MemberPeer` carry `OnlyClosed`
16
24
  * checks, so an open strand has no rows and the set is empty — and
17
25
  * `StrandInstanceManager` additionally skips arming this enforcer entirely for
18
- * `Type !== 'c'`, so an open strand does not even poll.
26
+ * `Type !== 'c'`, so an open strand neither subscribes nor reads.
19
27
  * - **A joining party mid-admission is admitted** (it has no orphaned binding).
20
28
  * An allowlist ("only peers bound to live members") was considered and
21
29
  * rejected: a joiner's first membership writes must travel through the very
@@ -44,22 +52,19 @@
44
52
  * Refusing NEW connections only half-honors "no longer be answered to or
45
53
  * communicated with": a long-lived strand connection may never re-dial, so
46
54
  * without teardown a removed party keeps whatever session it already holds.
47
- * There is no push notification to hang teardown off — a REPLICATED revocation
48
- * arrives with no change event (the strand database has no reactive
49
- * subscription; `StrandWatcher` polls for the same reason), and a LOCAL
50
- * `revokeMember`/`leaveStrand` writes through a bare `Database` handle this
51
- * runtime never sees — so teardown rides the snapshot refresh itself, with
52
- * `refresh()` exposed for immediacy
55
+ * Teardown rides the snapshot refresh itself, which runs when the membership
56
+ * tables change (see "When the deny set is refreshed"). `refresh()` is public
57
+ * for a caller that wants to await the cut
53
58
  * (`StrandInstanceManager.refreshRevocationEnforcement` →
54
- * `CadreNode.refreshRevocationEnforcement`).
59
+ * `CadreNode.refreshRevocationEnforcement`): it resolves only after the sweep.
55
60
  *
56
61
  * The sweep is driven by MEMBERSHIP in the deny set, never by an
57
62
  * entered-the-set diff: every refresh hangs up every currently-connected
58
63
  * revoked peer, so a resume, a crashed refresh, or a connection established
59
64
  * between two refreshes cannot leave a session standing (a diff would be a
60
65
  * strict subset of this, so none is kept). A peer with no open connection is
61
- * simply not swept, and a failed `hangUp` is logged, never thrown — the next
62
- * refresh retries it. `hangUp` closes DIRECT and RELAYED connections alike, and
66
+ * simply not swept, and a failed `hangUp` is logged, never thrown, and retried
67
+ * by a refresh {@link REVOCATION_REFRESH_RETRY_MS} later. `hangUp` closes DIRECT and RELAYED connections alike, and
63
68
  * on a strand node running the relay server it also drops any reservation the
64
69
  * revoked peer holds there (a reservation dies with its connection — see the
65
70
  * relay-seam doc in `membership-connection-gater.ts`).
@@ -81,6 +86,25 @@
81
86
  * Best-effort by nature: a removed party learns only if the tombstone
82
87
  * replicated to it before the cut.
83
88
  *
89
+ * ## When the deny set is refreshed
90
+ *
91
+ * Every refresh runs on one table change subscription (`table-change-watch.ts`),
92
+ * single-flight, so no two scheduled refreshes overlap:
93
+ *
94
+ * - **On a change** to `Strand.Member` or `Strand.MemberPeer`. App writes
95
+ * (`revokeMember`, `leaveStrand`) commit on the same Quereus `Database` the
96
+ * subscription is on, so a local removal is acted on within the coalescing
97
+ * window; a replicated one when this node's storage takes it in.
98
+ * - **Once at start**, when the strand's database is published.
99
+ * - **On a backstop** ({@link DEFAULT_REVOCATION_BACKSTOP_MS} after the last
100
+ * refresh settled), for a change that raised no event.
101
+ * - **After a failed refresh**, {@link REVOCATION_REFRESH_RETRY_MS} later. The
102
+ * first successful read also arms the plugin's bridge for replicated changes
103
+ * (the NOTE on `watchTables`), so until one succeeds only local commits wake it.
104
+ * - **After each successful refresh on a wide strand** — more distinct bound peer ids than
105
+ * the cluster size — {@link REVOCATION_WIDE_STRAND_REFRESH_MS} later, because
106
+ * this node may be outside a membership block's cohort and so hear no change.
107
+ *
84
108
  * ## What transfers from the control gater (`membership-connection-gater.ts`)
85
109
  *
86
110
  * Transfers: the two-layer shape (fail-closed per-stream gate as PRIMARY, a
@@ -117,23 +141,33 @@
117
141
  import debug from 'debug';
118
142
  import { decideWithinDeadline } from './membership-connection-gater.js';
119
143
  import { ADMISSION_DECISION_TIMEOUT_MS } from './link-budget.js';
144
+ import { scheduleRuns } from './table-change-watch.js';
120
145
  const log = debug('sereus:cadre:strand-revocation');
121
146
  /**
122
- * Default cadence of the deny-set refresh. Bounded staleness is the accepted
123
- * failure direction (see the module doc's stale-view paragraph); 30 s keeps a
124
- * revoked peer's post-replication admit window in the same order as the
125
- * replication delay itself. Overridable via
126
- * {@link StrandRevocationEnforcementConfig.pollIntervalMs}.
147
+ * Default longest wait between two deny-set refreshes when no membership change
148
+ * is heard. Overridable via {@link StrandRevocationEnforcementConfig.backstopMs}.
149
+ *
150
+ * NOTE: the backstop covers two paths the change subscription does not: a
151
+ * machine that was offline when the removal was committed (it normally takes
152
+ * the blocks in by join backfill or read repair on reconnect, which raise the
153
+ * change too), and any change that reaches storage without an event. The case
154
+ * of a node outside a membership block's cohort is covered by
155
+ * {@link REVOCATION_WIDE_STRAND_REFRESH_MS}, not by this.
156
+ */
157
+ export const DEFAULT_REVOCATION_BACKSTOP_MS = 5 * 60000;
158
+ /**
159
+ * How soon a failed refresh is retried. Also how soon a replicated removal is
160
+ * heard after a first read that failed, since that read is what arms the
161
+ * plugin's replicated-change bridge for the two tables.
127
162
  */
128
- export const DEFAULT_REVOCATION_POLL_INTERVAL_MS = 30000;
129
- const defaultScheduler = {
130
- setInterval: (fn, ms) => {
131
- const handle = setInterval(fn, ms);
132
- handle.unref?.();
133
- return handle;
134
- },
135
- clearInterval: (handle) => clearInterval(handle)
136
- };
163
+ export const REVOCATION_REFRESH_RETRY_MS = 30000;
164
+ /**
165
+ * How soon a strand with more distinct bound peer ids than its cluster size is
166
+ * refreshed again after a successful refresh. On such a strand this node may be
167
+ * outside a membership block's cohort, so it takes in no storage event for a
168
+ * removal (`docs/architecture.md` → "Table change subscriptions").
169
+ */
170
+ export const REVOCATION_WIDE_STRAND_REFRESH_MS = 30000;
137
171
  /** Every `Strand.MemberPeer` binding — live-membered and orphaned alike. */
138
172
  async function scanBindings(db) {
139
173
  const bindings = [];
@@ -162,17 +196,17 @@ async function scanMemberKeys(db) {
162
196
  * separate reads with nothing holding them to one snapshot, so a write that
163
197
  * lands between them is seen by the second scan and not the first. A member
164
198
  * joins as `Member` row then `MemberPeer` row (`MemberExists` forces that
165
- * order), so reading `Member` first would let a join that commits mid-read
166
- * produce a binding whose member key is absent from the key set — a brand-new
167
- * member classified as REVOKED, the one fail-CLOSED outcome this module exists
168
- * to avoid. Reading bindings first inverts the skew: the new binding is simply
169
- * not in the older bindings snapshot, so the joiner is unclassified and
170
- * admitted, and a revocation that lands mid-read is still seen (the key is
171
- * missing from the NEWER key scan). Every skew window then resolves fail-open,
172
- * matching the module doc.
199
+ * order; the module doc says why it holds on the network), so reading `Member`
200
+ * first would let a join that commits mid-read produce a binding whose member
201
+ * key is absent from the key set — a brand-new member classified as REVOKED,
202
+ * the one fail-CLOSED outcome this module exists to avoid. Reading bindings
203
+ * first inverts the skew: the new binding is simply not in the older bindings
204
+ * snapshot, so the joiner is unclassified and admitted, and a revocation that
205
+ * lands mid-read is still seen (the key is missing from the NEWER key scan).
206
+ * Every skew window then resolves fail-open, matching the module doc.
173
207
  *
174
- * NOTE: two whole-table scans per refresh (default every 30 s per closed
175
- * strand). Fine at strand scale (a handful of members and bindings); if
208
+ * NOTE: two whole-table scans per refresh (on each membership change and each
209
+ * backstop, per closed strand). Fine at strand scale (a handful of members and bindings); if
176
210
  * membership churn ever makes these tables large, the fix is a reliable
177
211
  * filtered read — which needs the networked point-lookup gap closed
178
212
  * (`debt-composite-pk-point-lookup-unreliable-untracked`) — not a bigger scan.
@@ -185,14 +219,13 @@ export async function readStrandRevocationRows(db) {
185
219
  /**
186
220
  * The per-strand revoked-peer deny set and the synchronous predicates over it.
187
221
  *
188
- * Lifecycle mirrors `PeerJoinBackfill`: created in
189
- * `StrandInstanceManager.buildStrandRuntime` (closed strands only), started
190
- * after the strand database initializes, stopped and dropped in
191
- * `releaseRuntime` — so quiesce → resume rebuilds it with a fresh snapshot.
192
- * The snapshot starts EMPTY (admit everything) and repopulates on the first
193
- * successful read; a revoked peer therefore gets a short admit window per
194
- * resume at the connection level. Accepted: fail-open posture, and resume is
195
- * never blocked on a refresh.
222
+ * Lifecycle: created in `StrandInstanceManager.buildStrandRuntime` (closed
223
+ * strands only), started when `publishDatabase` hands the strand's database to
224
+ * the app, stopped and dropped in `releaseRuntime` — so quiesce → resume
225
+ * rebuilds it with a fresh snapshot. The snapshot starts EMPTY (admit
226
+ * everything) and repopulates on the first successful read; a revoked peer
227
+ * therefore gets a short admit window per resume at the connection level.
228
+ * Accepted: fail-open posture, and resume is never blocked on a refresh.
196
229
  */
197
230
  export class StrandRevocationEnforcer {
198
231
  constructor(deps, config) {
@@ -201,43 +234,38 @@ export class StrandRevocationEnforcer {
201
234
  this.revokedPeerIds = new Set();
202
235
  /** Tail of the refresh chain — what serializes refreshes (no two reads in flight). */
203
236
  this.refreshTail = Promise.resolve();
204
- this.refreshing = false;
205
237
  this.started = false;
206
238
  this.stopped = false;
207
239
  /** Latch for the one-shot self-revocation signal — see {@link StrandRevocationEnforcerDeps.onSelfRevoked}. */
208
240
  this.selfRevokedSignaled = false;
209
- this.scheduler = deps.scheduler ?? defaultScheduler;
210
- this.pollIntervalMs = config?.pollIntervalMs ?? DEFAULT_REVOCATION_POLL_INTERVAL_MS;
241
+ this.backstopMs = config?.backstopMs ?? DEFAULT_REVOCATION_BACKSTOP_MS;
242
+ this.autoRefresh = config?.autoRefresh ?? true;
211
243
  }
212
244
  /** Number of peers currently denied — test/diagnostic surface. */
213
245
  get revokedCount() {
214
246
  return this.revokedPeerIds.size;
215
247
  }
216
- /** Kick an immediate refresh (not awaited — bring-up never blocks on it) and arm the poll. */
248
+ /**
249
+ * Subscribe to membership changes and run one refresh at once (not awaited —
250
+ * bring-up never blocks on it); the module doc's "When the deny set is
251
+ * refreshed" has the full schedule. Call once the strand's database is
252
+ * published. A second call, or one after {@link stop}, is a no-op.
253
+ */
217
254
  start() {
218
255
  if (this.started || this.stopped)
219
256
  return;
220
257
  this.started = true;
221
- void this.refresh();
222
- this.intervalHandle = this.scheduler.setInterval(() => {
223
- // Skip a tick while a refresh is in flight rather than queueing behind it —
224
- // the interval exists to bound staleness, and a stack of queued reads
225
- // bounds nothing extra. Explicit refresh() calls still chain (see refresh).
226
- if (!this.refreshing) {
227
- void this.refresh();
228
- }
229
- }, this.pollIntervalMs);
230
- log('[%s] revocation enforcer started (poll %dms)', this.deps.label, this.pollIntervalMs);
258
+ this.watch = this.subscribe();
259
+ this.watch.trigger(0);
260
+ log('[%s] revocation enforcer started (backstop %dms)', this.deps.label, this.backstopMs);
231
261
  }
232
- /** Disarm the poll; a read already in flight completes but its result is discarded. */
262
+ /** Stop scheduling refreshes; a read already in flight completes but its result is discarded. */
233
263
  stop() {
234
264
  if (this.stopped)
235
265
  return;
236
266
  this.stopped = true;
237
- if (this.intervalHandle != null) {
238
- this.scheduler.clearInterval(this.intervalHandle);
239
- this.intervalHandle = undefined;
240
- }
267
+ this.watch?.dispose();
268
+ this.watch = undefined;
241
269
  log('[%s] revocation enforcer stopped', this.deps.label);
242
270
  }
243
271
  /**
@@ -269,12 +297,41 @@ export class StrandRevocationEnforcer {
269
297
  authorizeStream(remotePeerId, _protocol) {
270
298
  return !this.isRevoked(remotePeerId);
271
299
  }
300
+ /**
301
+ * The watch every scheduled refresh runs on: the deps' change subscription, or
302
+ * a timer-only one when changes are not watched or the subscription throws.
303
+ *
304
+ * NOTE: a refresh can wake itself once. Its read may start a read-repair sync
305
+ * (a held block read more than Optimystic's `readRepairWindowMs`, 10 s, after
306
+ * its last check), and that sync's landing raises a change. The follow-up
307
+ * refresh runs within the coalescing window plus one read — well inside the
308
+ * read-repair window — so it starts no second sync and the chain stops there.
309
+ * If idle sync counts on a strand do not fall with this subscription, suspect
310
+ * this loop first.
311
+ */
312
+ subscribe() {
313
+ const onChange = () => this.refresh();
314
+ const options = {
315
+ label: `strand-revocation:${this.deps.label}`,
316
+ backstopMs: this.backstopMs,
317
+ scheduler: this.deps.scheduler,
318
+ };
319
+ if (this.autoRefresh && this.deps.watchChanges) {
320
+ try {
321
+ return this.deps.watchChanges(onChange, options);
322
+ }
323
+ catch (error) {
324
+ log('[%s] membership change subscription failed — refreshing on the backstop and retries only: %o', this.deps.label, error);
325
+ }
326
+ }
327
+ return scheduleRuns(onChange, options);
328
+ }
272
329
  /**
273
330
  * One serialized snapshot rebuild; contains every failure (contract: never rejects).
274
331
  *
275
332
  * NOTE: nothing here carries a deadline — a `readRows` or a `hangUp` that never
276
- * settles wedges the refresh chain, which freezes the deny set (the poll skips
277
- * while `refreshing`, and every later `refresh()` chains behind the stuck one).
333
+ * settles wedges the refresh chain, which freezes the deny set (the watch runs
334
+ * one refresh at a time, and every later `refresh()` chains behind the stuck one).
278
335
  * Both are bounded in practice (Quereus reads settle; libp2p's connection close
279
336
  * has its own timeout). If a strand is ever seen with a stale deny set and no
280
337
  * refresh log line, wrap both awaits in a timeout rather than hunting further.
@@ -282,13 +339,13 @@ export class StrandRevocationEnforcer {
282
339
  async doRefresh() {
283
340
  if (this.stopped)
284
341
  return;
285
- this.refreshing = true;
286
342
  try {
287
343
  const rows = await this.deps.readRows();
288
344
  if (this.stopped)
289
345
  return;
290
346
  this.revokedPeerIds = deriveRevokedPeerIds(rows);
291
347
  log('[%s] deny set refreshed: %d revoked peer(s)', this.deps.label, this.revokedPeerIds.size);
348
+ this.followUpWideStrand(rows);
292
349
  // Awaited inside the refresh, so an on-demand refresh() resolves only once
293
350
  // the cut has been made — that is what makes "revoke, then refresh" an
294
351
  // immediate teardown for the caller rather than a scheduled one.
@@ -296,16 +353,31 @@ export class StrandRevocationEnforcer {
296
353
  }
297
354
  catch (error) {
298
355
  log('[%s] deny-set refresh failed — keeping previous snapshot: %o', this.deps.label, error);
356
+ this.scheduleFollowUp(REVOCATION_REFRESH_RETRY_MS, 'refresh failed');
299
357
  }
300
- finally {
301
- this.refreshing = false;
358
+ }
359
+ /** Arm one more refresh `delayMs` from now, unless {@link StrandRevocationEnforcementConfig.autoRefresh} is off or the enforcer is not running. */
360
+ scheduleFollowUp(delayMs, reason) {
361
+ if (!this.autoRefresh || !this.watch)
362
+ return;
363
+ log('[%s] %s — refreshing again in %dms', this.deps.label, reason, delayMs);
364
+ this.watch.trigger(delayMs);
365
+ }
366
+ /** Schedule {@link REVOCATION_WIDE_STRAND_REFRESH_MS} when `rows` bind more distinct peers than the cluster holds. */
367
+ followUpWideStrand(rows) {
368
+ const breadth = this.deps.cohortBreadth;
369
+ if (breadth === undefined)
370
+ return;
371
+ const boundPeers = new Set(rows.bindings.map((binding) => binding.peerId)).size;
372
+ if (boundPeers > breadth) {
373
+ this.scheduleFollowUp(REVOCATION_WIDE_STRAND_REFRESH_MS, `${boundPeers} bound peers on a cluster of ${breadth}`);
302
374
  }
303
375
  }
304
376
  /**
305
377
  * Close what is already OPEN to the peers of `revoked` — the teardown half of
306
378
  * enforcement (module doc: "Removal cuts LIVE sessions too"). Never rejects:
307
- * every failure is contained, so the refresh loop survives and simply retries
308
- * on the next tick.
379
+ * every failure is contained, so the refresh chain survives, and a failed
380
+ * `hangUp` schedules a retry.
309
381
  *
310
382
  * `revoked` is passed IN rather than read off the field, so the sweep judges
311
383
  * the exact snapshot its own refresh produced; likewise the connection list is
@@ -372,7 +444,8 @@ export class StrandRevocationEnforcer {
372
444
  log('[%s] hung up revoked peer %s', this.deps.label, peer.toString());
373
445
  }
374
446
  catch (error) {
375
- log('[%s] hangUp of revoked peer %s failed — next refresh retries: %o', this.deps.label, peer.toString(), error);
447
+ log('[%s] hangUp of revoked peer %s failed: %o', this.deps.label, peer.toString(), error);
448
+ this.scheduleFollowUp(REVOCATION_REFRESH_RETRY_MS, 'hangUp failed');
376
449
  }
377
450
  }
378
451
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"strand-revocation-enforcer.js","sourceRoot":"","sources":["../src/strand-revocation-enforcer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strand-revocation-enforcer.js","sourceRoot":"","sources":["../src/strand-revocation-enforcer.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type { Libp2p } from '@libp2p/interface';
2
2
  import type { OpenInvitation, FormStrandResult, StrandFormationDisclosure } from './types.js';
3
3
  import { type CadrePeerAddrsSource, type MembershipInviteIssuer, type StrandFormationManagerConfig } from './strand-formation-manager.js';
4
4
  import { type FormationResultMessage } from './strand-formation-protocol.js';
5
+ import { type FormationTokenRead } from './formation-token.js';
5
6
  /**
6
7
  * Interface for validating formation disclosures
7
8
  */
@@ -14,6 +15,24 @@ export interface DisclosureValidator {
14
15
  */
15
16
  validateDisclosure(token: string, disclosure: StrandFormationDisclosure): Promise<boolean>;
16
17
  }
18
+ /**
19
+ * A bound invite's host strand as {@link FormationUsageRecorder.resolveStrand} read it, once
20
+ * per session: the membership invitation is issued from it and the consent row recorded
21
+ * against it without reading the `Strand` row again.
22
+ */
23
+ export interface BoundHostStrand {
24
+ strandId: string;
25
+ /** `'c'` closed: the joiner gets a membership invitation; `'o'` open: nothing to invite into. */
26
+ strandType: 'o' | 'c';
27
+ /**
28
+ * The row's one-off `StampId`, which the consent row names (`FormationUsage.StrandStampId`).
29
+ * Fixed for the life of the row; a row removed and re-seated in between gets a new one, and
30
+ * the `StrandExists` CHECK then refuses the consent row.
31
+ */
32
+ strandStampId: string;
33
+ /** The closed-strand read-gating secret; null for an open strand. */
34
+ memberPrivateKey: string | null;
35
+ }
17
36
  /**
18
37
  * Discriminated result of resolving the host strand an invite binds to (responder side):
19
38
  *
@@ -26,20 +45,15 @@ export interface DisclosureValidator {
26
45
  * non-existent strand, which would fail the deferred `FormationUsage.StrandExists` CHECK at
27
46
  * commit and drop the result frame.
28
47
  *
29
- * Replaces the older `{ strandId, memberPrivateKey } | null` shape, which conflated `bound`
30
- * and `missing` (both produced a non-null result whenever the invite had a `StrandId`).
31
- *
32
48
  * The invite's `ValidationUrl` (the outside approval hook) is deliberately NOT surfaced here:
33
- * the recorder that performs the write reads it itself, so the choice of which hook to trust
34
- * never travels through a caller.
49
+ * the recorder that performs the write takes it from the session's {@link FormationTokenRead},
50
+ * so the choice of which hook to trust never travels through a caller.
35
51
  */
36
52
  export type ResolvedHostStrand = {
37
53
  kind: 'unbound';
38
- } | {
54
+ } | ({
39
55
  kind: 'bound';
40
- strandId: string;
41
- memberPrivateKey: string | null;
42
- } | {
56
+ } & BoundHostStrand) | {
43
57
  kind: 'missing';
44
58
  strandId: string;
45
59
  };
@@ -64,47 +78,44 @@ export interface AuthorizedFormationUsage {
64
78
  record(): Promise<void>;
65
79
  }
66
80
  /**
67
- * Interface for recording formation usage
81
+ * The responder's view of the formation-invite tables. A session reads its token once
82
+ * ({@link readToken}) and hands that read to every later step, so no step reads the invite again.
68
83
  */
69
84
  export interface FormationUsageRecorder {
70
85
  /**
71
- * Record that a formation invite was used. Where {@link authorizeUsage} is implemented, this
72
- * is the same as authorizing and then calling `record()` straight away.
86
+ * Record that a formation invite was used, reading the invite for itself. Where
87
+ * {@link authorizeUsage} is implemented, this is the same as reading the token, authorizing,
88
+ * and calling `record()` straight away.
73
89
  */
74
90
  recordUsage(params: FormationUsageParams): Promise<void>;
75
91
  /**
76
92
  * Everything {@link recordUsage} does short of the write: obtain the outside approval (when
77
- * the invite demands one) and pre-check the seat budget, returning a handle whose `record()`
78
- * writes the consent row with exactly the fields that were approved. Lets the manager ask
79
- * before it writes anything into the host strand, and write consent only after.
93
+ * `read` says the invite demands one) and, after an obtained approval, re-check the seat
94
+ * budget, returning a handle whose `record()` writes the consent row with exactly the fields
95
+ * that were approved. Lets the manager ask before it writes anything into the host strand,
96
+ * and write consent only after. `host` is the resolved host strand the consent row names.
80
97
  * Optional: a recorder without it is treated as having nothing to ask up front.
81
98
  */
82
- authorizeUsage?(params: FormationUsageParams): Promise<AuthorizedFormationUsage>;
99
+ authorizeUsage?(params: FormationUsageParams, read: FormationTokenRead, host: BoundHostStrand): Promise<AuthorizedFormationUsage>;
83
100
  /**
84
- * Check if a token has already been used (for single-use invites)
101
+ * Read one token as a formation session acts on it: the invite row (null when there is none
102
+ * here — it may not have replicated yet) and, for a metered unexpired invite, its recorded
103
+ * use count. One read per session; `classifyTokenRead` turns it into the token check.
85
104
  */
86
- isTokenUsed(token: string): Promise<boolean>;
87
- /**
88
- * Check if a token is valid and not expired. An invalid answer says why: `'unknown'` (no
89
- * invitation row here — it may not have replicated yet) or `'expired'`. An answer without
90
- * a reason is treated as `'unknown'`, the retryable one.
91
- */
92
- isTokenValid(token: string): Promise<{
93
- valid: boolean;
94
- reason?: 'unknown' | 'expired';
95
- invitation?: OpenInvitation;
96
- }>;
105
+ readToken(token: string): Promise<FormationTokenRead>;
97
106
  /**
98
- * Resolve the host strand an invite binds to, classifying it as unbound / bound /
99
- * missing (see {@link ResolvedHostStrand}). Optional: a recorder that does not bind
100
- * strands omits it, and {@link StrandFormationManager} treats every invite as `unbound`
101
- * and falls back to its provisioner. Keeping resolution behind this interface keeps the
102
- * manager DB-agnostic and unit-testable with an in-memory fake.
107
+ * Resolve the host strand the read invite binds to, classifying it as unbound / bound /
108
+ * missing (see {@link ResolvedHostStrand}). Reads the `Strand` row, never the invite.
109
+ * Optional: a recorder that does not bind strands omits it, and
110
+ * {@link StrandFormationManager} treats every invite as `unbound` and falls back to its
111
+ * provisioner. Keeping resolution behind this interface keeps the manager DB-agnostic and
112
+ * unit-testable with an in-memory fake.
103
113
  */
104
- resolveStrand?(token: string): Promise<ResolvedHostStrand>;
114
+ resolveStrand?(read: FormationTokenRead): Promise<ResolvedHostStrand>;
105
115
  /**
106
116
  * Provision a NEW strand for an UNBOUND invite and record consent against it
107
117
  * ATOMICALLY (single `FormationUsage` row → single-use enforced on the next redemption).
118
+ * Takes the invite's approval hook and seat budget from `read`.
108
119
  * Optional: a recorder that only supports provision-then-record omits it, and the
109
120
  * manager falls back to its {@link StrandProvisioner}. Mirrors the create-strand-by-consent
110
121
  * path the schema's `Strand.AuthorizedInsert` `FormationUsage` branch authorizes. Returns the
@@ -123,7 +134,7 @@ export interface FormationUsageRecorder {
123
134
  disclosure: string;
124
135
  /** Aborted when the caller has given up; observed BEFORE any write so the invite stays unspent. */
125
136
  signal?: AbortSignal;
126
- }): Promise<{
137
+ }, read: FormationTokenRead): Promise<{
127
138
  strandId: string;
128
139
  memberPrivateKey: string | null;
129
140
  }>;
@@ -131,8 +142,8 @@ export interface FormationUsageRecorder {
131
142
  * Is ANY invitation this recorder knows about unexpired and not fully
132
143
  * consumed? Optional: a recorder that cannot enumerate invitations omits it,
133
144
  * and only locally-minted invitations hold the connection gate's formation
134
- * exemption open. Distinct from the per-token {@link isTokenValid} /
135
- * {@link isTokenUsed} pair — the connection gate has no token to ask about.
145
+ * exemption open. Distinct from the per-token {@link readToken} — the
146
+ * connection gate has no token to ask about.
136
147
  */
137
148
  hasOutstandingInvitation?(): Promise<boolean>;
138
149
  }
@@ -297,8 +308,8 @@ export declare class StrandSolicitationService {
297
308
  * in-memory and dies with the process. Expired entries are dropped. With
298
309
  * no {@link FormationUsageRecorder} configured there is no consumption
299
310
  * oracle, so an unexpired minted token counts as outstanding by
300
- * construction; with one, a token it reports used is deleted (consumption
301
- * is permanent, so the registry never reconsiders it).
311
+ * construction; with one, a token whose row it reads as expired or used up
312
+ * is deleted (both are permanent, so the registry never reconsiders it).
302
313
  * 2. The recorder's optional {@link FormationUsageRecorder.hasOutstandingInvitation},
303
314
  * which survives restarts and sees invitations replicated in from siblings.
304
315
  *
@@ -10,6 +10,7 @@ import { ed25519KeyPairFromLibp2p } from './ed25519-key.js';
10
10
  import { mintPlaceholderStrandId } from './strand-id.js';
11
11
  import { StrandFormationManager } from './strand-formation-manager.js';
12
12
  import { isValidResponderCreatesResult } from './strand-formation-protocol.js';
13
+ import { classifyTokenRead } from './formation-token.js';
13
14
  const log = debug('sereus:cadre:solicitation');
14
15
  /**
15
16
  * Built-in structural {@link FormationResponseValidator}.
@@ -214,8 +215,8 @@ export class StrandSolicitationService {
214
215
  * in-memory and dies with the process. Expired entries are dropped. With
215
216
  * no {@link FormationUsageRecorder} configured there is no consumption
216
217
  * oracle, so an unexpired minted token counts as outstanding by
217
- * construction; with one, a token it reports used is deleted (consumption
218
- * is permanent, so the registry never reconsiders it).
218
+ * construction; with one, a token whose row it reads as expired or used up
219
+ * is deleted (both are permanent, so the registry never reconsiders it).
219
220
  * 2. The recorder's optional {@link FormationUsageRecorder.hasOutstandingInvitation},
220
221
  * which survives restarts and sees invitations replicated in from siblings.
221
222
  *
@@ -232,7 +233,13 @@ export class StrandSolicitationService {
232
233
  if (!this.formationUsageRecorder) {
233
234
  return true;
234
235
  }
235
- if (!(await this.formationUsageRecorder.isTokenUsed(token))) {
236
+ // NOTE: a read of its own, not shared with a formation session's: this runs while a
237
+ // stranger's connection is being admitted, before any stream or token exists, under the
238
+ // gate's fail-open deadline, and the session that follows reads on a different call.
239
+ // An unknown token stays outstanding (its row may not be published yet); an expired or
240
+ // used-up row is dropped, the same `token-spent` the formation handler would answer.
241
+ const check = classifyTokenRead(await this.formationUsageRecorder.readToken(token), now);
242
+ if (check.valid || check.code === 'token-unknown') {
236
243
  return true;
237
244
  }
238
245
  this.mintedInvitations.delete(token);
@@ -1 +1 @@
1
- {"version":3,"file":"strand-solicitation.js","sourceRoot":"","sources":["../src/strand-solicitation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"strand-solicitation.js","sourceRoot":"","sources":["../src/strand-solicitation.ts"],"names":[],"mappings":"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"}