@serfab/cadre-core 1.9.0 → 1.11.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 (119) hide show
  1. package/dist/cadre-node.d.ts +148 -44
  2. package/dist/cadre-node.js +363 -139
  3. package/dist/cadre-node.js.map +1 -1
  4. package/dist/control-authorization.d.ts +2 -2
  5. package/dist/control-authorization.js +1 -0
  6. package/dist/control-authorization.js.map +1 -1
  7. package/dist/control-cohort.d.ts +1 -1
  8. package/dist/control-cohort.js +1 -1
  9. package/dist/control-database.d.ts +105 -14
  10. package/dist/control-database.js +242 -73
  11. package/dist/control-database.js.map +1 -1
  12. package/dist/control-formation-recorder.d.ts +6 -6
  13. package/dist/control-formation-recorder.js +7 -8
  14. package/dist/control-formation-recorder.js.map +1 -1
  15. package/dist/control-schema.d.ts +1 -1
  16. package/dist/control-schema.js +1066 -979
  17. package/dist/control-schema.js.map +1 -1
  18. package/dist/control-write-retry.d.ts +21 -15
  19. package/dist/control-write-retry.js +21 -15
  20. package/dist/control-write-retry.js.map +1 -1
  21. package/dist/diagnostics/connection-path.d.ts +1 -18
  22. package/dist/diagnostics/connection-path.js +1 -20
  23. package/dist/diagnostics/connection-path.js.map +1 -1
  24. package/dist/identity-key.d.ts +0 -30
  25. package/dist/identity-key.js +7 -40
  26. package/dist/identity-key.js.map +1 -1
  27. package/dist/index.d.ts +8 -5
  28. package/dist/index.js +12 -6
  29. package/dist/index.js.map +1 -1
  30. package/dist/invitation-bootstrap.d.ts +32 -0
  31. package/dist/invitation-bootstrap.js +30 -0
  32. package/dist/invitation-bootstrap.js.map +1 -0
  33. package/dist/link-budget.d.ts +204 -119
  34. package/dist/link-budget.js +208 -120
  35. package/dist/link-budget.js.map +1 -1
  36. package/dist/membership-connection-gater.d.ts +3 -3
  37. package/dist/membership-connection-gater.js +3 -3
  38. package/dist/peer-dial.d.ts +18 -14
  39. package/dist/peer-dial.js +18 -14
  40. package/dist/peer-dial.js.map +1 -1
  41. package/dist/peer-join-backfill.d.ts +3 -3
  42. package/dist/pending-join-runner.d.ts +186 -0
  43. package/dist/pending-join-runner.js +649 -0
  44. package/dist/pending-join-runner.js.map +1 -0
  45. package/dist/push-fanout.d.ts +1 -1
  46. package/dist/push-fanout.js +1 -1
  47. package/dist/relay-stun.d.ts +24 -0
  48. package/dist/relay-stun.js +51 -0
  49. package/dist/relay-stun.js.map +1 -0
  50. package/dist/seed-bootstrap.d.ts +2 -2
  51. package/dist/seed-bootstrap.js +5 -5
  52. package/dist/strand-addr-protocol.js +2 -2
  53. package/dist/strand-formation-deadlines.d.ts +5 -5
  54. package/dist/strand-formation-deadlines.js +5 -5
  55. package/dist/strand-formation-manager.d.ts +18 -4
  56. package/dist/strand-formation-manager.js +48 -33
  57. package/dist/strand-formation-manager.js.map +1 -1
  58. package/dist/strand-formation-protocol.d.ts +71 -14
  59. package/dist/strand-formation-protocol.js +222 -47
  60. package/dist/strand-formation-protocol.js.map +1 -1
  61. package/dist/strand-formation-rejection.d.ts +94 -0
  62. package/dist/strand-formation-rejection.js +77 -0
  63. package/dist/strand-formation-rejection.js.map +1 -0
  64. package/dist/strand-instance-manager.js +4 -1
  65. package/dist/strand-instance-manager.js.map +1 -1
  66. package/dist/strand-membership-writer.js +32 -32
  67. package/dist/strand-solicitation.d.ts +11 -3
  68. package/dist/strand-solicitation.js +9 -0
  69. package/dist/strand-solicitation.js.map +1 -1
  70. package/dist/types.d.ts +103 -17
  71. package/dist/types.js +5 -9
  72. package/dist/types.js.map +1 -1
  73. package/package.json +22 -22
  74. package/src/cadre-node.ts +8654 -8400
  75. package/src/control-authorization.ts +2 -1
  76. package/src/control-cohort.ts +128 -128
  77. package/src/control-database.ts +303 -82
  78. package/src/control-formation-recorder.ts +353 -354
  79. package/src/control-read-retry.ts +216 -216
  80. package/src/control-schema.ts +1078 -991
  81. package/src/control-write-retry.ts +567 -561
  82. package/src/diagnostics/connection-path.ts +1 -29
  83. package/src/formation-approval.ts +610 -610
  84. package/src/hibernation-manager.ts +638 -638
  85. package/src/identity-key.ts +7 -62
  86. package/src/index.ts +644 -627
  87. package/src/invitation-bootstrap.ts +40 -0
  88. package/src/joined-strand-store.ts +498 -498
  89. package/src/link-budget.ts +684 -583
  90. package/src/membership-connection-gater.ts +570 -570
  91. package/src/node-local-snapshot.ts +298 -298
  92. package/src/peer-dial.ts +315 -311
  93. package/src/peer-join-backfill.ts +710 -710
  94. package/src/pending-join-runner.ts +735 -0
  95. package/src/push-fanout.ts +1 -1
  96. package/src/relay-reservation.ts +1121 -1121
  97. package/src/relay-server.ts +98 -98
  98. package/src/relay-stun.ts +58 -0
  99. package/src/seed-bootstrap.ts +1448 -1448
  100. package/src/strand-addr-protocol.ts +547 -547
  101. package/src/strand-database.ts +287 -287
  102. package/src/strand-first-sync-gate.ts +391 -391
  103. package/src/strand-formation-deadlines.ts +227 -227
  104. package/src/strand-formation-manager.ts +725 -700
  105. package/src/strand-formation-protocol.ts +1036 -802
  106. package/src/strand-formation-rejection.ts +129 -0
  107. package/src/strand-fret-addrs.ts +145 -145
  108. package/src/strand-instance-manager.ts +1789 -1786
  109. package/src/strand-membership-writer.ts +1974 -1974
  110. package/src/strand-network-state-file.ts +40 -40
  111. package/src/strand-network-state.ts +243 -243
  112. package/src/strand-revocation-enforcer.ts +654 -654
  113. package/src/strand-solicitation.ts +532 -519
  114. package/src/strand-wake-protocol.ts +401 -401
  115. package/src/types.ts +2222 -2140
  116. package/dist/diagnostics/webrtc-turn-tracker.d.ts +0 -50
  117. package/dist/diagnostics/webrtc-turn-tracker.js +0 -196
  118. package/dist/diagnostics/webrtc-turn-tracker.js.map +0 -1
  119. package/src/diagnostics/webrtc-turn-tracker.ts +0 -222
