@serfab/cadre-core 0.11.0 → 0.13.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 (121) hide show
  1. package/README.md +3 -2
  2. package/dist/announce-addrs.d.ts +49 -0
  3. package/dist/announce-addrs.js +78 -0
  4. package/dist/announce-addrs.js.map +1 -0
  5. package/dist/cadre-node.d.ts +607 -53
  6. package/dist/cadre-node.js +1268 -157
  7. package/dist/cadre-node.js.map +1 -1
  8. package/dist/control-database.d.ts +174 -23
  9. package/dist/control-database.js +317 -107
  10. package/dist/control-database.js.map +1 -1
  11. package/dist/control-read-retry.d.ts +103 -0
  12. package/dist/control-read-retry.js +145 -0
  13. package/dist/control-read-retry.js.map +1 -0
  14. package/dist/control-retry.d.ts +101 -0
  15. package/dist/control-retry.js +108 -0
  16. package/dist/control-retry.js.map +1 -0
  17. package/dist/control-schema.d.ts +1 -1
  18. package/dist/control-schema.js +50 -6
  19. package/dist/control-schema.js.map +1 -1
  20. package/dist/control-write-retry.d.ts +59 -35
  21. package/dist/control-write-retry.js +21 -92
  22. package/dist/control-write-retry.js.map +1 -1
  23. package/dist/delegate-admission.d.ts +17 -15
  24. package/dist/delegate-admission.js +17 -15
  25. package/dist/delegate-admission.js.map +1 -1
  26. package/dist/enrolled-machine-store-file.d.ts +13 -0
  27. package/dist/enrolled-machine-store-file.js +41 -0
  28. package/dist/enrolled-machine-store-file.js.map +1 -0
  29. package/dist/enrolled-machine-store.d.ts +81 -0
  30. package/dist/enrolled-machine-store.js +225 -0
  31. package/dist/enrolled-machine-store.js.map +1 -0
  32. package/dist/file-durable-slot.js +5 -3
  33. package/dist/file-durable-slot.js.map +1 -1
  34. package/dist/index.d.ts +10 -6
  35. package/dist/index.js +39 -12
  36. package/dist/index.js.map +1 -1
  37. package/dist/membership-connection-gater.d.ts +226 -26
  38. package/dist/membership-connection-gater.js +316 -30
  39. package/dist/membership-connection-gater.js.map +1 -1
  40. package/dist/node-local-snapshot.d.ts +6 -0
  41. package/dist/node-local-snapshot.js +7 -1
  42. package/dist/node-local-snapshot.js.map +1 -1
  43. package/dist/{strand-backfill.d.ts → peer-join-backfill.d.ts} +49 -20
  44. package/dist/{strand-backfill.js → peer-join-backfill.js} +146 -56
  45. package/dist/peer-join-backfill.js.map +1 -0
  46. package/dist/peer-record.d.ts +26 -0
  47. package/dist/peer-record.js +32 -0
  48. package/dist/peer-record.js.map +1 -1
  49. package/dist/relay-addrs.d.ts +145 -22
  50. package/dist/relay-addrs.js +314 -31
  51. package/dist/relay-addrs.js.map +1 -1
  52. package/dist/relay-reservation.d.ts +20 -15
  53. package/dist/relay-reservation.js +18 -14
  54. package/dist/relay-reservation.js.map +1 -1
  55. package/dist/strand-addr-protocol.js +16 -0
  56. package/dist/strand-addr-protocol.js.map +1 -1
  57. package/dist/strand-database.d.ts +12 -0
  58. package/dist/strand-database.js +16 -0
  59. package/dist/strand-database.js.map +1 -1
  60. package/dist/strand-formation-manager.d.ts +22 -9
  61. package/dist/strand-formation-manager.js +20 -12
  62. package/dist/strand-formation-manager.js.map +1 -1
  63. package/dist/strand-formation-protocol.d.ts +83 -9
  64. package/dist/strand-formation-protocol.js +86 -10
  65. package/dist/strand-formation-protocol.js.map +1 -1
  66. package/dist/strand-instance-manager.d.ts +151 -17
  67. package/dist/strand-instance-manager.js +237 -32
  68. package/dist/strand-instance-manager.js.map +1 -1
  69. package/dist/strand-membership-writer.d.ts +118 -14
  70. package/dist/strand-membership-writer.js +203 -15
  71. package/dist/strand-membership-writer.js.map +1 -1
  72. package/dist/strand-network-config.d.ts +84 -0
  73. package/dist/strand-network-config.js +136 -0
  74. package/dist/strand-network-config.js.map +1 -0
  75. package/dist/strand-revocation-enforcer.d.ts +392 -0
  76. package/dist/strand-revocation-enforcer.js +533 -0
  77. package/dist/strand-revocation-enforcer.js.map +1 -0
  78. package/dist/strand-solicitation.d.ts +10 -3
  79. package/dist/strand-solicitation.js +12 -7
  80. package/dist/strand-solicitation.js.map +1 -1
  81. package/dist/strand-wake-protocol.d.ts +47 -2
  82. package/dist/strand-wake-protocol.js +76 -6
  83. package/dist/strand-wake-protocol.js.map +1 -1
  84. package/dist/strand-watcher.js +6 -1
  85. package/dist/strand-watcher.js.map +1 -1
  86. package/dist/types.d.ts +282 -43
  87. package/dist/types.js +7 -1
  88. package/dist/types.js.map +1 -1
  89. package/package.json +16 -8
  90. package/src/announce-addrs.ts +93 -0
  91. package/src/cadre-node.ts +1366 -171
  92. package/src/control-database.ts +2628 -2406
  93. package/src/control-read-retry.ts +167 -0
  94. package/src/control-retry.ts +190 -0
  95. package/src/control-schema.ts +50 -6
  96. package/src/control-write-retry.ts +30 -130
  97. package/src/delegate-admission.ts +17 -15
  98. package/src/enrolled-machine-store-file.ts +43 -0
  99. package/src/enrolled-machine-store.ts +280 -0
  100. package/src/file-durable-slot.ts +5 -3
  101. package/src/index.ts +477 -407
  102. package/src/membership-connection-gater.ts +539 -204
  103. package/src/node-local-snapshot.ts +13 -1
  104. package/src/peer-addr-book.ts +251 -250
  105. package/src/{strand-backfill.ts → peer-join-backfill.ts} +187 -75
  106. package/src/peer-record.ts +33 -0
  107. package/src/relay-addrs.ts +436 -111
  108. package/src/relay-reservation.ts +828 -823
  109. package/src/strand-addr-protocol.ts +17 -0
  110. package/src/strand-database.ts +17 -0
  111. package/src/strand-formation-manager.ts +511 -491
  112. package/src/strand-formation-protocol.ts +808 -692
  113. package/src/strand-instance-manager.ts +899 -611
  114. package/src/strand-membership-writer.ts +232 -15
  115. package/src/strand-network-config.ts +172 -0
  116. package/src/strand-revocation-enforcer.ts +653 -0
  117. package/src/strand-solicitation.ts +484 -472
  118. package/src/strand-wake-protocol.ts +94 -8
  119. package/src/strand-watcher.ts +319 -314
  120. package/src/types.ts +1554 -1309
  121. package/dist/strand-backfill.js.map +0 -1
