@serfab/cadre-core 1.5.0 → 1.7.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 +206 -67
- package/dist/cadre-node.js +399 -98
- package/dist/cadre-node.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +112 -0
- package/dist/joined-strand-store.js +263 -0
- package/dist/joined-strand-store.js.map +1 -0
- package/dist/key-store.d.ts +6 -0
- package/dist/key-store.js.map +1 -1
- package/dist/link-budget.d.ts +95 -53
- package/dist/link-budget.js +97 -53
- package/dist/link-budget.js.map +1 -1
- package/dist/node-local-snapshot.d.ts +5 -4
- package/dist/node-local-snapshot.js +6 -3
- package/dist/node-local-snapshot.js.map +1 -1
- package/dist/peer-dial.d.ts +3 -3
- package/dist/peer-dial.js +3 -3
- package/dist/peer-join-backfill.d.ts +35 -16
- package/dist/peer-join-backfill.js +117 -57
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/relay-reservation.d.ts +2 -2
- package/dist/relay-reservation.js +2 -2
- package/dist/seed-bootstrap.js +1 -1
- package/dist/strand-first-sync-gate.d.ts +88 -43
- package/dist/strand-first-sync-gate.js +92 -46
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +39 -0
- package/dist/strand-instance-manager.js +80 -3
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-peer-book-file.d.ts +12 -0
- package/dist/strand-peer-book-file.js +37 -0
- package/dist/strand-peer-book-file.js.map +1 -0
- package/dist/strand-peer-book-protocol.d.ts +159 -0
- package/dist/strand-peer-book-protocol.js +360 -0
- package/dist/strand-peer-book-protocol.js.map +1 -0
- package/dist/strand-peer-book-swap.d.ts +104 -0
- package/dist/strand-peer-book-swap.js +284 -0
- package/dist/strand-peer-book-swap.js.map +1 -0
- package/dist/strand-peer-book.d.ts +159 -0
- package/dist/strand-peer-book.js +354 -0
- package/dist/strand-peer-book.js.map +1 -0
- package/dist/strand-peer-observer.d.ts +88 -0
- package/dist/strand-peer-observer.js +180 -0
- package/dist/strand-peer-observer.js.map +1 -0
- package/dist/types.d.ts +84 -17
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +11 -7
- package/src/cadre-node.ts +7776 -7445
- package/src/index.ts +68 -0
- package/src/joined-strand-store.ts +308 -0
- package/src/key-store.ts +6 -0
- package/src/link-budget.ts +100 -53
- package/src/node-local-snapshot.ts +293 -289
- package/src/peer-dial.ts +3 -3
- package/src/peer-join-backfill.ts +709 -647
- package/src/relay-reservation.ts +2 -2
- package/src/seed-bootstrap.ts +1 -1
- package/src/strand-first-sync-gate.ts +352 -306
- package/src/strand-instance-manager.ts +106 -3
- package/src/strand-peer-book-file.ts +39 -0
- package/src/strand-peer-book-protocol.ts +463 -0
- package/src/strand-peer-book-swap.ts +338 -0
- package/src/strand-peer-book.ts +468 -0
- package/src/strand-peer-observer.ts +235 -0
- package/src/types.ts +86 -17
package/dist/cadre-node.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { CadreNodeConfig, StrandInstance, StrandRow, StrandConfig, FoundStr
|
|
|
4
4
|
import { type Ed25519KeyPair } from './ed25519-key.js';
|
|
5
5
|
import { type TrustedOwnerStore, type TrustSource } from './trusted-owner-store.js';
|
|
6
6
|
import { type BootstrapPeerStore } from './bootstrap-peer-store.js';
|
|
7
|
+
import { type StrandPeerBookStore } from './strand-peer-book.js';
|
|
7
8
|
import { type EnrolledMachineStore } from './enrolled-machine-store.js';
|
|
8
9
|
import { type SAppIdLookup } from './strand-watcher.js';
|
|
9
10
|
import { type ControlCohortReconcileResult } from './control-cohort.js';
|
|
@@ -257,37 +258,36 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
257
258
|
*/
|
|
258
259
|
private readonly strandPeerAddrRefreshAt;
|
|
259
260
|
/**
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
261
|
+
* Node-local strand peer book (see `strand-peer-book.ts`): per strand, the strand
|
|
262
|
+
* peers this node has met and their last-known strand-network addresses. Three
|
|
263
|
+
* writers: {@link recordFormationStrandPeers} files the responder's live strand
|
|
264
|
+
* addrs a formation result carried back (`FormationResultMessage.strandAddrs`),
|
|
265
|
+
* {@link observeStrandPeer} files every strand peer a running strand node
|
|
266
|
+
* identifies, and the per-strand book swap (`strand-peer-book-swap.ts`, handed the
|
|
267
|
+
* store as `StartStrandConfig.strandPeerBook`) files the node's own signed entry
|
|
268
|
+
* plus every signed entry a strand peer sends it — the only writer whose entries
|
|
269
|
+
* carry a signature, and the only one that can refresh a peer's addresses without
|
|
270
|
+
* meeting that peer. Read by {@link resolveCohortSeed} (launch + hibernation resume) and
|
|
271
|
+
* re-merged by every {@link refreshStrandPeerAddrs} pass, which is what keeps the
|
|
272
|
+
* entries alive past the peerStore's one-hour address expiry.
|
|
263
273
|
*
|
|
264
274
|
* This is the ONLY cross-party discovery input there is. The strand-addr RPC that
|
|
265
275
|
* resolves a strand's addresses is membership-gated and answers own-party siblings
|
|
266
|
-
* only, so without
|
|
267
|
-
* the mesh never forms
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
* NOTE: entries are kept for the node's lifetime, including across a
|
|
282
|
-
* {@link stopStrand} — a stopped strand may be claimed again with {@link addStrand}
|
|
283
|
-
* (the watcher itself will not re-offer it: the stop suppresses the id for the rest of
|
|
284
|
-
* the session) and must still get its seed. Each strand's list is capped at
|
|
285
|
-
* `MAX_STRAND_ADDRS`, but the
|
|
286
|
-
* number of KEYS is bounded only by the strands this node has ever formed as an
|
|
287
|
-
* initiator (not by time); if a node ever forms strands at scale, evict on
|
|
288
|
-
* `unpublishStrand` or cap the map.
|
|
289
|
-
*/
|
|
290
|
-
private readonly crossPartyStrandAddrs;
|
|
276
|
+
* only, so without the book a joiner's cohort seed for a two-party strand is empty
|
|
277
|
+
* and the mesh never forms — and, with an in-memory book, never RE-forms after a
|
|
278
|
+
* restart (gotchoices/sereus#18). A STORE rather than a map so an embedder can make
|
|
279
|
+
* it outlive the process; constructed (or adopted from `config.strandPeers.store`)
|
|
280
|
+
* by {@link initializeStrandPeerBookStore} during {@link start}, deliberately NOT
|
|
281
|
+
* cleared by {@link cleanup}, so it survives a stop()→start() cycle of the same node
|
|
282
|
+
* instance — same lifecycle as {@link bootstrapPeerStore}.
|
|
283
|
+
*
|
|
284
|
+
* Entries survive a {@link stopStrand} (a stopped strand may be claimed again with
|
|
285
|
+
* {@link addStrand}, and is rediscovered on restart) and are forgotten by
|
|
286
|
+
* {@link unpublishStrand}, {@link forgetJoinedStrand} and self-revocation; the store
|
|
287
|
+
* ages the rest out after 14 days and caps each strand at 16 peers, so the book is
|
|
288
|
+
* bounded by time and by the strands this node runs rather than by its history.
|
|
289
|
+
*/
|
|
290
|
+
private strandPeerBookStore;
|
|
291
291
|
/**
|
|
292
292
|
* PENDING strand membership invitations learned at formation, keyed by strandId — the
|
|
293
293
|
* single-use `Strand.Invite` credential a closed-strand formation result carried back
|
|
@@ -295,10 +295,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
295
295
|
* to redeem (`consumeInvite` seats the `Strand.Member` row under this party's own key
|
|
296
296
|
* — the `strand-node-binds-member-peer` half of the party-identity chain).
|
|
297
297
|
*
|
|
298
|
-
* IN-MEMORY, deliberately
|
|
299
|
-
* re-forms from scratch
|
|
300
|
-
*
|
|
301
|
-
* a fresh invitation. A re-formation against the same strand REPLACES the entry — the
|
|
298
|
+
* IN-MEMORY, deliberately: an invitation is single-use and short-lived, a restarted
|
|
299
|
+
* joiner that never redeemed it re-forms from scratch, and re-forming issues a fresh
|
|
300
|
+
* one. A re-formation against the same strand REPLACES the entry — the
|
|
302
301
|
* fresh invitation supersedes one that may have expired. The party key the invitation
|
|
303
302
|
* admits, by contrast, IS persisted (`StrandPartyKey`, seated by
|
|
304
303
|
* {@link adoptFormationMembershipInvite} before the entry lands here), so a lost
|
|
@@ -314,8 +313,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
314
313
|
* just waits; once launched, staging notifies the manager, which re-arms a finished loop.
|
|
315
314
|
*
|
|
316
315
|
* NOTE: entries live for the node's lifetime (one small pair per formed closed
|
|
317
|
-
* strand)
|
|
318
|
-
* if a node ever forms strands at scale, evict
|
|
316
|
+
* strand); the number of keys is bounded only by the strands this node has ever
|
|
317
|
+
* formed, not by time — if a node ever forms strands at scale, evict on
|
|
318
|
+
* `unpublishStrand` / `forgetJoinedStrand` as the strand peer book does.
|
|
319
319
|
*/
|
|
320
320
|
private readonly pendingMembershipInvites;
|
|
321
321
|
/**
|
|
@@ -386,6 +386,23 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
386
386
|
* so it survives a stop()→start() cycle of the same node instance.
|
|
387
387
|
*/
|
|
388
388
|
private enrolledMachineStore;
|
|
389
|
+
/**
|
|
390
|
+
* Node-local record of the strands this node joined from ANOTHER party (see
|
|
391
|
+
* `joined-strand-store.ts`) — the only thing that names them after a restart, since
|
|
392
|
+
* this party's control database holds no row for them. Written by {@link formStrand}
|
|
393
|
+
* and by an {@link addStrand} of a foreign row; forgotten by {@link forgetJoinedStrand}
|
|
394
|
+
* and on self-revocation. Adopted from `config.joinedStrands.store`, else built over
|
|
395
|
+
* `config.keyStore`, else in-memory, by {@link initializeJoinedStrandStore}. Like
|
|
396
|
+
* {@link bootstrapPeerStore} it is deliberately NOT cleared by {@link cleanup}.
|
|
397
|
+
*/
|
|
398
|
+
private joinedStrandStore;
|
|
399
|
+
/**
|
|
400
|
+
* The strand watcher's view of {@link joinedStrandStore}: its records unioned with the
|
|
401
|
+
* control rows each poll. Per SESSION, unlike the store — rebuilt at every
|
|
402
|
+
* {@link start}, which is what ends a revoked join's "keep offering until this session
|
|
403
|
+
* ends" (see `JoinedStrandRows.forgetAfterThisSession`).
|
|
404
|
+
*/
|
|
405
|
+
private joinedStrandRows;
|
|
389
406
|
/**
|
|
390
407
|
* The enrolled-machine count this node's CONTROL libp2p node was (or will be)
|
|
391
408
|
* built with — read out of {@link enrolledMachineStore} during {@link start},
|
|
@@ -693,6 +710,25 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
693
710
|
* number nobody chose, and the mismatch always means a miswired embedder.
|
|
694
711
|
*/
|
|
695
712
|
private initializeEnrolledMachineStore;
|
|
713
|
+
/**
|
|
714
|
+
* Construct (or adopt) the node-local joined-strand store (see
|
|
715
|
+
* {@link joinedStrandStore}) and this session's watcher view over it.
|
|
716
|
+
*
|
|
717
|
+
* The store instance is kept across stop()→start(); the view is rebuilt. A store
|
|
718
|
+
* scoped to a different party is a configuration error, fail closed: its joins
|
|
719
|
+
* would be offered to this party's app as if this party had made them.
|
|
720
|
+
*/
|
|
721
|
+
private initializeJoinedStrandStore;
|
|
722
|
+
/**
|
|
723
|
+
* Construct (or adopt) the node-local strand peer book (see
|
|
724
|
+
* {@link strandPeerBookStore}). Synchronous for the reason
|
|
725
|
+
* {@link initializeBootstrapPeerStore} is: an injected store has already loaded its
|
|
726
|
+
* persisted entries by the time it is handed in, and the in-memory fallback has
|
|
727
|
+
* nothing to load. The instance is kept across stop()→start(). A store scoped to a
|
|
728
|
+
* different party is a configuration error, fail closed: another party's strand
|
|
729
|
+
* peers must never enter this node's dial loop.
|
|
730
|
+
*/
|
|
731
|
+
private initializeStrandPeerBookStore;
|
|
696
732
|
/**
|
|
697
733
|
* The node-local enrolled-machine store (null before {@link start}) — what this
|
|
698
734
|
* node last knew about its party's size. Exposed for diagnostics and for a host
|
|
@@ -706,6 +742,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
706
742
|
* node dial if it is stranded?".
|
|
707
743
|
*/
|
|
708
744
|
getBootstrapPeerStore(): BootstrapPeerStore | null;
|
|
745
|
+
/**
|
|
746
|
+
* The node-local strand peer book (null before {@link start}) — per strand, the
|
|
747
|
+
* strand peers this node dials first on launch, resume and refresh. Exposed for
|
|
748
|
+
* diagnostics and for a host that wants to show "whom would this strand re-find
|
|
749
|
+
* after a restart?".
|
|
750
|
+
*/
|
|
751
|
+
getStrandPeerBookStore(): StrandPeerBookStore | null;
|
|
709
752
|
/**
|
|
710
753
|
* The node-local trusted-owner anchor (null before {@link start}). This is
|
|
711
754
|
* the set the authorized-membership predicate and seed-trust anchor consult —
|
|
@@ -765,10 +808,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
765
808
|
* needs no work of its own: `createLibp2pNode` registers the block-transfer
|
|
766
809
|
* handler on every node it builds, control node included, and this node's
|
|
767
810
|
* per-stream gate (`authorizeInboundControlStream`) covers the inbound
|
|
768
|
-
* direction. A denied peer is retried on its next `
|
|
769
|
-
* because the production join order is
|
|
770
|
-
* committed membership change via
|
|
771
|
-
* `scheduleConnectedPeers()` call.
|
|
811
|
+
* direction. A denied peer is retried on its next `peer:identify` (a
|
|
812
|
+
* reconnect re-runs identify), and — because the production join order is
|
|
813
|
+
* connect-then-authorize — on every committed membership change via
|
|
814
|
+
* {@link refreshAuthorizedControlPeers}'s `scheduleConnectedPeers()` call.
|
|
772
815
|
*
|
|
773
816
|
* No-ops (logged) when the embedder configured no control storage or the
|
|
774
817
|
* node exposes no key network — the backfill would have nothing to read or
|
|
@@ -1045,6 +1088,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1045
1088
|
* address without a `/p2p/<id>` component contributes nothing.
|
|
1046
1089
|
*/
|
|
1047
1090
|
private getBootstrapPeerIds;
|
|
1091
|
+
/**
|
|
1092
|
+
* What the strand watcher polls: this party's control rows plus a row per remembered
|
|
1093
|
+
* cross-party join (see {@link joinedStrandRows}), so a joined strand is re-offered
|
|
1094
|
+
* and relaunched on the same path as the party's own.
|
|
1095
|
+
*/
|
|
1048
1096
|
private createStrandQueryable;
|
|
1049
1097
|
/**
|
|
1050
1098
|
* Schedule the node's initial self-record publish + ongoing refresh shortly
|
|
@@ -1875,6 +1923,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1875
1923
|
* published (e.g. re-attaching its own orphan after a restart) founds it, and attaching
|
|
1876
1924
|
* anyone else's row joins, without the caller needing to know which it is.
|
|
1877
1925
|
*
|
|
1926
|
+
* A joined row (no `founder: true`) this party's control database does not hold — a
|
|
1927
|
+
* strand joined from another party — is remembered in the node's joined-strand store, so it is re-offered as
|
|
1928
|
+
* `strand:discovered` after a restart (see {@link forgetJoinedStrand}).
|
|
1929
|
+
*
|
|
1878
1930
|
* A rejected call leaves nothing running but DOES leave the sApp config
|
|
1879
1931
|
* registered, deliberately: both an explicit retry and the {@link StrandWatcher}'s
|
|
1880
1932
|
* automatic relaunch need it. A failed launch here hands the strand back to that
|
|
@@ -2273,6 +2325,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2273
2325
|
* for a relay we are not yet connected to.
|
|
2274
2326
|
*/
|
|
2275
2327
|
private resolveCohortSeed;
|
|
2328
|
+
/**
|
|
2329
|
+
* The strand peer book's contribution to a strand's seed: every live entry's
|
|
2330
|
+
* addresses, freshest peer first, minus this node's own entry when `selfPeerId` is
|
|
2331
|
+
* known (the book swap files one under the strand transport id; a node must never
|
|
2332
|
+
* dial itself). Empty before {@link start} builds the store.
|
|
2333
|
+
*/
|
|
2334
|
+
private strandPeerBookAddrs;
|
|
2276
2335
|
/**
|
|
2277
2336
|
* The own-party half of {@link resolveCohortSeed}: strand-network addresses resolved
|
|
2278
2337
|
* from CONNECTED cohort siblings over the control-mesh strand-addr RPC, doubling as
|
|
@@ -2390,7 +2449,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2390
2449
|
* NOTE: against a relay that is DOWN this hook costs up to two strand-addr
|
|
2391
2450
|
* timeouts (10 s each: dial by peer id, then by addr) before the reservation drive even
|
|
2392
2451
|
* starts, so one failed re-drive holds the supervisor `driving` for those 20 s plus the
|
|
2393
|
-
* drive's own deadline —
|
|
2452
|
+
* drive's own deadline — 34 s at the default declared link round trip, and longer on a host
|
|
2394
2453
|
* that declared a slower one (`link-budget.ts`).
|
|
2395
2454
|
* Bounded and harmless while the relay is unreachable anyway; if recovery
|
|
2396
2455
|
* latency after a relay comes back ever matters, skip the announce when the
|
|
@@ -2427,17 +2486,17 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2427
2486
|
private refreshStrandPeerAddrs;
|
|
2428
2487
|
/**
|
|
2429
2488
|
* One strand's share of {@link refreshStrandPeerAddrs}: RPC the siblings, union their
|
|
2430
|
-
* answers with this strand's
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2489
|
+
* answers with this strand's peer-book addresses, and merge the lot into the strand's
|
|
2490
|
+
* address book. Errors are logged and swallowed so one strand's failure never costs
|
|
2491
|
+
* the others their refresh.
|
|
2433
2492
|
*
|
|
2434
2493
|
* `targets` may be EMPTY — a solo node, or one whose only control peers are strangers.
|
|
2435
|
-
* The
|
|
2436
|
-
*
|
|
2437
|
-
*
|
|
2438
|
-
*
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2494
|
+
* The peer-book addresses still have to be re-merged in that case: nothing re-resolves
|
|
2495
|
+
* another party's addresses, so this periodic re-merge is the ONLY thing standing
|
|
2496
|
+
* between them and the peerStore's one-hour expiry. A strand with neither a sibling to
|
|
2497
|
+
* ask nor a book entry does nothing and leaves its throttle unstamped, so the next
|
|
2498
|
+
* reconcile tick retries rather than sitting out the whole refresh interval having
|
|
2499
|
+
* done nothing.
|
|
2441
2500
|
*/
|
|
2442
2501
|
private refreshOneStrandPeerAddrs;
|
|
2443
2502
|
/**
|
|
@@ -2459,14 +2518,14 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2459
2518
|
* peerStore's one-hour expiry. No new gating here — cross-party strand trust is
|
|
2460
2519
|
* `backlog/strand-network-nat-relay-reachability`.
|
|
2461
2520
|
*
|
|
2462
|
-
* NOTE: one input
|
|
2463
|
-
*
|
|
2464
|
-
* {@link refreshStrandPeerAddrs} re-merges the
|
|
2465
|
-
*
|
|
2466
|
-
*
|
|
2467
|
-
*
|
|
2468
|
-
*
|
|
2469
|
-
*
|
|
2521
|
+
* NOTE: one input ages out on a slower clock — the strand peer book's entries
|
|
2522
|
+
* ({@link strandPeerBookStore}). Nothing can re-resolve another party's addresses,
|
|
2523
|
+
* so {@link refreshStrandPeerAddrs} re-merges the book every pass, which means a
|
|
2524
|
+
* junk entry from a responder or a peer's identify survives until the book drops it
|
|
2525
|
+
* (14 days unrefreshed, or the peer's next connection replacing the entry) rather
|
|
2526
|
+
* than an hour. Bounded to 16 peers × 16 addrs per strand, forgotten on
|
|
2527
|
+
* `unpublishStrand` / `forgetJoinedStrand`, and still authority-free — so the
|
|
2528
|
+
* exposure is a handful of failed dials, not a trust hole.
|
|
2470
2529
|
*/
|
|
2471
2530
|
private mergeStrandPeerAddrs;
|
|
2472
2531
|
/**
|
|
@@ -2479,6 +2538,69 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2479
2538
|
* live node, so it answers and a later sibling can dial in.
|
|
2480
2539
|
*/
|
|
2481
2540
|
private getStrandMultiaddrs;
|
|
2541
|
+
/**
|
|
2542
|
+
* Leave a strand joined from another party: forget its remembered join, so no later
|
|
2543
|
+
* start re-offers it, then {@link stopStrand} it here. The "leave" a joiner has, since it
|
|
2544
|
+
* cannot {@link unpublishStrand} a row its party's control database never held. For one
|
|
2545
|
+
* of this party's own strands the forget is a no-op and this is just {@link stopStrand}.
|
|
2546
|
+
*
|
|
2547
|
+
* Touches nothing beyond this node — the other members are not told, and this party's
|
|
2548
|
+
* membership row in the strand stays.
|
|
2549
|
+
*/
|
|
2550
|
+
forgetJoinedStrand(strandId: string): Promise<void>;
|
|
2551
|
+
/**
|
|
2552
|
+
* Record `row` as a join from another party when this party's control database holds no
|
|
2553
|
+
* row for it — the one case nothing else would re-offer after a restart. Skips the write
|
|
2554
|
+
* when an identical record is already there (an app re-claiming a remembered join on
|
|
2555
|
+
* every start), and keeps the first `joinedAt`.
|
|
2556
|
+
*
|
|
2557
|
+
* Best-effort, for {@link addStrand}: a failure costs the strand its re-offer after the
|
|
2558
|
+
* next restart, not this attach, so it is reported and the attach goes on.
|
|
2559
|
+
* {@link formStrand}, whose join nothing else would name, fails loudly instead.
|
|
2560
|
+
*
|
|
2561
|
+
* NOTE: "no control row" also describes a row the party has just unpublished. A claim
|
|
2562
|
+
* of such a row the app kept from an earlier offer, made after the watcher already
|
|
2563
|
+
* withdrew it, is remembered as a join and survives the removal on this machine until
|
|
2564
|
+
* {@link forgetJoinedStrand}. Contrived today (a claim of a row the node itself is still
|
|
2565
|
+
* offering skips this method); if it shows up, check the strand's `Revocation`
|
|
2566
|
+
* tombstone here before recording.
|
|
2567
|
+
*/
|
|
2568
|
+
private rememberForeignStrand;
|
|
2569
|
+
/**
|
|
2570
|
+
* Self-revocation arm of the joined-strand record: a party removed from a strand must
|
|
2571
|
+
* not re-attach it on every launch. The strand keeps running this session — the
|
|
2572
|
+
* `strand:revoked` contract is that nothing is torn down for the app — and is gone
|
|
2573
|
+
* after the next start. The join record is a no-op for this party's own strands, which
|
|
2574
|
+
* have none; the strand peer book is forgotten either way, since a removed party must
|
|
2575
|
+
* not keep dialing the strand's peers.
|
|
2576
|
+
*
|
|
2577
|
+
* NOTE: a manager can re-admit a removed party directly (`addMemberByManager`), and the
|
|
2578
|
+
* membership loop then finishes the join on its own — but the record is gone by then, so
|
|
2579
|
+
* the next start does not re-attach the strand. Re-forming records it again. If direct
|
|
2580
|
+
* re-admission becomes a routine flow, re-record the join when the revoked-peer gate
|
|
2581
|
+
* clears for this node.
|
|
2582
|
+
*/
|
|
2583
|
+
private forgetRevokedJoin;
|
|
2584
|
+
/**
|
|
2585
|
+
* Forget a strand's entries in the peer book (see {@link strandPeerBookStore}):
|
|
2586
|
+
* fire-and-log, like every book write — the removal is visible synchronously by the
|
|
2587
|
+
* store's contract, and a failed persist costs restart survival only.
|
|
2588
|
+
*/
|
|
2589
|
+
private forgetStrandPeers;
|
|
2590
|
+
/**
|
|
2591
|
+
* The strand peer book's observation writer (`StartStrandConfig.onStrandPeerIdentified`):
|
|
2592
|
+
* a strand node identified a strand peer at `observation.addrs`, so remember it as an
|
|
2593
|
+
* unsigned entry seen just now. The observer never reports self, and the store binds
|
|
2594
|
+
* every address to the peer id before filing it.
|
|
2595
|
+
*/
|
|
2596
|
+
private observeStrandPeer;
|
|
2597
|
+
/**
|
|
2598
|
+
* Merge one entry into the peer book. Fire-and-log: the entry is visible
|
|
2599
|
+
* synchronously by the store's contract, and the promise tracks durability only. A
|
|
2600
|
+
* persist failure costs restart survival, never this session's seed — the same trade
|
|
2601
|
+
* {@link retainDialTarget} makes.
|
|
2602
|
+
*/
|
|
2603
|
+
private rememberStrandPeer;
|
|
2482
2604
|
/**
|
|
2483
2605
|
* Stop a strand on THIS node only: untrack it from hibernation, drop its sApp config,
|
|
2484
2606
|
* stop the local instance, and emit `strand:stopped`. The shared `Strand` row is left
|
|
@@ -2487,7 +2609,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2487
2609
|
* id in the watcher (`StrandWatcher.suppressStrand`) and drops it from
|
|
2488
2610
|
* {@link getDiscoveredStrands}, so neither a later poll nor a drain can undo a
|
|
2489
2611
|
* deliberate stop. Only an explicit {@link addStrand} does, which is the caller
|
|
2490
|
-
* reversing its own decision. Party-wide removal is {@link unpublishStrand}.
|
|
2612
|
+
* reversing its own decision. Party-wide removal is {@link unpublishStrand}. A strand
|
|
2613
|
+
* joined from another party comes back the same way, from its remembered join;
|
|
2614
|
+
* {@link forgetJoinedStrand} is how to leave one for good.
|
|
2491
2615
|
*/
|
|
2492
2616
|
stopStrand(strandId: string): Promise<void>;
|
|
2493
2617
|
/**
|
|
@@ -2613,7 +2737,7 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2613
2737
|
*
|
|
2614
2738
|
* BUDGET: the supervisor's first attempt is what `start()` waits on — deliberately the drive's
|
|
2615
2739
|
* ordinary deadline rather than a boot-specific one. That deadline is now COUNTED, four link
|
|
2616
|
-
* round trips at the declared `network.linkRoundTripMs` (
|
|
2740
|
+
* round trips at the declared `network.linkRoundTripMs` (14 s at its default, where it was a
|
|
2617
2741
|
* fixed 10 s): a healthy dial-plus-reserve is sub-second even over a WAN, so this is slack for
|
|
2618
2742
|
* a slow link, while going much longer would make a dead relay indistinguishable from a hung
|
|
2619
2743
|
* start and much shorter would fail nodes on links that were merely slow. A host that declares
|
|
@@ -3059,6 +3183,16 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3059
3183
|
* @returns The member key and strand info if successful
|
|
3060
3184
|
*/
|
|
3061
3185
|
formStrand(invitation: OpenInvitation, disclosure?: StrandFormationDisclosure): Promise<FormStrandResult>;
|
|
3186
|
+
/**
|
|
3187
|
+
* Remember the strand a formation just joined (see {@link joinedStrandStore}), so it
|
|
3188
|
+
* is re-offered after a restart even when the app is killed before its `addStrand`.
|
|
3189
|
+
* Last in {@link formStrand}, after the membership adoption, so a failure here leaves
|
|
3190
|
+
* the party key and staged invitation in place for the re-formation it asks for.
|
|
3191
|
+
*
|
|
3192
|
+
* Throws on failure, like {@link adoptFormationMembershipInvite}: the formation's
|
|
3193
|
+
* token is spent, and a join no store names would vanish at the next restart.
|
|
3194
|
+
*/
|
|
3195
|
+
private rememberFormedStrand;
|
|
3062
3196
|
/**
|
|
3063
3197
|
* Adopt an approved closed-strand formation's membership half on the JOINER:
|
|
3064
3198
|
*
|
|
@@ -3145,15 +3279,20 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3145
3279
|
private issueStrandMembershipInvite;
|
|
3146
3280
|
/**
|
|
3147
3281
|
* Remember the responder's strand-network addresses for a strand this node just
|
|
3148
|
-
* formed
|
|
3149
|
-
* launches it
|
|
3150
|
-
*
|
|
3151
|
-
*
|
|
3152
|
-
*
|
|
3153
|
-
*
|
|
3154
|
-
*
|
|
3155
|
-
|
|
3156
|
-
|
|
3282
|
+
* formed in the strand peer book (see {@link strandPeerBookStore}), so the strand's
|
|
3283
|
+
* discovery seed has something to work with when the app launches it — and again
|
|
3284
|
+
* after every restart.
|
|
3285
|
+
*
|
|
3286
|
+
* The carried list is peer-agnostic (`sanitizeStrandAddrs` bounds and parses it,
|
|
3287
|
+
* nothing more), so it is attributed per peer here (`groupAddrsByPeerId`, the same
|
|
3288
|
+
* rule the address-book merge applies) and each peer becomes one unsigned entry seen
|
|
3289
|
+
* just now: the responder disclosed the addresses live a moment ago. An entry naming
|
|
3290
|
+
* no destination peer is dropped there. Scoped strictly to `strandId`: these
|
|
3291
|
+
* addresses reach ONE strand node of ONE other party and must never seed another
|
|
3292
|
+
* strand's mesh or the control peerStore. An empty list records nothing, so a later
|
|
3293
|
+
* formation against the same strand that DOES disclose addresses is not shadowed.
|
|
3294
|
+
*/
|
|
3295
|
+
private recordFormationStrandPeers;
|
|
3157
3296
|
/**
|
|
3158
3297
|
* Encode an open invitation for out-of-band delivery (QR, link, etc.).
|
|
3159
3298
|
*/
|