package/dist/peer-dial.js CHANGED
@@ -2,12 +2,15 @@
2
2
  * Dialing one peer from a list of candidate addresses, so that an address that
3
3
  * never answers cannot use up the time the others needed.
4
4
  *
5
- * libp2p's own multi-address dial (`libp2p.dial(addrs)`, libp2p 3.1.3's
6
- * `DialQueue.dialPeer`) tries the addresses ONE AT A TIME under ONE signal, with
7
- * no time limit per address. An address whose connection attempt is silently
8
- * dropped — a firewall, a subnet the dialer cannot route to, a virtual adapter's
9
- * address a Windows host reports alongside its real ones — holds that dial until
10
- * the whole signal expires, and every address sorted after it is never tried. It
5
+ * libp2p's own multi-address dial (`libp2p.dial(addrs)`, `DialQueue.dialPeer`)
6
+ * tries the addresses ONE AT A TIME under ONE signal. Its only per-address limit
7
+ * is the connection manager's `addressDialTimeout` (libp2p 3.3+), which cadre
8
+ * sizes for a cold relayed open through two admission decisions
9
+ * (`optimysticDialLimits` in `link-budget.ts`: 39 s at the default declared
10
+ * link). An address whose connection attempt is silently dropped — a firewall, a
11
+ * subnet the dialer cannot route to, a virtual adapter's address a Windows host
12
+ * reports alongside its real ones — holds that dial for that long or until the
13
+ * whole signal expires, and the addresses sorted after it get what is left. It
11
14
  * also sorts the list itself (`defaultAddressSorter`), putting loopback addresses