@@ -1,6 +1,4 @@
1
- import debug from 'debug';
2
- import { unwrapError } from '@quereus/quereus';
3
- const log = debug('sereus:cadre:control-db');
1
+ import { chainMessages, retryControlOperation } from './control-retry.js';
4
2
  /**
5
3
  * Bounded retry for TRANSIENT control-write failures — the classifier and loop behind
6
4
  * `ControlDatabase.lockedWithRetry`, the single funnel every local control write passes
@@ -27,7 +25,9 @@ const log = debug('sereus:cadre:control-db');
27
25
  * list must be safe for all ~19 callers.
28
26
  *
29
27
  * Lives outside `control-database.ts` so a spec can drive the classifier against real engine
30
- * errors without importing the whole database class.
28
+ * errors without importing the whole database class. The loop itself lives in
29
+ * `control-retry.ts`, shared with the READ policy (`control-read-retry.ts`) — this module
30
+ * owns the write policies: their classifiers, attempt counts, backoff and budget.
31
31
  */
32
32
  /**
33
33
  * Attempts allowed per control write: the first, plus two retries of a transiently-failed
@@ -154,8 +154,12 @@ const SUPER_MAJORITY_SHORTFALL_UNANSWERED = /Failed to get super-majority: \d+\/
154
154
  * An aggregate whose details came out EMPTY (possible when `formatBatchStatuses` has no
155
155
  * batches to format) carries neither token, matches nothing here, and is not retried — an
156
156
  * unattributable failure is not a proven non-commit.
157
+ *
158
+ * Exported for the READ classifier (`control-read-retry.ts`), which reuses it verbatim: a
159
+ * `get` batch formats the same single-block `[block:` token, and a read can never produce
160
+ * the commit-phase `[blocks:` shape at all.
157
161
  */
