@serfab/cadre-core 1.8.0 → 1.10.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.
- package/dist/cadre-node.d.ts +301 -121
- package/dist/cadre-node.js +588 -244
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-authorization.d.ts +2 -2
- package/dist/control-authorization.js +1 -0
- package/dist/control-authorization.js.map +1 -1
- package/dist/control-cohort.d.ts +1 -1
- package/dist/control-cohort.js +1 -1
- package/dist/control-database.d.ts +105 -14
- package/dist/control-database.js +242 -73
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +6 -6
- package/dist/control-formation-recorder.js +7 -8
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +90 -3
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +21 -15
- package/dist/control-write-retry.js +21 -15
- package/dist/control-write-retry.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +16 -13
- package/dist/index.js.map +1 -1
- package/dist/invitation-bootstrap.d.ts +32 -0
- package/dist/invitation-bootstrap.js +30 -0
- package/dist/invitation-bootstrap.js.map +1 -0
- package/dist/link-budget.d.ts +204 -119
- package/dist/link-budget.js +208 -120
- package/dist/link-budget.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +3 -3
- package/dist/membership-connection-gater.js +3 -3
- package/dist/node-local-snapshot.d.ts +6 -4
- package/dist/node-local-snapshot.js +7 -3
- package/dist/node-local-snapshot.js.map +1 -1
- package/dist/peer-dial.d.ts +18 -14
- package/dist/peer-dial.js +18 -14
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +3 -12
- package/dist/peer-join-backfill.js +2 -3
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/pending-join-runner.d.ts +186 -0
- package/dist/pending-join-runner.js +649 -0
- package/dist/pending-join-runner.js.map +1 -0
- package/dist/push-fanout.d.ts +1 -1
- package/dist/push-fanout.js +1 -1
- package/dist/seed-bootstrap.d.ts +2 -2
- package/dist/seed-bootstrap.js +1 -1
- package/dist/strand-addr-protocol.js +2 -2
- package/dist/strand-formation-deadlines.d.ts +5 -5
- package/dist/strand-formation-deadlines.js +5 -5
- package/dist/strand-formation-manager.d.ts +18 -4
- package/dist/strand-formation-manager.js +48 -33
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +71 -25
- package/dist/strand-formation-protocol.js +225 -51
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-formation-rejection.d.ts +94 -0
- package/dist/strand-formation-rejection.js +77 -0
- package/dist/strand-formation-rejection.js.map +1 -0
- package/dist/strand-fret-addrs.d.ts +54 -0
- package/dist/strand-fret-addrs.js +108 -0
- package/dist/strand-fret-addrs.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +9 -38
- package/dist/strand-instance-manager.js +17 -74
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-network-state-file.d.ts +12 -0
- package/dist/strand-network-state-file.js +38 -0
- package/dist/strand-network-state-file.js.map +1 -0
- package/dist/strand-network-state.d.ts +111 -0
- package/dist/strand-network-state.js +191 -0
- package/dist/strand-network-state.js.map +1 -0
- package/dist/strand-solicitation.d.ts +11 -3
- package/dist/strand-solicitation.js +9 -0
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/types.d.ts +123 -40
- package/dist/types.js +5 -9
- package/dist/types.js.map +1 -1
- package/package.json +25 -24
- package/src/cadre-node.ts +637 -251
- package/src/control-authorization.ts +117 -116
- package/src/control-cohort.ts +1 -1
- package/src/control-database.ts +303 -82
- package/src/control-formation-recorder.ts +8 -9
- package/src/control-schema.ts +90 -3
- package/src/control-write-retry.ts +21 -15
- package/src/index.ts +36 -56
- package/src/invitation-bootstrap.ts +40 -0
- package/src/link-budget.ts +221 -120
- package/src/membership-connection-gater.ts +3 -3
- package/src/node-local-snapshot.ts +12 -7
- package/src/peer-dial.ts +18 -14
- package/src/peer-join-backfill.ts +5 -6
- package/src/pending-join-runner.ts +735 -0
- package/src/push-fanout.ts +1 -1
- package/src/seed-bootstrap.ts +2 -2
- package/src/strand-addr-protocol.ts +2 -2
- package/src/strand-formation-deadlines.ts +5 -5
- package/src/strand-formation-manager.ts +62 -37
- package/src/strand-formation-protocol.ts +1036 -803
- package/src/strand-formation-rejection.ts +129 -0
- package/src/strand-fret-addrs.ts +145 -0
- package/src/strand-instance-manager.ts +24 -97
- package/src/strand-network-state-file.ts +40 -0
- package/src/strand-network-state.ts +243 -0
- package/src/strand-solicitation.ts +17 -4
- package/src/types.ts +119 -40
- package/dist/strand-peer-book-file.d.ts +0 -12
- package/dist/strand-peer-book-file.js +0 -37
- package/dist/strand-peer-book-file.js.map +0 -1
- package/dist/strand-peer-book-protocol.d.ts +0 -168
- package/dist/strand-peer-book-protocol.js +0 -356
- package/dist/strand-peer-book-protocol.js.map +0 -1
- package/dist/strand-peer-book-swap.d.ts +0 -104
- package/dist/strand-peer-book-swap.js +0 -284
- package/dist/strand-peer-book-swap.js.map +0 -1
- package/dist/strand-peer-book.d.ts +0 -159
- package/dist/strand-peer-book.js +0 -361
- package/dist/strand-peer-book.js.map +0 -1
- package/dist/strand-peer-observer.d.ts +0 -88
- package/dist/strand-peer-observer.js +0 -180
- package/dist/strand-peer-observer.js.map +0 -1
- package/src/strand-peer-book-file.ts +0 -39
- package/src/strand-peer-book-protocol.ts +0 -466
- package/src/strand-peer-book-swap.ts +0 -338
- package/src/strand-peer-book.ts +0 -475
- package/src/strand-peer-observer.ts +0 -235
|
@@ -77,11 +77,12 @@ export const SCHEMA_INIT_ATTEMPTS = 5;
|
|
|
77
77
|
* This budget — not the attempt count — is what makes the policy safe to sit under every
|
|
78
78
|
* control write. A transient failure (stream reset while a connection is still forming)
|
|
79
79
|
* surfaces in well under a second, so it is retried and the loop adds at most ~2.2 s. A
|
|
80
|
-
* genuinely silent cohort member
|
|
81
|
-
* response-deadline attempts, 10.5 s each at the default declared link
|
|
82
|
-
*
|
|
83
|
-
* already exceeds this budget
|
|
84
|
-
*
|
|
80
|
+
* genuinely silent cohort member costs ~21 s per consensus round (two `ClusterClient`
|
|
81
|
+
* response-deadline attempts, 10.5 s each at the default declared link): one pend round plus
|
|
82
|
+
* the cancel discharge's three rounds, about 84 s for one write in
|
|
83
|
+
* `control-write-degraded-cohort-member.integration.ts`, which already exceeds this budget
|
|
84
|
+
* when attempt 1 returns — so that case is surfaced immediately and retry adds ZERO latency
|
|
85
|
+
* to the case where it cannot help.
|
|
85
86
|
*
|
|
86
87
|
* It cuts the loop off by design, so it does not grow with the link: its job is to end the
|
|
87
88
|
* retries of slow attempts, and the caller gets the last attempt's error unchanged. An attempt
|
|
@@ -92,16 +93,21 @@ export const SCHEMA_INIT_ATTEMPTS = 5;
|
|
|
92
93
|
* (10.5 s at the default declared link) still gets none. See `docs/cadre-consistency.md` →
|
|
93
94
|
* "Deadlines Over Optimystic's Reads and Commits".
|
|
94
95
|
*
|
|
95
|
-
* NOTE: a failed commit attempt
|
|
96
|
-
* (optimystic `TransactorSource.transact`'s catch
|
|
97
|
-
* `
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
96
|
+
* NOTE: a failed commit attempt also pays a cancel discharge before its error returns
|
|
97
|
+
* (optimystic `TransactorSource.transact`'s catch) — bounded by six rounds and
|
|
98
|
+
* `abortOrCancelTimeoutMs`, which every collection this repo opens sets to the larger of 5 s
|
|
99
|
+
* and the RPC dial deadline: 42.5 s at the default declared link (`optimysticDialLimits` in
|
|
100
|
+
* `link-budget.ts`;
|
|
101
|
+
* `../optimystic/packages/quereus-plugin-optimystic/src/optimystic-adapter/collection-factory.ts`).
|
|
102
|
+
* One cancel that runs its full budget therefore ends the retries on its own, cutting the
|
|
103
|
+
* three-attempt policy to however many attempts came before it. A cancel only runs that long
|
|
104
|
+
* when a peer stays silent, and that attempt has already spent its pend round past this
|
|
105
|
+
* budget, so the cut loses nothing there. After a transient fault the cancel is either
|
|
106
|
+
* answered or gives up after its six rounds against a dead transport, in about a second
|
|
107
|
+
* either way (optimystic `NetworkTransactor.MAX_CANCEL_ROUNDS`). Not observed — every
|
|
108
|
+
* measured round of the transient-reset case committed on attempt 3 of 3 — so this is a
|
|
109
|
+
* condition to watch, not work to do: if that case ever starts failing with
|
|
110
|
+
* `failed after 2/3 attempt(s)`, the cancel discharge is where the time went.
|
|
105
111
|
*/
|
|
106
112
|
// eslint-disable-next-line no-restricted-syntax -- cuts off by design: it ends the retries of slow attempts rather than waiting them out; see docs/cadre-consistency.md → "Deadlines Over Optimystic's Reads and Commits"
|
|
107
113
|
export const CONTROL_WRITE_RETRY_BUDGET_MS = 10_000;
|
package/src/index.ts
CHANGED
|
@@ -128,61 +128,21 @@ export {
|
|
|
128
128
|
type JoinedStrandRecord
|
|
129
129
|
} from './joined-strand-store.js';
|
|
130
130
|
|
|
131
|
-
// Node-local strand
|
|
132
|
-
//
|
|
133
|
-
// re-
|
|
134
|
-
// above — interface + in-memory + slot-backed stores
|
|
135
|
-
//
|
|
136
|
-
export {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
type StrandPeerEntry
|
|
147
|
-
} from './strand-peer-book.js';
|
|
148
|
-
export {
|
|
149
|
-
StrandPeerObserver,
|
|
150
|
-
dialableAddrs,
|
|
151
|
-
connectedIdentifiedPeers,
|
|
152
|
-
STRAND_PEER_OBSERVE_THROTTLE_MS,
|
|
153
|
-
type StrandPeerObservation,
|
|
154
|
-
type StrandPeerObserverDeps,
|
|
155
|
-
type StrandPeerObserverOptions,
|
|
156
|
-
type ConnectedIdentifiedPeer
|
|
157
|
-
} from './strand-peer-observer.js';
|
|
158
|
-
// The signed book SWAP between strand peers (`/sereus/strand-peers/1.0.0`): the wire
|
|
159
|
-
// protocol, signing and verification, and the per-strand driver that arms it.
|
|
160
|
-
export {
|
|
161
|
-
STRAND_PEER_BOOK_PROTOCOL,
|
|
162
|
-
SIGNED_STRAND_PEER_ENTRY_VERSION,
|
|
163
|
-
STRAND_PEER_ISSUED_AT_SKEW_MS,
|
|
164
|
-
MAX_BOOK_FRAME_SIZE,
|
|
165
|
-
StrandPeerBookService,
|
|
166
|
-
exchangeStrandPeerBook,
|
|
167
|
-
signStrandPeerEntry,
|
|
168
|
-
signedStrandPeerEntryPayload,
|
|
169
|
-
verifySignedStrandPeerEntry,
|
|
170
|
-
verifyStrandPeerBookFrame,
|
|
171
|
-
trimBookFrameToFit,
|
|
172
|
-
assertBookFrameFits,
|
|
173
|
-
type SignedStrandPeerEntry,
|
|
174
|
-
type StrandPeerBookFrame,
|
|
175
|
-
type StrandPeerEntryVerdict,
|
|
176
|
-
type StrandPeerBookServiceDeps,
|
|
177
|
-
type ExchangeStrandPeerBookOptions
|
|
178
|
-
} from './strand-peer-book-protocol.js';
|
|
179
|
-
export {
|
|
180
|
-
StrandPeerBookSwap,
|
|
181
|
-
STRAND_PEER_BOOK_SWAP_THROTTLE_MS,
|
|
182
|
-
OWN_ENTRY_RESIGN_DEBOUNCE_MS,
|
|
183
|
-
type StrandPeerBookSwapDeps,
|
|
184
|
-
type StrandPeerBookSwapOptions
|
|
185
|
-
} from './strand-peer-book-swap.js';
|
|
131
|
+
// Node-local strand network state: per strand, the state Optimystic's db-p2p saves for
|
|
132
|
+
// the strand node (its FRET routing table with each peer's signed address record), so a
|
|
133
|
+
// restarted strand node re-imports the peers it was talking to. Same cross-platform
|
|
134
|
+
// split as the bootstrap-peer store above — interface + in-memory + slot-backed stores
|
|
135
|
+
// here, Node-only file backend behind '@serfab/cadre-core/strand-network-state-file'.
|
|
136
|
+
export {
|
|
137
|
+
MemoryStrandNetworkStateStore,
|
|
138
|
+
PersistentStrandNetworkStateStore,
|
|
139
|
+
strandNetworkStatePersistence,
|
|
140
|
+
type StrandNetworkStateStore
|
|
141
|
+
} from './strand-network-state.js';
|
|
142
|
+
// The signed address records a running strand node's FRET table holds, as per-peer dial
|
|
143
|
+
// addresses: what the periodic refresh re-merges into the node's address book, and a
|
|
144
|
+
// diagnostic for "whom could this strand node redial right now?".
|
|
145
|
+
export { strandFretPeerAddrs, type FretAddrHost, type FretPeerAddrs } from './strand-fret-addrs.js';
|
|
186
146
|
|
|
187
147
|
// Storage scope keys — what `CadreNodeConfig.storage.provider` is called with. A
|
|
188
148
|
// strand's key is its strand id; the control database's key carries the party id,
|
|
@@ -524,6 +484,8 @@ export {
|
|
|
524
484
|
// one declared assumption about the link moves them all — see `NetworkConfig.linkRoundTripMs`.
|
|
525
485
|
export {
|
|
526
486
|
DECLARED_LINK_ROUND_TRIP_MS,
|
|
487
|
+
CIRCUIT_DIAL_ROUND_TRIPS,
|
|
488
|
+
RELAY_DIAL_ROUND_TRIPS,
|
|
527
489
|
RELAYED_DIAL_ROUND_TRIPS,
|
|
528
490
|
RELAY_RESERVATION_ROUND_TRIPS,
|
|
529
491
|
CIRCUIT_REQUEST_ROUND_TRIPS,
|
|
@@ -536,7 +498,10 @@ export {
|
|
|
536
498
|
circuitRequestBudgetMs,
|
|
537
499
|
relayedRequestBudgetMs,
|
|
538
500
|
peerJoinPushBudget,
|
|
539
|
-
type PeerJoinPushBudget
|
|
501
|
+
type PeerJoinPushBudget,
|
|
502
|
+
DIAL_ADMISSION_DECISIONS,
|
|
503
|
+
optimysticDialLimits,
|
|
504
|
+
type OptimysticDialLimits
|
|
540
505
|
} from './link-budget.js';
|
|
541
506
|
|
|
542
507
|
// Seed trust policy (trust anchor for incoming seeds)
|
|
@@ -561,6 +526,7 @@ export {
|
|
|
561
526
|
export {
|
|
562
527
|
FormationListener,
|
|
563
528
|
dialFormation,
|
|
529
|
+
dialFormationByMachine,
|
|
564
530
|
isValidResponderCreatesResult,
|
|
565
531
|
isWellFormedMembershipInvite,
|
|
566
532
|
sanitizeStrandAddrs,
|
|
@@ -574,9 +540,22 @@ export {
|
|
|
574
540
|
type FormationListenerOptions,
|
|
575
541
|
type FormationDialOptions,
|
|
576
542
|
type FormationDialResult,
|
|
543
|
+
type FormationRejection,
|
|
544
|
+
type FormationTokenCheck,
|
|
577
545
|
type ResponderProvisionOutcome
|
|
578
546
|
} from './strand-formation-protocol.js';
|
|
547
|
+
// How a formation dial fails: a typed refusal (with a fixed code) or no answer at all
|
|
548
|
+
export {
|
|
549
|
+
FormationRejectedError,
|
|
550
|
+
FormationUnreachableError,
|
|
551
|
+
FormationPostApprovalError,
|
|
552
|
+
FORMATION_REJECTION_RETRYABLE,
|
|
553
|
+
isFormationRejectionCode,
|
|
554
|
+
type FormationRejectionCode
|
|
555
|
+
} from './strand-formation-rejection.js';
|
|
579
556
|
export { formationDeadlines, type FormationDeadlines } from './strand-formation-deadlines.js';
|
|
557
|
+
// The pending-join retry loop behind CadreNode.requestJoin (PendingJoinStatus is in types.ts)
|
|
558
|
+
export { PENDING_JOIN_POLL_MS, PENDING_JOIN_MAX_BACKOFF_MS, MAX_PENDING_JOIN_MS } from './pending-join-runner.js';
|
|
580
559
|
|
|
581
560
|
// Strand Formation manager (drives the native transport)
|
|
582
561
|
export {
|
|
@@ -585,6 +564,7 @@ export {
|
|
|
585
564
|
MEMBERSHIP_INVITE_TTL_MS,
|
|
586
565
|
MEMBERSHIP_INVITE_UNAVAILABLE_REASON,
|
|
587
566
|
HOST_STRAND_MUST_BE_RECREATED_REASON,
|
|
567
|
+
type CadrePeerAddrsSource,
|
|
588
568
|
type MembershipInviteIssuer,
|
|
589
569
|
type StrandFormationManagerConfig,
|
|
590
570
|
type StrandFormationManagerOptions
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which of the inviting party's other machines an open invitation names, so a joiner can still
|
|
3
|
+
* form while the machine that minted it is offline. The minting machine's own addresses go
|
|
4
|
+
* first and are not chosen here (`CadreNode.createOpenInvitation`).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* At most this many of the party's other machines are named, each with at most
|
|
9
|
+
* {@link INVITATION_ADDRS_PER_SIBLING} addresses: 12 extra addresses of roughly 100–200
|
|
10
|
+
* characters, base64url-encoded into an invitation shared as text.
|
|
11
|
+
*
|
|
12
|
+
* NOTE: if invitations are ever carried in a QR code, lower these caps or name the machines by
|
|
13
|
+
* peer id only.
|
|
14
|
+
* NOTE: the per-machine cap keeps the record's order (relay first, then direct addresses as the
|
|
15
|
+
* machine published them, loopback included). If a sibling with many interfaces is seen to have
|
|
16
|
+
* its reachable address cut, rank loopback and private addresses last before slicing.
|
|
17
|
+
*/
|
|
18
|
+
export const INVITATION_SIBLING_MACHINES = 3;
|
|
19
|
+
export const INVITATION_ADDRS_PER_SIBLING = 4;
|
|
20
|
+
|
|
21
|
+
/** One other machine of the party whose signed address record resolved. */
|
|
22
|
+
export interface InvitationSibling {
|
|
23
|
+
peerId: string;
|
|
24
|
+
/** The record's `UpdatedAt`: when the machine last published its addresses. */
|
|
25
|
+
updatedAt: number;
|
|
26
|
+
/** Relay (signaling) addresses first, each ending in `/p2p/<peerId>`. */
|
|
27
|
+
addrs: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The addresses of the siblings an invitation names. Machines this node is connected to right
|
|
32
|
+
* now come first, since a live connection is the best evidence that a machine is up; a record
|
|
33
|
+
* shows only that it was up within the freshness window. Within each half, newest record first.
|
|
34
|
+
*/
|
|
35
|
+
export function selectInvitationSiblingAddrs(siblings: InvitationSibling[], connected: ReadonlySet<string>): string[] {
|
|
36
|
+
return [...siblings]
|
|
37
|
+
.sort((a, b) => Number(connected.has(b.peerId)) - Number(connected.has(a.peerId)) || b.updatedAt - a.updatedAt)
|
|
38
|
+
.slice(0, INVITATION_SIBLING_MACHINES)
|
|
39
|
+
.flatMap((sibling) => sibling.addrs.slice(0, INVITATION_ADDRS_PER_SIBLING));
|
|
40
|
+
}
|