12
15
  * last, behind exactly the LAN addresses most likely to be dropped. A phone
13
16
  * borrowing a node from a cadre-host whose only reachable address was the
@@ -29,17 +32,17 @@ import { relayedDialBudgetMs } from './link-budget.js';
29
32
  const log = debug('sereus:cadre:peer-dial');
30
33
  /**
31
34
  * Default limit on ONE address's dial attempt, in ms, at the DEFAULT declared link round trip:
32
- * `RELAYED_DIAL_ROUND_TRIPS` (4) x `DECLARED_LINK_ROUND_TRIP_MS` (3500 ms) plus the called
33
- * machine's `ADMISSION_DECISION_TIMEOUT_MS` (2000 ms) = 16 000 ms (`relayedDialBudgetMs`). It
34
- * was a fixed 8000 ms before it was derived.
35
+ * `RELAYED_DIAL_ROUND_TRIPS` (5) x `DECLARED_LINK_ROUND_TRIP_MS` (3500 ms) plus
36
+ * `DIAL_ADMISSION_DECISIONS` (2) x `ADMISSION_DECISION_TIMEOUT_MS` (2000 ms) = 21 500 ms
37
+ * (`relayedDialBudgetMs`). It was a fixed 8000 ms before it was derived.
35
38
  *
36
39
  * It has to cover the slowest address that should succeed, because an attempt
37
40
  * that needs longer fails the same way on every retry. That is a relayed dial on
38
41
  * a mobile link: connect to the relay (transport, encryption and multiplexer
39
42
  * handshakes, when no relay connection is open yet), open the circuit, then run
40
43
  * both handshakes again end to end through the relay. `link-budget.ts` is where that
41
- * reasoning is now a measured count instead of an estimate — four link round trips, measured at
42
- * 12 094 ms on a link whose round trip is 3 s — so the value MOVES with a host's
44
+ * reasoning is now a measured count instead of an estimate — five link round trips, measured at
45
+ * 15 113 ms on a link whose round trip is 3 s — so the value MOVES with a host's
43
46
  * `NetworkConfig.linkRoundTripMs` rather than pinning the band this node can reach to whatever
44
47
  * number was typed here. A direct dial that works is far quicker — a phone's WebSocket dial to
45
48
  * a node forwarded over `adb reverse` measured 1.6 s end to end.
@@ -162,9 +165,10 @@ export async function dialPeerAddrs(dialer, addrs, budget, label) {
162
165
  * one address and immediately dialing the next for the same peer therefore
163
166
  * joins the dying job, which rejects the new dial with `AbortError` before it
164
167
  * touches the network — the next address is never tried. Seen against libp2p
165
- * 3.1.3; `test/peer-dial.spec.ts` dials real nodes so an upgrade that changes it
166
- * shows up there. All of the queue's cleanup runs as microtasks, so it has
167
- * finished by the time a macrotask runs.
168
+ * 3.1.3, and the queue's join is unchanged in 3.3.11; `test/peer-dial.spec.ts`
169
+ * dials real nodes so an upgrade that changes it shows up there. All of the
170
+ * queue's cleanup runs as microtasks, so it has finished by the time a
171
+ * macrotask runs.
168
172
  */