158
- function isUncommittedTransactorAggregate(message) {
162
+ export function isUncommittedTransactorAggregate(message) {
159
163
  return TRANSACTOR_AGGREGATE.test(message) && message.includes(SINGLE_BLOCK_BATCH_TOKEN);
160
164
  }
161
165
  /**
@@ -202,24 +206,6 @@ const SELF_COORDINATION_GRACE_REFUSAL = /Self-coordination blocked: grace-period
202
206
  function isSelfCoordinationGraceRefusal(message) {
203
207
  return SELF_COORDINATION_GRACE_REFUSAL.test(message);
204
208
  }
205
- /**
206
- * Every message in the failure's `cause` chain.
207
- *
208
- * `unwrapError` declares its `message` as `string`, but it follows `.cause` without checking what
209
- * that holds — a chain link that is not an `Error` (a stream rejected with a bare string reason,
210
- * an `AbortSignal.reason` that is a plain object) yields `undefined` there, and calling
211
- * `.includes` on it would throw a `TypeError` out of this classifier, INSIDE `retryControlWrite`'s
212
- * catch, replacing the real control-write failure with a confusing one. Non-strings are dropped:
213
- * a link nobody can read is a link that matches nothing, which is already the conservative answer.
214
- *
215
- * NOTE: a cause chain with a CYCLE would spin forever inside `unwrapError` itself. No error in
216
- * this repo builds one; if a hang ever localises to a control-write failure path, look there.
217
- */
218
- function chainMessages(error) {
219
- return unwrapError(error)
220
- .map(({ message }) => message)
221
- .filter(message => typeof message === 'string');
222
- }
223
209
  /**
224
210
  * The error messages that mean "the cohort did not answer AND nothing committed", and nothing
225
211
  * else. The observed one-shot failure was `registerSelf()` racing a connection still forming:
@@ -260,7 +246,8 @@ const RETRIABLE_SCHEMA_INIT_MATCHERS = [
260
246
  * Did this control write fail because the cluster cohort did not ANSWER — i.e. is
261
247
  * re-presenting the SAME signed write a moment later the right response?
262
248
  *
263
- * Classifies by MESSAGE, walking the `cause` chain with Quereus' own {@link unwrapError} —
249
+ * Classifies by MESSAGE, walking the `cause` chain with the shared {@link chainMessages}
250
+ * (Quereus' own `unwrapError` underneath) —
264
251
  * the failure surface is not recognisable by type. The transactor and the coordinator both throw bare `Error`s, and by
265
252
  * the time one reaches `ControlDatabase` it is wrapped in a `QuereusError` (the real chain
266
253
  * is `QuereusError` → `Error` → `Error`), so the match must work at any depth. Anything
@@ -340,73 +327,15 @@ export const SCHEMA_INIT_RETRY_POLICY = {
340
327
  * so the exact messages downstream code and the degraded-cohort-member scenario assert on
341
328
  * survive. A non-retriable failure propagates from the attempt that raised it.
342
329
  */
343
- export async function retryControlWrite(attempt, options = {}) {
344
- const attempts = Math.max(1, options.attempts ?? CONTROL_WRITE_ATTEMPTS);
345
- const delays = options.delaysMs ?? CONTROL_WRITE_RETRY_DELAYS_MS;
346
- const isRetriable = options.isRetriable ?? isRetriableControlWriteFailure;
347
- const sleep = options.sleep ?? defaultSleep;
348
- const now = options.now ?? Date.now;
349
- // Empty when unlabelled, so an unlabelled line is byte-identical to what this loop
350
- // logged before labels existed.
351
- const tag = options.label ? ` [${options.label}]` : '';
352
- const start = now();
353
- let lastError;
354
- let attemptsMade = 0;
355
- for (let attemptNumber = 1; attemptNumber <= attempts; attemptNumber++) {
356
- attemptsMade = attemptNumber;
357
- try {
358
- const result = await attempt();
359
- if (attemptNumber > 1) {
360
- log('Control write%s committed on attempt %d/%d', tag, attemptNumber, attempts);
361
- }
362
- return result;
363
- }
364
- catch (error) {
365
- if (!isRetriable(error)) {
366
- // The ONLY trace that this funnel saw a failure and declined it. Without it the
367
- // log is silent either way, so "the classifier vetoed this one" is
368
- // indistinguishable from "the retry is not wired into this path at all".
369
- log('Control write%s failed non-transiently on attempt %d/%d, not retried here: %s', tag, attemptNumber, attempts, error);
370
- throw error;
371
- }
372
- lastError = error;
373
- if (attemptNumber === attempts) {
374
- break;
375
- }
376
- const elapsed = now() - start;
377
- if (elapsed >= CONTROL_WRITE_RETRY_BUDGET_MS) {
378
- break;
379
- }
380
- const delay = jitteredDelay(delays, attemptNumber);
381
- log('Control write%s failed transiently (attempt %d/%d), retrying in %d ms: %s', tag, attemptNumber, attempts, delay, error);
382
- await sleep(delay);
383
- }
384
- }
385
- log('Control write%s failed after %d/%d attempt(s): %s', tag, attemptsMade, attempts, lastError);
386
- throw lastError;
387
- }
388
- /**
389
- * Backoff for the retry that follows attempt `attemptNumber`: the matching base delay
390
- * (last entry repeats), jittered ±50%, then capped at the list's largest base so no single
391
- * sleep exceeds it (see {@link CONTROL_WRITE_RETRY_DELAYS_MS} for why). `Math.random` is
392
- * fine here — the jitter only de-synchronizes concurrent retriers, nothing is derived
393
- * from it.
394
- *
395
- * NOTE: the cap bites on the LAST delay, whose base IS the largest, so ~half of those sleeps
396
- * land exactly on the cap rather than spread — de-synchronization is only partial there.
397
- * Harmless while retriers are a handful of party nodes whose attempts already start seconds
398
- * apart; if a party ever retries in a tight synchronized herd, raise the cap above the
399
- * largest base instead of jittering about it.
400
- */
401
- function jitteredDelay(delays, attemptNumber) {
402
- if (delays.length === 0) {
403
- return 0;
404
- }
405
- const base = delays[Math.min(attemptNumber - 1, delays.length - 1)];
406
- const jittered = base * (0.5 + Math.random());
407
- return Math.min(jittered, Math.max(...delays));
408
- }
409
- function defaultSleep(ms) {
410
- return new Promise(resolve => setTimeout(resolve, ms));
330
+ export function retryControlWrite(attempt, options = {}) {
331
+ return retryControlOperation(attempt, {
332
+ attempts: CONTROL_WRITE_ATTEMPTS,
333
+ delaysMs: CONTROL_WRITE_RETRY_DELAYS_MS,
334
+ budgetMs: CONTROL_WRITE_RETRY_BUDGET_MS,
335
+ isRetriable: isRetriableControlWriteFailure,
336
+ // The default prefix, named anyway: the degraded-cohort scenario asserts on
337
+ // `Control write [<label>] …` lines byte-for-byte.
338
+ logPrefix: 'Control write',
339
+ }, options);
411
340
  }
412
341
  //# sourceMappingURL=control-write-retry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,GAAG,GAAG,KAAK,CAAC,yBAAyB,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAM,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,6BAA6B,GAAsB,CAAC,GAAG,EAAE,IAAK,CAAC,CAAC;AAEtE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,2BAA2B,GAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAK,EAAE,IAAK,CAAC,CAAC;AAEhF,+FAA+F;AAC/F,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAE5D;;;GAGG;AACH,MAAM,wBAAwB,GAAG,SAAS,CAAC;AAE3C;;;GAGG;AACH,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,mCAAmC,GACxC,+EAA+E,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,SAAS,gCAAgC,CAAC,OAAe;IACxD,OAAO,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AACzF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,0BAA0B,CAAC,QAA2B;IAC9D,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,mFAAmF;AACnF,SAAS,kCAAkC,CAAC,OAAe;IAC1D,OAAO,mCAAmC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,+BAA+B,GACpC,0FAA0F,CAAC;AAE5F,wFAAwF;AACxF,SAAS,8BAA8B,CAAC,OAAe;IACtD,OAAO,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CAAC,KAAY;IAClC,OAAO,WAAW,CAAC,KAAK,CAAC;SACvB,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC;SAC7B,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,gCAAgC,GAA8C;IACnF,gCAAgC;IAChC,kCAAkC;CAClC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,8BAA8B,GAA8C;IACjF,GAAG,gCAAgC;IACnC,8BAA8B;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAc;IAC5D,OAAO,uBAAuB,CAAC,KAAK,EAAE,gCAAgC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IAC1D,OAAO,uBAAuB,CAAC,KAAK,EAAE,8BAA8B,CAAC,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAC/B,KAAc,EACd,QAAmD;IAEnD,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,0BAA0B,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC;AAuCD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAuC;IAC3E,QAAQ,EAAE,oBAAoB;IAC9B,QAAQ,EAAE,2BAA2B;IACrC,WAAW,EAAE,4BAA4B;CACzC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,OAAyB,EACzB,UAAoC,EAAE;IAEtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,sBAAsB,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,IAAI,6BAA6B,CAAC;IACjE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,8BAA8B,CAAC;IAC1E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,mFAAmF;IACnF,gCAAgC;IAChC,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC;IACpB,IAAI,SAAkB,CAAC;IACvB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,IAAI,aAAa,GAAG,CAAC,EAAE,aAAa,IAAI,QAAQ,EAAE,aAAa,EAAE,EAAE,CAAC;QACxE,YAAY,GAAG,aAAa,CAAC;QAC7B,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;YAC/B,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACvB,GAAG,CAAC,4CAA4C,EAAE,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;YACjF,CAAC;YACD,OAAO,MAAM,CAAC;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,gFAAgF;gBAChF,mEAAmE;gBACnE,yEAAyE;gBACzE,GAAG,CAAC,+EAA+E,EAClF,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACtC,MAAM,KAAK,CAAC;YACb,CAAC;YACD,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,aAAa,KAAK,QAAQ,EAAE,CAAC;gBAChC,MAAM;YACP,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC;YAC9B,IAAI,OAAO,IAAI,6BAA6B,EAAE,CAAC;gBAC9C,MAAM;YACP,CAAC;YACD,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YACnD,GAAG,CAAC,2EAA2E,EAC9E,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;YAC7C,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IACD,GAAG,CAAC,mDAAmD,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACjG,MAAM,SAAS,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CAAC,MAAyB,EAAE,aAAqB;IACtE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,CAAC;IACV,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAE,CAAC;IACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,YAAY,CAAC,EAAU;IAC/B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACxD,CAAC"}
1
+ {"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"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"}
@@ -5,24 +5,26 @@
5
5
  * A strand node runs as its own libp2p instance with its own transport peerId,
6
6
  * derived from the cadre identity key + strandId (`strand-transport-key.ts`).
7
7
  * That derivation uses the member's PRIVATE seed by design, so no third party —
8
- * including a co-cadre relay — can recompute it. When a NAT'd member's strand
9
- * node tries to reserve a circuit-relay slot on a sibling's control node, the
10
- * relay's membership connection gater sees an unknown peerId and denies the
11
- * connection, which kills the reservation and fails the strand's
12
- * `libp2p.start()` outright.
8
+ * including a co-cadre relay — can recompute it: a sibling's relay sees an
9
+ * unknown peerId it has no way to place as a member.
13
10
  *
14
- * The resolution (docs/strands.md → "Relays and admission"): a party control
11
+ * The resolution (docs/strands.md → "Relay willingness"): a party control
15
12
  * node running a relay is party-private infrastructure — it relays for its own
16
13
  * party's nodes, including the extra transport identities its members' strand
17
- * nodes run as, and for nobody else. The mechanism is a **member-announced
18
- * delegate grant**: before a member's control node starts a strand node, it
19
- * tells its siblings (over the already-authenticated `/sereus/strand-addr/1.0.0`
20
- * RPC) the derived peerId that strand node will use, and the receiver holds a
21
- * short-lived, in-memory admission grant for exactly that peerId. The grant is
22
- * consulted ONLY by the connection-level gate
23
- * (`CadreNode.admitInboundControlConnection`); the fail-closed per-stream gate
24
- * (`authorizeInboundControlStream`) never honors it, so a delegate gets the
25
- * connection (all a circuit-relay `hop` reservation needs) and nothing more.
14
+ * nodes run as. The mechanism is a **member-announced delegate grant**: before
15
+ * a member's control node starts a strand node, it tells its siblings (over the
16
+ * already-authenticated `/sereus/strand-addr/1.0.0` RPC) the derived peerId
17
+ * that strand node will use, and the receiver holds a short-lived, in-memory
18
+ * admission grant for exactly that peerId. The grant is consulted by the
19
+ * connection-level gate (`CadreNode.admitInboundControlConnection`) and by the
20
+ * relay-reservation admission (`CadreNode.admitControlRelayReservation`) — a
21
+ * granted delegate is admitted outright, never drawing on the small
22
+ * unauthorized-reservation budget that unplaced peers share
23
+ * (`membership-connection-gater.ts` → "The relay-reservation seam") and never
24
+ * racing its not-reserving connection deadline. The fail-closed per-stream gate
25
+ * (`authorizeInboundControlStream`) never honors a grant, so a delegate gets
26
+ * the connection and its reservation (all a circuit-relay `hop` needs) and
27
+ * nothing more.
26
28
  *
27
29
  * A grant is a delegation of trust to an already-trusted member: the receiver
28
30
  * cannot verify that the announced peerId really is the member's strand node,
@@ -5,24 +5,26 @@
5
5
  * A strand node runs as its own libp2p instance with its own transport peerId,
6
6
  * derived from the cadre identity key + strandId (`strand-transport-key.ts`).
7
7
  * That derivation uses the member's PRIVATE seed by design, so no third party —
8
- * including a co-cadre relay — can recompute it. When a NAT'd member's strand
9
- * node tries to reserve a circuit-relay slot on a sibling's control node, the
10
- * relay's membership connection gater sees an unknown peerId and denies the
11
- * connection, which kills the reservation and fails the strand's
12
- * `libp2p.start()` outright.
8
+ * including a co-cadre relay — can recompute it: a sibling's relay sees an
9
+ * unknown peerId it has no way to place as a member.
13
10
  *
14
- * The resolution (docs/strands.md → "Relays and admission"): a party control
11
+ * The resolution (docs/strands.md → "Relay willingness"): a party control
15
12
  * node running a relay is party-private infrastructure — it relays for its own
16
13
  * party's nodes, including the extra transport identities its members' strand
17
- * nodes run as, and for nobody else. The mechanism is a **member-announced
18
- * delegate grant**: before a member's control node starts a strand node, it
19
- * tells its siblings (over the already-authenticated `/sereus/strand-addr/1.0.0`
20
- * RPC) the derived peerId that strand node will use, and the receiver holds a
21
- * short-lived, in-memory admission grant for exactly that peerId. The grant is
22
- * consulted ONLY by the connection-level gate
23
- * (`CadreNode.admitInboundControlConnection`); the fail-closed per-stream gate
24
- * (`authorizeInboundControlStream`) never honors it, so a delegate gets the
25
- * connection (all a circuit-relay `hop` reservation needs) and nothing more.
14
+ * nodes run as. The mechanism is a **member-announced delegate grant**: before
15
+ * a member's control node starts a strand node, it tells its siblings (over the
16
+ * already-authenticated `/sereus/strand-addr/1.0.0` RPC) the derived peerId
17
+ * that strand node will use, and the receiver holds a short-lived, in-memory
18
+ * admission grant for exactly that peerId. The grant is consulted by the
19
+ * connection-level gate (`CadreNode.admitInboundControlConnection`) and by the
20
+ * relay-reservation admission (`CadreNode.admitControlRelayReservation`) — a
21
+ * granted delegate is admitted outright, never drawing on the small
22
+ * unauthorized-reservation budget that unplaced peers share
23
+ * (`membership-connection-gater.ts` → "The relay-reservation seam") and never
24
+ * racing its not-reserving connection deadline. The fail-closed per-stream gate
25
+ * (`authorizeInboundControlStream`) never honors a grant, so a delegate gets
26
+ * the connection and its reservation (all a circuit-relay `hop` needs) and
27
+ * nothing more.
26
28
  *
27
29
  * A grant is a delegation of trust to an already-trusted member: the receiver
28
30
  * cannot verify that the announced peerId really is the member's strand node,
@@ -1 +1 @@
1
- {"version":3,"file":"delegate-admission.js","sourceRoot":"","sources":["../src/delegate-admission.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"delegate-admission.js","sourceRoot":"","sources":["../src/delegate-admission.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { EnrolledMachineStore } from './enrolled-machine-store.js';
2
+ /**
3
+ * File-backed {@link EnrolledMachineStore}. Open via {@link open}, which loads the
4
+ * existing file and returns the cross-platform store over it. An absent, corrupt,
5
+ * wrong-party, junk-valued **or unreadable** file is a cold start (`count()` is
6
+ * `undefined`, the node declares no repair yardstick and runs at the base control
7
+ * policy) — `open` never rejects, unlike the sibling stores' file backends. That
8
+ * divergence and its reasoning live on `enrolled-machine-store.ts`.
9
+ */
10
+ export declare const FileEnrolledMachineStore: {
11
+ /** Load (or cold-start) the party's last recorded machine count from a file in `dir`. */
12
+ open(dir: string, partyId: string): Promise<EnrolledMachineStore>;
13
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Node-only file-backed {@link EnrolledMachineStore}: one JSON file per party under
3
+ * a configured directory (the node's state directory — `cadre-cli` passes
4
+ * `ResolvedConfig.nodeStateDir`), holding the node-local, non-replicated count of
5
+ * machines this party had enrolled the last time this node looked.
6
+ *
7
+ * Nothing but the file itself lives here: the envelope, the cold-start-on-anything
8
+ * load policy (deliberately NOT the throw-on-unreadable policy its two sibling
9
+ * records use — see the `enrolled-machine-store.ts` module comment) and the
10
+ * serialised writes are cross-platform in `PersistentEnrolledMachineStore`, and the
11
+ * file is a `FileDurableSlot`. This module exists only so the `node:fs` edge stays
12
+ * out of the package's cross-platform default entry (`./index.js`) — import it from
13
+ * the dedicated subpath instead:
14
+ *
15
+ * ```ts
16
+ * import { FileEnrolledMachineStore } from '@serfab/cadre-core/enrolled-machine-store-file';
17
+ * ```
18
+ *
19
+ * A React Native / browser entry graph never resolves this path, so the `node:fs`
20
+ * edge never reaches a bundler that cannot satisfy it (same isolation pattern as
21
+ * `bootstrap-peer-store-file.ts` / `trusted-owner-store-file.ts` / `key-store-file.ts`).
22
+ */
23
+ import { FileDurableSlot } from './file-durable-slot.js';
24
+ import { PersistentEnrolledMachineStore } from './enrolled-machine-store.js';
25
+ /** Base name of the store file: `<dir>/enrolled-machines.<encoded partyId>.json`. */
26
+ const SLOT_NAME = 'enrolled-machines';
27
+ /**
28
+ * File-backed {@link EnrolledMachineStore}. Open via {@link open}, which loads the
29
+ * existing file and returns the cross-platform store over it. An absent, corrupt,
30
+ * wrong-party, junk-valued **or unreadable** file is a cold start (`count()` is
31
+ * `undefined`, the node declares no repair yardstick and runs at the base control
32
+ * policy) — `open` never rejects, unlike the sibling stores' file backends. That
33
+ * divergence and its reasoning live on `enrolled-machine-store.ts`.
34
+ */
35
+ export const FileEnrolledMachineStore = {
36
+ /** Load (or cold-start) the party's last recorded machine count from a file in `dir`. */
37
+ async open(dir, partyId) {
38
+ return PersistentEnrolledMachineStore.open(new FileDurableSlot(dir, SLOT_NAME, partyId), partyId);
39
+ }
40
+ };
41
+ //# sourceMappingURL=enrolled-machine-store-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrolled-machine-store-file.js","sourceRoot":"","sources":["../src/enrolled-machine-store-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAG7E,qFAAqF;AACrF,MAAM,SAAS,GAAG,mBAAmB,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACvC,yFAAyF;IACzF,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,OAAe;QACtC,OAAO,8BAA8B,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IACnG,CAAC;CACD,CAAC"}
@@ -0,0 +1,81 @@
1
+ import type { DurableSlot } from './node-local-snapshot.js';
2
+ export interface EnrolledMachineStore {
3
+ /** Party this store is scoped to. */
4
+ readonly partyId: string;
5
+ /**
6
+ * Machines last recorded for this party, or `undefined` when nothing usable was
7
+ * ever recorded — a brand-new node, or a slot that could not be read. Callers
8
+ * pass this straight to `controlClusterPolicy`, whose `undefined` branch returns
9
+ * the frozen base policy unchanged, so "this node does not know" and "this node
10
+ * has never run" are the same declaration: none.
11
+ */
12
+ count(): number | undefined;
13
+ /**
14
+ * Record the current count. Reflected by {@link count} SYNCHRONOUSLY; the
15
+ * returned promise resolves once the persist attempt has settled.
16
+ *
17
+ * **Never rejects.** Its sole caller is
18
+ * `CadreNode.refreshAuthorizedControlPeers`, whose contract is never-rejects and
19
+ * which leaves the promise un-awaited (`void`) — so a rejection here would
20
+ * surface as an unhandled rejection in the embedder's process, over a hint that
21
+ * re-lands on the next refresh anyway. A failed persist is LOGGED, and the
22
+ * in-memory count stays correct for this session.
23
+ *
24
+ * A count that is not a positive integer is a caller bug: it is logged and
25
+ * IGNORED rather than persisted, so a degenerate value can never reach the slot
26
+ * and be read back as a declaration nobody chose.
27
+ */
28
+ record(count: number): Promise<void>;
29
+ }
30
+ /**
31
+ * Ephemeral in-memory store — the default when no store is injected via
32
+ * `CadreNodeConfig.enrolledMachines`. A node using this cold-starts on every
33
+ * launch: `count()` is `undefined` at `start()`, so its control node declares
34
+ * nothing and runs at today's behaviour, exactly as before this record existed.
35
+ */
36
+ export declare class MemoryEnrolledMachineStore implements EnrolledMachineStore {
37
+ readonly partyId: string;
38
+ private current;
39
+ constructor(partyId: string);
40
+ count(): number | undefined;
41
+ record(count: number): Promise<void>;
42
+ }
43
+ /**
44
+ * Durable {@link EnrolledMachineStore} over an app-supplied {@link DurableSlot} —
45
+ * the cross-platform half of every persistent backend (the Node
46
+ * `FileEnrolledMachineStore` is this class over a file slot).
47
+ *
48
+ * Construct via {@link open}. Load policy is the module comment's: every failure
49
+ * mode cold-starts, and `open` never rejects.
50
+ */
51
+ export declare class PersistentEnrolledMachineStore implements EnrolledMachineStore {
52
+ private readonly slot;
53
+ readonly partyId: string;
54
+ /** Serialises persists so the last count recorded is the last one written. */
55
+ private writeChain;
56
+ /** Last count accepted, whether or not it has reached the slot yet. */
57
+ private current;
58
+ /** Last count believed to BE in the slot; drives the unchanged-write skip. */
59
+ private persisted;
60
+ private constructor();
61
+ /** Load (or cold-start) the party's last recorded machine count from `slot`. */
62
+ static open(slot: DurableSlot, partyId: string): Promise<PersistentEnrolledMachineStore>;
63
+ count(): number | undefined;
64
+ /**
65
+ * Record the count: visible via {@link count} synchronously, then persisted.
66
+ *
67
+ * Writes are SKIPPED when the slot already holds this number, because the sole
68
+ * caller runs on every committed membership write *and* every timed reconcile
69
+ * pass — a party whose membership is stable would otherwise rewrite the same
70
+ * integer forever. The skip is keyed off {@link persisted} rather than
71
+ * {@link current}, so a write that FAILED is retried by the next refresh instead
72
+ * of being suppressed as "unchanged".
73
+ */
74
+ record(count: number): Promise<void>;
75
+ /**
76
+ * Write whatever {@link current} holds when this link of the chain runs — so a
77
+ * burst of records collapses into one write of the latest value — and never
78
+ * throw (see {@link EnrolledMachineStore.record}).
79
+ */
80
+ private persistCurrent;
81
+ }