169
173
  export async function tryAddrsInTurn(addrs, budget, label, attempt) {
170
174
  const deadline = Date.now() + budget.totalMs;
@@ -1 +1 @@
1
- {"version":3,"file":"peer-dial.js","sourceRoot":"","sources":["../src/peer-dial.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"peer-dial.js","sourceRoot":"","sources":["../src/peer-dial.ts"],"names":[],"mappings":"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"}
@@ -28,9 +28,9 @@ export interface PeerJoinBackfillConfig {
28
28
  /** Max blocks per push message. Default 64. */
29
29
  maxChunkBlocks?: number;
30
30
  /**
31
- * Per-push dial deadline, ms. Default {@link peerJoinPushBudget}'s `dialTimeoutMs` — four link
32
- * round trips at the declared link plus the called machine's admission decision, 16 000 ms as
33
- * shipped. NOT a fixed number: a relayed dial
31
+ * Per-push dial deadline, ms. Default {@link peerJoinPushBudget}'s `dialTimeoutMs` — five link
32
+ * round trips at the declared link plus two admission decisions (a party-run relay's and the
33
+ * called machine's), 21 500 ms as shipped. NOT a fixed number: a relayed dial
34
34
  * costs a fixed number of exchanges, so a host on a slower link moves this (and every other
35
35
  * cadre dial budget) by declaring `NetworkConfig.linkRoundTripMs`. Naming it here still wins
36
36
  * over the derived value — `link-budget.ts` has the counts and the measurement.
@@ -0,0 +1,186 @@
1
+ /**
2
+ * The pending-join retry loop: carries on a join this party asked for through another party's
3
+ * invitation (`CadreControl.PendingJoin`, one row per invitation) in the background, on every
4
+ * owner machine of the party, until the join works, the invitation is used up or expires, or
5
+ * the user dismisses it. The behaviour is described in `docs/strands.md` → "Joining while the
6
+ * inviter is offline".
7
+ *
8
+ * `CadreNode` owns every side effect and hands this module plain functions
9
+ * ({@link PendingJoinRunnerDeps}): read the rows, run one attempt (its own `formStrand`), write
10
+ * an outcome, say whether this machine is an owner, and the clock. This module owns the policy:
11
+ * when to attempt, how to read an attempt's failure, and how to settle an outcome write that
12
+ * another machine's write beat.
13
+ *
14
+ * Only owner machines run it, because every `PendingJoin` write is owner-signed. Letting a
15
+ * machine without an owner key finish a join is `blocked/decide-non-owner-machine-completes-a-pending-join`;
16
+ * that changes {@link PendingJoinRunnerDeps.isOwner} and the write functions, not this loop.
17
+ */
18
+ import type { FormStrandResult, PendingJoinRow, PendingJoinStatus, StrandFormationDisclosure, StrandMembershipInvite } from './types.js';
19
+ import { type TimeoutScheduler } from './timeout-scheduler.js';
20
+ /** How often an owner machine re-reads the party's pending joins (it also reads once right after start). */
21
+ export declare const PENDING_JOIN_POLL_MS = 30000;
22
+ /** Ceiling on the wait between two attempts of one join on one machine, before jitter. */
23
+ export declare const PENDING_JOIN_MAX_BACKOFF_MS: number;
24
+ /**
25
+ * The longest a join is tried for. A row's `ExpiresAt` is the earlier of this and the
26
+ * invitation's own expiration, which the inviter chose.
27
+ */
28
+ export declare const MAX_PENDING_JOIN_MS: number;
29
+ /** A `PendingJoin` row as written: every column but the stamp, which each write mints. */
30
+ export type PendingJoinFields = Omit<PendingJoinRow, 'StampId'>;
31
+ export interface PendingJoinRunnerDeps {
32
+ /** This machine's peer id; with the row id it fixes when this machine first tries a row it did not ask for. */
33
+ selfId: string;
34
+ /** `NetworkConfig.linkRoundTripMs`: the retry pace follows the formation deadlines it yields. */
35
+ linkRoundTripMs?: number;
36
+ /** Whether this machine may write `PendingJoin` rows now. Asked every pass. */
37
+ isOwner(): Promise<boolean>;
38
+ readRows(): Promise<PendingJoinRow[]>;
39
+ readRow(id: string): Promise<PendingJoinRow | null>;
40
+ /** One formation attempt for the row's invitation and disclosure (`CadreNode.formStrand`). */
41
+ attempt(row: PendingJoinRow): Promise<FormStrandResult>;
42
+ /** `ControlDatabase.replacePendingJoin`, owner-signed: throws `PendingJoinChangedError` when the live row is not `expectedStampId`. */
43
+ replace(expectedStampId: string, next: PendingJoinFields): Promise<PendingJoinRow>;
44
+ /** `ControlDatabase.deletePendingJoin`, owner-signed. */
45
+ remove(id: string): Promise<boolean>;
46
+ /** Whether this machine has no control connection now, so a write it commits reaches no other machine. */
47
+ isAlone(): boolean;
48
+ /** The sApp the row's invitation names. */
49
+ sAppIdOf(row: PendingJoinRow): string;
50
+ /** Every pass's rows, read by an owner machine; `CadreNode` stages the membership invitations they carry. */
51
+ observeRows(rows: readonly PendingJoinRow[]): void;
52
+ emit(status: PendingJoinStatus): void;
53
+ now?: () => number;
54
+ random?: () => number;
55
+ scheduler?: TimeoutScheduler;
56
+ }
57
+ /**
58
+ * The pending row a `requestJoin` writes: tried until the invitation's own expiration or
59
+ * {@link MAX_PENDING_JOIN_MS} from now, whichever comes first.
60
+ */
61
+ export declare function requestedPendingJoin(id: string, encodedInvitation: string, disclosure: StrandFormationDisclosure, invitationExpiresAt: number, now: number): PendingJoinFields;
62
+ /** A row's stored disclosure, as the next attempt sends it. Owner-signed, so anything but an object is a bug. */
63
+ export declare function parseStoredDisclosure(row: PendingJoinRow): StrandFormationDisclosure;
64
+ /** A `joined` row's `MembershipInvite` column, or null when it is not the `{inviteKey, invitePrivateKey}` JSON the loop writes. */
65
+ export declare function parseStoredMembershipInvite(text: string): StrandMembershipInvite | null;
66
+ /**
67
+ * The membership invitations `joined` rows carry that this process has not staged yet, so a
68
+ * closed strand joined on one owner machine can be seated by whichever machine launches it
69
+ * first. Rows older than {@link MEMBERSHIP_INVITE_TTL_MS} are skipped: their invitation is dead.
70
+ * `alreadyStaged` holds invite keys; a malformed column is skipped and logged.
71
+ */
72
+ export declare function membershipInvitesToStage(rows: readonly PendingJoinRow[], alreadyStaged: ReadonlySet<string>, now: number): Array<{
73
+ rowId: string;
74
+ strandId: string;
75
+ invite: StrandMembershipInvite;
76
+ }>;
77
+ export declare class PendingJoinRunner {
78
+ private readonly deps;
79
+ private readonly tracked;
80
+ /** Rows whose latest write by this machine committed with no control connection: id → the stamp written. */
81
+ private readonly writtenAlone;
82
+ private readonly dueQueue;
83
+ private readonly scheduler;
84
+ private readonly now;
85
+ private readonly random;
86
+ /** First retry delay, and the window a row this machine did not ask for is first tried in. */
87
+ private readonly baseDelayMs;
88
+ /** How long a `token-spent` answer waits before its confirming attempt: long enough for a sibling's `joined` write to replicate. */
89
+ private readonly spentConfirmDelayMs;
90
+ private running;
91
+ private pollTimer;
92
+ private passInFlight;
93
+ private passAgain;
94
+ private backgroundAttempts;
95
+ constructor(deps: PendingJoinRunnerDeps);
96
+ /** Start passes: one at once, then every {@link PENDING_JOIN_POLL_MS}. */
97
+ start(): void;
98
+ /**
99
+ * Stop scheduling. Clears every timer and starts no new attempt.
100
+ *
101
+ * NOTE: an attempt already in flight is not awaited, because `formStrand` takes no abort
102
+ * signal. An approval that lands while the node stops can lose its local records; the row then
103
+ * stays pending, and the next start's attempt answers `token-spent`, which fails the row after
104
+ * its confirming attempt. Honest and bounded; if it shows up in practice, give `formStrand` a
105
+ * signal and abort it here.
106
+ */
107
+ stop(): void;
108
+ /** Run a pass now, for a change that may make one useful (this machine just became an owner). */
109
+ kick(): void;
110
+ /**
111
+ * Try `row` on this machine at once, outside the background slots, and report the status
112
+ * after the attempt. Joins an attempt already running for the row.
113
+ */
114
+ attemptNow(row: PendingJoinRow): Promise<PendingJoinStatus>;
115
+ /** This machine's view of `row`: the row's own state, with this machine's attempt state laid over a pending row. */
116
+ statusOf(row: PendingJoinRow): PendingJoinStatus;
117
+ /** Record a `PendingJoin` write this machine made outside the loop (a `requestJoin`), for {@link reissueWritesMadeAlone}. */
118
+ noteWritten(row: PendingJoinRow): void;
119
+ /** Stop tracking a row the user dismissed. An attempt in flight finishes; its outcome write then finds the row gone. */
120
+ forgetRow(id: string): void;
121
+ /**
122
+ * Re-write, with identical content under a fresh stamp, each row this machine last wrote while
123
+ * it had no control connection, so the other machines receive it. Called on the control
124
+ * connection growth edge. A row someone wrote since is left alone.
125
+ *
126
+ * NOTE: in memory only, so a row written alone by a process that stopped before it reconnected
127
+ * reaches the party only with that row's next write. A sweep of every row this machine wrote,
128
+ * on the first connection after start, would cover that, at the cost of one permanent
129
+ * `Revocation` tombstone per row per start. Revisit if other machines are seen missing such rows.
130
+ */
131
+ reissueWritesMadeAlone(): Promise<void>;
132
+ private schedulePass;
133
+ private clearPollTimer;
134
+ /** One pass at a time; a kick during a pass runs one more after it. */
135
+ private pass;
136
+ private runPass;
137
+ /** Drop every scheduled attempt; the first pass that finds this machine an owner again schedules afresh. */
138
+ private pauseAttempts;
139
+ /** Bring one read row into this machine's schedule. */
140
+ private consider;
141
+ /**
142
+ * The tracked entry for `row`, updated to it. A row asked for again (`RequestedAt` changed)
143
+ * starts this machine's counting over; a finished row stops its schedule.
144
+ */
145
+ private adopt;
146
+ private scheduleAttempt;
147
+ private cancelTimer;
148
+ private enqueue;
149
+ /** Start due attempts while background slots are free. */
150
+ private pump;
151
+ /** Run one attempt for `entry`, or join the one already running. Never rejects. */
152
+ private startAttempt;
153
+ private attemptOnce;
154
+ /** Read a failed attempt: retry, confirm a spent token, or fail the row. */
155
+ private onAttemptFailed;
156
+ /**
157
+ * A `token-spent` answer may mean another owner machine of this party won the same
158
+ * invitation. Adopt its outcome if the row already shows one; otherwise confirm once, after
159
+ * long enough for that machine's `joined` write to arrive, before failing the row.
160
+ */
161
+ private onSpent;
162
+ private retryLater;
163
+ /** `min(base × 2^(n−1), max)`, moved by up to ±{@link RETRY_JITTER}. */
164
+ private backoffMs;
165
+ /**
166
+ * Write `next` over the row this machine last read. When another write got there first,
167
+ * re-read and settle by {@link resolveLostWrite}. A row the user dismissed meanwhile is not
168
+ * recreated; a join this machine made is still remembered machine-locally, as every
169
+ * `formStrand` is.
170
+ */
171
+ private writeOutcome;
172
+ private settle;
173
+ /**
174
+ * Remove a finished row {@link MEMBERSHIP_INVITE_TTL_MS} after its outcome: the membership
175
+ * invitation it carries is dead by then, and an app that was not running has seen the strand
176
+ * through `strand:discovered`. Only while connected, like every write nothing waits on.
177
+ *
178
+ * NOTE: `deletePendingJoin` removes whichever incarnation is live, so a `requestJoin` of the
179
+ * same invitation landing on another machine in the same instant can be removed with it. The
180
+ * user asks again; revisit if that is ever seen.
181
+ */
182
+ private ageOut;
183
+ private forget;
184
+ private emitIfChanged;
185
+ private describe;
186
+ }