@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
package/dist/cadre-node.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Libp2p, PeerId } from '@libp2p/interface';
|
|
2
2
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
|
3
|
-
import type { CadreNodeConfig, StrandInstance, StrandRow, StrandConfig, FoundStrandConfig, FoundStrandResult, SAppConfig, CadreNodeEvents, ControlNetworkSeed, ApplySeedResult, AddDroneOptions, AddPhoneOptions, DroneInitResult, InviteResult, CadreInvite, OpenInvitation, FormStrandResult, StrandFormationDisclosure, StrandMembershipInvite, ResolveOpts, SelfRegistrationOutcome, ServiceWakeResult, PushPlatform, DeviceTokenRecord, ResolveDeviceTokenOpts } from './types.js';
|
|
3
|
+
import type { CadreNodeConfig, StrandInstance, StrandRow, StrandConfig, FoundStrandConfig, FoundStrandResult, SAppConfig, CadreNodeEvents, ControlNetworkSeed, ApplySeedResult, AddDroneOptions, AddPhoneOptions, DroneInitResult, InviteResult, CadreInvite, OpenInvitation, FormStrandResult, StrandFormationDisclosure, StrandMembershipInvite, ResolveOpts, SelfRegistrationOutcome, ServiceWakeResult, PushPlatform, DeviceTokenRecord, ResolveDeviceTokenOpts, PendingJoinStatus } from './types.js';
|
|
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
|
|
7
|
+
import { type StrandNetworkStateStore } from './strand-network-state.js';
|
|
8
8
|
import { type EnrolledMachineStore } from './enrolled-machine-store.js';
|
|
9
9
|
import { type SAppIdLookup } from './strand-watcher.js';
|
|
10
10
|
import { type ControlCohortReconcileResult } from './control-cohort.js';
|
|
@@ -84,6 +84,15 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
84
84
|
private enrollmentService;
|
|
85
85
|
private seedBootstrapService;
|
|
86
86
|
private strandSolicitationService;
|
|
87
|
+
/**
|
|
88
|
+
* The service whose formation handler is registered on the control node. Trails
|
|
89
|
+
* {@link strandSolicitationService} while {@link initializeStrandSolicitation} swaps a new
|
|
90
|
+
* one in: the field is set at once so concurrent callers reuse it, the handler only when
|
|
91
|
+
* its queued swap runs.
|
|
92
|
+
*/
|
|
93
|
+
private registeredSolicitation;
|
|
94
|
+
/** Tail of the queued formation-handler swaps ({@link swapFormationResponder}). */
|
|
95
|
+
private solicitationSwaps;
|
|
87
96
|
private strandWakeService;
|
|
88
97
|
/**
|
|
89
98
|
* Control-network strand-address responder. Answers a co-cadre sibling's
|
|
@@ -304,36 +313,54 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
304
313
|
*/
|
|
305
314
|
private readonly strandAddrAskDueAt;
|
|
306
315
|
/**
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
* carry a signature, and the only one that can refresh a peer's addresses without
|
|
316
|
-
* meeting that peer. Read by {@link resolveCohortSeed} (launch + hibernation resume) and
|
|
317
|
-
* re-merged by every {@link refreshStrandPeerAddrs} pass, which is what keeps the
|
|
318
|
-
* entries alive past the peerStore's one-hour address expiry.
|
|
319
|
-
*
|
|
320
|
-
* This is the ONLY cross-party discovery input there is. The strand-addr RPC that
|
|
316
|
+
* The strand-network addresses a formation carried back
|
|
317
|
+
* (`FormationResultMessage.strandAddrs`), by strand id: the responder's live strand
|
|
318
|
+
* node addresses, kept so the strand's first attach has something to dial. Written by
|
|
319
|
+
* {@link recordFormationStrandAddrs}, read by {@link resolveCohortSeed} (launch and
|
|
320
|
+
* hibernation resume) and by every refresh pass for the peers the strand node's FRET
|
|
321
|
+
* table holds no record for yet ({@link remergeUnrecordedFormationAddrs}).
|
|
322
|
+
*
|
|
323
|
+
* This is the only cross-party input a FIRST attach has. The strand-addr RPC that
|
|
321
324
|
* resolves a strand's addresses is membership-gated and answers own-party siblings
|
|
322
|
-
* only, so without
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
325
|
+
* only, so without it a joiner's seed for a two-party strand is empty and the mesh
|
|
326
|
+
* never forms. Every later launch has the strand node's saved network state as well
|
|
327
|
+
* ({@link strandNetworkStateStore}), which is what a restart re-finds the other party
|
|
328
|
+
* from (gotchoices/sereus#18).
|
|
329
|
+
*
|
|
330
|
+
* A re-formation replaces the strand's list. An entry survives a {@link stopStrand}
|
|
331
|
+
* and a stop()→start() of this node instance ({@link cleanup} leaves the map alone),
|
|
332
|
+
* and is dropped where the saved network state is: {@link unpublishStrand},
|
|
333
|
+
* {@link forgetJoinedStrand} and self-revocation.
|
|
334
|
+
*
|
|
335
|
+
* NOTE: accepted tradeoff — in memory only, so a process restart between `formStrand`
|
|
336
|
+
* and the strand's first launch loses the carried addresses, and the strand then
|
|
337
|
+
* launches with no cross-party seed until it is re-formed. Persisting the list on the
|
|
338
|
+
* joined-strand record was weighed and declined: it mixes address state into the join
|
|
339
|
+
* record, and needs an "only until the first run" rule to stop dead addresses being
|
|
340
|
+
* dialled on every launch. Every embedder launches straight after forming, and once
|
|
341
|
+
* the strand has run the saved network state covers every later restart. Revisit if an
|
|
342
|
+
* embedder forms and launches in separate sessions.
|
|
343
|
+
*/
|
|
344
|
+
private readonly formationStrandAddrs;
|
|
345
|
+
/**
|
|
346
|
+
* Node-local strand network state (see `strand-network-state.ts`): per strand, the
|
|
347
|
+
* state db-p2p saves for the strand's libp2p node — its FRET routing table with each
|
|
348
|
+
* peer's signed address record. Handed to every strand launch as
|
|
349
|
+
* `StartStrandConfig.networkState`; the strand node saves into it on every connection
|
|
350
|
+
* and re-imports it when it is next built, which is what gives a restarted strand
|
|
351
|
+
* node addresses for the peers it was talking to.
|
|
352
|
+
*
|
|
353
|
+
* Constructed (or adopted from `config.strandNetworkState.store`) by
|
|
354
|
+
* {@link initializeStrandNetworkStateStore} during {@link start}, deliberately NOT
|
|
327
355
|
* cleared by {@link cleanup}, so it survives a stop()→start() cycle of the same node
|
|
328
356
|
* instance — same lifecycle as {@link bootstrapPeerStore}.
|
|
329
357
|
*
|
|
330
|
-
*
|
|
331
|
-
* {@link
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
* bounded by time and by the strands this node runs rather than by its history.
|
|
358
|
+
* A strand's state survives a {@link stopStrand} and a hibernation quiesce, and is
|
|
359
|
+
* forgotten by {@link unpublishStrand}, {@link forgetJoinedStrand} and
|
|
360
|
+
* self-revocation. A strand detached because the watcher saw its row gone keeps its
|
|
361
|
+
* state (`NOTE:` on `PersistentStrandNetworkStateStore`).
|
|
335
362
|
*/
|
|
336
|
-
private
|
|
363
|
+
private strandNetworkStateStore;
|
|
337
364
|
/**
|
|
338
365
|
* PENDING strand membership invitations learned at formation, keyed by strandId — the
|
|
339
366
|
* single-use `Strand.Invite` credential a closed-strand formation result carried back
|
|
@@ -361,9 +388,23 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
361
388
|
* NOTE: entries live for the node's lifetime (one small pair per formed closed
|
|
362
389
|
* strand); the number of keys is bounded only by the strands this node has ever
|
|
363
390
|
* formed, not by time — if a node ever forms strands at scale, evict on
|
|
364
|
-
* `unpublishStrand` / `forgetJoinedStrand` as
|
|
391
|
+
* `unpublishStrand` / `forgetJoinedStrand` as {@link formationStrandAddrs} is.
|
|
365
392
|
*/
|
|
366
393
|
private readonly pendingMembershipInvites;
|
|
394
|
+
/**
|
|
395
|
+
* Invite keys of the membership invitations this process has staged, by
|
|
396
|
+
* {@link adoptFormationMembershipInvite} or from a `joined` `PendingJoin` row
|
|
397
|
+
* ({@link stageMembershipInvitesFromPendingJoins}), so one the reconciler has settled is not
|
|
398
|
+
* staged again by the next pending-join pass. Same lifetime as
|
|
399
|
+
* {@link pendingMembershipInvites}: a restarted process stages each live one once more, and the
|
|
400
|
+
* reconciler settles it again (spent, or the party already seated).
|
|
401
|
+
*/
|
|
402
|
+
private readonly stagedMembershipInviteKeys;
|
|
403
|
+
/**
|
|
404
|
+
* The pending-join retry loop (`pending-join-runner.ts`): built by {@link start}, stopped by
|
|
405
|
+
* {@link cleanup}. It acts only while this machine is an enrolled owner.
|
|
406
|
+
*/
|
|
407
|
+
private pendingJoinRunner;
|
|
367
408
|
/**
|
|
368
409
|
* Founder launches refused because the strand was founded before the per-party
|
|
369
410
|
* identity split (`PreSplitStrandIdentityError`), keyed by strandId. Read by
|
|
@@ -767,15 +808,15 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
767
808
|
*/
|
|
768
809
|
private initializeJoinedStrandStore;
|
|
769
810
|
/**
|
|
770
|
-
* Construct (or adopt) the node-local strand
|
|
771
|
-
* {@link
|
|
811
|
+
* Construct (or adopt) the node-local strand network state (see
|
|
812
|
+
* {@link strandNetworkStateStore}). Synchronous for the reason
|
|
772
813
|
* {@link initializeBootstrapPeerStore} is: an injected store has already loaded its
|
|
773
814
|
* persisted entries by the time it is handed in, and the in-memory fallback has
|
|
774
815
|
* nothing to load. The instance is kept across stop()→start(). A store scoped to a
|
|
775
|
-
* different party is a configuration error, fail closed: another party's
|
|
776
|
-
*
|
|
816
|
+
* different party is a configuration error, fail closed: another party's routing
|
|
817
|
+
* tables must never be imported into this node's strands.
|
|
777
818
|
*/
|
|
778
|
-
private
|
|
819
|
+
private initializeStrandNetworkStateStore;
|
|
779
820
|
/**
|
|
780
821
|
* The node-local enrolled-machine store (null before {@link start}) — what this
|
|
781
822
|
* node last knew about its party's size. Exposed for diagnostics and for a host
|
|
@@ -790,12 +831,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
790
831
|
*/
|
|
791
832
|
getBootstrapPeerStore(): BootstrapPeerStore | null;
|
|
792
833
|
/**
|
|
793
|
-
* The node-local strand
|
|
794
|
-
*
|
|
795
|
-
* diagnostics and for a host that wants to show "
|
|
796
|
-
*
|
|
834
|
+
* The node-local strand network state (null before {@link start}) — per strand, the
|
|
835
|
+
* state its strand node last saved and will re-import when next built. Exposed for
|
|
836
|
+
* diagnostics and for a host that wants to show "what routing table would this
|
|
837
|
+
* strand restart with?".
|
|
797
838
|
*/
|
|
798
|
-
|
|
839
|
+
getStrandNetworkStateStore(): StrandNetworkStateStore | null;
|
|
799
840
|
/**
|
|
800
841
|
* The node-local trusted-owner anchor (null before {@link start}). This is
|
|
801
842
|
* the set the authorized-membership predicate and seed-trust anchor consult —
|
|
@@ -948,11 +989,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
948
989
|
* `StrandSolicitationService.hasOutstandingInvitation`). A formation
|
|
949
990
|
* initiator is another party's peer by design and its token is only
|
|
950
991
|
* checkable inside the protocol, so the gate asks the coarser question
|
|
951
|
-
* "does this node expect a stranger at all?".
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
* bring-up) and `formStrand`'s lazy initialization both leave the gate
|
|
955
|
-
* armed, because neither mints an invitation.
|
|
992
|
+
* "does this node expect a stranger at all?". REGISTERING the responder
|
|
993
|
+
* does not suspend stranger denial: every node registers one at
|
|
994
|
+
* {@link start}, and registering mints no invitation.
|
|
956
995
|
*
|
|
957
996
|
* Ordering is semantically free (the checks are OR'd) but decides who pays:
|
|
958
997
|
* checks 1-3 are in-memory, 4/5 share one control-DB read, and only a peer
|
|
@@ -984,6 +1023,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
984
1023
|
* layer is fail-open behind `ADMISSION_DECISION_TIMEOUT_MS`, so the live
|
|
985
1024
|
* read is safe here — unlike the per-stream gate, which must consult the
|
|
986
1025
|
* materialized {@link authorizedControlPeers} snapshot instead.
|
|
1026
|
+
* NOTE: check 6 adds a second control read (`hasOutstandingFormationInvite`) for a
|
|
1027
|
+
* stranger with no locally minted invitation in play, on every node now that every
|
|
1028
|
+
* node runs the responder — a relay-enabled storage node included. If stranger
|
|
1029
|
+
* connections to such a node ever arrive fast enough for that read to show, cache
|
|
1030
|
+
* the answer for a few seconds.
|
|
987
1031
|
* NOTE: on a relay-DISABLED node, a sibling whose membership row has not yet
|
|
988
1032
|
* replicated here is denied until the row converges (typically via the
|
|
989
1033
|
* owner); either side's next outbound reconcile dial (outbound is never
|
|
@@ -1326,6 +1370,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1326
1370
|
* handling, is what keeps a mixed list from taking a whole peer offline.
|
|
1327
1371
|
*/
|
|
1328
1372
|
resolvePeerAddrs(peerId: string, opts?: ResolveOpts): Promise<Multiaddr[]>;
|
|
1373
|
+
/**
|
|
1374
|
+
* {@link resolvePeerAddrs} with the record's `UpdatedAt` kept beside the addresses, for a
|
|
1375
|
+
* caller that ranks peers by how recently they published. `null` wherever that returns `[]`
|
|
1376
|
+
* for a failed gate.
|
|
1377
|
+
*/
|
|
1378
|
+
private resolvePeerRecord;
|
|
1329
1379
|
/**
|
|
1330
1380
|
* Guarantee every address handed to a control-network dial terminates in
|
|
1331
1381
|
* `/p2p/<peerId>`, with no duplicates — the invariant every dial path
|
|
@@ -1519,15 +1569,18 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1519
1569
|
*
|
|
1520
1570
|
* The list may name transports this node cannot dial (a lent node reports TCP
|
|
1521
1571
|
* and `/ws` addresses to a phone that dials WebSockets only). That needs no
|
|
1522
|
-
* filtering here: libp2p's dial queue (`calculateMultiaddrs`, libp2p 3.
|
|
1572
|
+
* filtering here: libp2p's dial queue (`calculateMultiaddrs`, libp2p 3.3.11)
|
|
1523
1573
|
* rejects an address no transport can dial before touching the network, so
|
|
1524
1574
|
* such an address costs a log line.
|
|
1525
1575
|
*
|
|
1526
1576
|
* The list is NOT handed to one `dial()`. libp2p tries a multi-address dial's
|
|
1527
|
-
* addresses one after another under a single deadline,
|
|
1528
|
-
*
|
|
1529
|
-
*
|
|
1530
|
-
*
|
|
1577
|
+
* addresses one after another under a single deadline, and sorts loopback
|
|
1578
|
+
* addresses last — so one or two addresses that never answer use up most of
|
|
1579
|
+
* the deadline before the address that works is tried. libp2p 3.3's
|
|
1580
|
+
* per-address `addressDialTimeout` does not prevent that: cadre sizes it for a
|
|
1581
|
+
* cold relayed open through two admission decisions (`optimysticDialLimits`,
|
|
1582
|
+
* 39 s at the default declared link).
|
|
1583
|
+
* {@link dialPeerAddrs} dials each address on its own time limit instead.
|
|
1531
1584
|
*/
|
|
1532
1585
|
private resolveControlDialAddrs;
|
|
1533
1586
|
/**
|
|
@@ -2479,13 +2532,6 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2479
2532
|
* for a relay we are not yet connected to.
|
|
2480
2533
|
*/
|
|
2481
2534
|
private resolveCohortSeed;
|
|
2482
|
-
/**
|
|
2483
|
-
* The strand peer book's contribution to a strand's seed: every live entry's
|
|
2484
|
-
* addresses, freshest peer first, minus this node's own entry when `selfPeerId` is
|
|
2485
|
-
* known (the book swap files one under the strand transport id; a node must never
|
|
2486
|
-
* dial itself). Empty before {@link start} builds the store.
|
|
2487
|
-
*/
|
|
2488
|
-
private strandPeerBookAddrs;
|
|
2489
2535
|
/**
|
|
2490
2536
|
* The own-party half of {@link resolveCohortSeed}: strand-network addresses resolved
|
|
2491
2537
|
* from CONNECTED cohort siblings over the control-mesh strand-addr RPC, doubling as
|
|
@@ -2602,9 +2648,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2602
2648
|
* caller runs the drive regardless).
|
|
2603
2649
|
*
|
|
2604
2650
|
* NOTE: against a relay that is DOWN this hook costs up to two strand-addr
|
|
2605
|
-
* timeouts (dial by peer id, then by addr;
|
|
2651
|
+
* timeouts (dial by peer id, then by addr; 28.5 s each at the default declared link round trip)
|
|
2606
2652
|
* before the reservation drive even starts, so one failed re-drive holds the supervisor
|
|
2607
|
-
* `driving` for those
|
|
2653
|
+
* `driving` for those 57 s plus the drive's own deadline — 75 s at the default, and longer on
|
|
2608
2654
|
* a host that declared a slower one (`link-budget.ts`).
|
|
2609
2655
|
* Bounded and harmless while the relay is unreachable anyway; if recovery
|
|
2610
2656
|
* latency after a relay comes back ever matters, skip the announce when the
|
|
@@ -2615,18 +2661,19 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2615
2661
|
/** One strand's share of {@link refreshDelegateGrants}: announce to the relays whose grant is due. */
|
|
2616
2662
|
private announceDelegateToDueRelays;
|
|
2617
2663
|
/**
|
|
2618
|
-
* Keep each running strand's own libp2p address book warm: re-merge
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2664
|
+
* Keep each running strand's own libp2p address book warm: re-merge the address
|
|
2665
|
+
* records its FRET routing table holds on every pass
|
|
2666
|
+
* ({@link remergeStrandFretRecords}), and re-ask each connected SIBLING for its
|
|
2667
|
+
* strand addresses over the control mesh when that (sibling, strand) is due
|
|
2621
2668
|
* ({@link strandAddrAskDueAt}).
|
|
2622
2669
|
*
|
|
2623
|
-
* Without this, a strand's address book
|
|
2670
|
+
* Without this, cadre-core writes a strand's address book exactly once — the
|
|
2624
2671
|
* launch/resume seed — and everything below cadre-core that dials a strand peer
|
|
2625
2672
|
* by bare peer id (Optimystic's cluster and repo clients, FRET ping/announce)
|
|
2626
|
-
* loses its address for any
|
|
2673
|
+
* loses its address for any peer it is not currently connected to: a sibling
|
|
2627
2674
|
* that restarted its strand node or rotated its relay reservation is never
|
|
2628
|
-
* re-resolved, and
|
|
2629
|
-
* one-hour expiry (see `peer-addr-book.ts`).
|
|
2675
|
+
* re-resolved, and every address, another party's included, falls off at the
|
|
2676
|
+
* peerStore's one-hour expiry (see `peer-addr-book.ts`).
|
|
2630
2677
|
*
|
|
2631
2678
|
* Due times are per (sibling, strand) and set from each sibling's own outcome, so
|
|
2632
2679
|
* a sibling that connects late — a phone joining after the party's always-on
|
|
@@ -2670,17 +2717,59 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2670
2717
|
private strandAddrRefreshTargets;
|
|
2671
2718
|
/**
|
|
2672
2719
|
* One strand's share of {@link refreshStrandPeerAddrs}: RPC the siblings that are
|
|
2673
|
-
* due
|
|
2674
|
-
*
|
|
2675
|
-
* strand's failure never costs the others their refresh.
|
|
2720
|
+
* due and merge their answers into the strand's address book, then re-merge the
|
|
2721
|
+
* address records the strand node's FRET table holds. Errors are logged and
|
|
2722
|
+
* swallowed so one strand's failure never costs the others their refresh.
|
|
2676
2723
|
*
|
|
2677
|
-
* The
|
|
2678
|
-
*
|
|
2679
|
-
*
|
|
2680
|
-
*
|
|
2681
|
-
*
|
|
2724
|
+
* The sibling half runs first, so a failure reading the FRET table cannot cost a
|
|
2725
|
+
* sibling answer its merge. The FRET half, and the formation-carried addresses of
|
|
2726
|
+
* the peers it holds no record for, run on EVERY pass, whether or not any sibling is
|
|
2727
|
+
* due or connected — see {@link remergeStrandFretRecords} and
|
|
2728
|
+
* {@link remergeUnrecordedFormationAddrs} for why.
|
|
2682
2729
|
*/
|
|
2683
2730
|
private refreshOneStrandPeerAddrs;
|
|
2731
|
+
/**
|
|
2732
|
+
* Is `strandNode` still the node `strandId` runs on? Asked again after every await
|
|
2733
|
+
* in a refresh pass: a strand stopped mid-pass, or one already restarted onto a new
|
|
2734
|
+
* node, must never have its store written to.
|
|
2735
|
+
*/
|
|
2736
|
+
private isRunningStrandNode;
|
|
2737
|
+
/**
|
|
2738
|
+
* Re-merge, into a running strand node's address book, the addresses of every peer
|
|
2739
|
+
* its FRET routing table holds a signed address record for (`strand-fret-addrs.ts`).
|
|
2740
|
+
*
|
|
2741
|
+
* This is what keeps ANOTHER PARTY's strand nodes dialable from a node that stays
|
|
2742
|
+
* up. Nothing re-resolves their addresses — the strand-addr RPC answers own-party
|
|
2743
|
+
* siblings only — and the peerStore hides an address one hour after it was first
|
|
2744
|
+
* observed. FRET keeps each peer's record but hands it to the peerStore only when it
|
|
2745
|
+
* arrives or is imported, so without this pass a connection to another party that
|
|
2746
|
+
* drops after the first hour could not be redialed by either side.
|
|
2747
|
+
*
|
|
2748
|
+
* A record is held while FRET holds the peer's table entry, and at most 14 days after
|
|
2749
|
+
* it was last confirmed, so that is also how long a wrong address can keep being
|
|
2750
|
+
* re-merged. Each record is signed by the peer it names and verified before use, so
|
|
2751
|
+
* the exposure is failed dials to an address that peer itself published.
|
|
2752
|
+
*
|
|
2753
|
+
* NOTE: every pass serialises the whole FRET table (`exportTable()`), verifies one
|
|
2754
|
+
* signature per record and makes one `peerStore.merge` per peer, per running strand
|
|
2755
|
+
* per 15 s tick. Fine at strand table sizes, and an unchanged address set writes
|
|
2756
|
+
* nothing in libp2p's persistent peer store. If many strands or large tables make it
|
|
2757
|
+
* show up, read only the entries whose address stamp is near the one-hour mark.
|
|
2758
|
+
*
|
|
2759
|
+
* @returns the ids of the peers the table holds a usable record for.
|
|
2760
|
+
*/
|
|
2761
|
+
private remergeStrandFretRecords;
|
|
2762
|
+
/**
|
|
2763
|
+
* Re-merge the addresses this strand's formation carried ({@link formationStrandAddrs})
|
|
2764
|
+
* for every peer the strand node's FRET table holds no record for (`recorded`).
|
|
2765
|
+
*
|
|
2766
|
+
* Until the first connection to the responder, the carried addresses are the only
|
|
2767
|
+
* thing naming it, and the launch seed writes them once. FRET's `bootstraps` keep only
|
|
2768
|
+
* the peer id, so if the responder stays unreachable past the peerStore's one-hour
|
|
2769
|
+
* expiry, nothing could dial it when it returns. Once FRET holds the peer's own signed
|
|
2770
|
+
* record, that record supersedes what the formation carried and this stops.
|
|
2771
|
+
*/
|
|
2772
|
+
private remergeUnrecordedFormationAddrs;
|
|
2684
2773
|
/**
|
|
2685
2774
|
* RPC `due` siblings for `strandId` and set each one's next due time from its own
|
|
2686
2775
|
* outcome: an answer, even an empty one, waits the full refresh interval; anything
|
|
@@ -2695,11 +2784,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2695
2784
|
* attributed per peer. Best-effort throughout: an address-book write must never
|
|
2696
2785
|
* fail a launch, a resume, or a reconcile pass.
|
|
2697
2786
|
*
|
|
2698
|
-
* `addrs` is
|
|
2699
|
-
* {@link groupAddrsByPeerId} attributes each
|
|
2700
|
-
* peerId in its final `/p2p/` component — never
|
|
2701
|
-
* which names a different libp2p node entirely.
|
|
2702
|
-
* dropped there and counted here, once per pass.
|
|
2787
|
+
* `addrs` is a peer-agnostic list — the union the strand-addr RPC returns, or the
|
|
2788
|
+
* addresses a formation carried — so {@link groupAddrsByPeerId} attributes each
|
|
2789
|
+
* entry to the **strand transport** peerId in its final `/p2p/` component — never
|
|
2790
|
+
* the sibling's control peerId, which names a different libp2p node entirely.
|
|
2791
|
+
* Entries that name no peer are dropped there and counted here, once per pass.
|
|
2703
2792
|
*
|
|
2704
2793
|
* NOTE: a member could answer with arbitrary multiaddrs bound to arbitrary peer
|
|
2705
2794
|
* ids and poison this address book. That is the same exposure the launch-time
|
|
@@ -2709,14 +2798,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2709
2798
|
* peerStore's one-hour expiry. No new gating here — cross-party strand trust is
|
|
2710
2799
|
* `backlog/strand-network-nat-relay-reachability`.
|
|
2711
2800
|
*
|
|
2712
|
-
* NOTE: one input
|
|
2713
|
-
* ({@link
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
*
|
|
2719
|
-
* exposure is a handful of failed dials, not a trust hole.
|
|
2801
|
+
* NOTE: one input outlives that hour — a formation's carried addresses
|
|
2802
|
+
* ({@link formationStrandAddrs}) are in every launch and resume seed for as long as
|
|
2803
|
+
* this process remembers the formation, and re-merged on every refresh pass until the
|
|
2804
|
+
* strand node's FRET table holds the peer's own record, so a junk address from a
|
|
2805
|
+
* responder that is never met keeps being re-merged. Bounded by `sanitizeStrandAddrs`,
|
|
2806
|
+
* replaced by a re-formation, dropped on `unpublishStrand` / `forgetJoinedStrand`, and
|
|
2807
|
+
* still authority-free — so the exposure is a handful of failed dials, not a trust hole.
|
|
2720
2808
|
*/
|
|
2721
2809
|
private mergeStrandPeerAddrs;
|
|
2722
2810
|
/**
|
|
@@ -2732,7 +2820,8 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2732
2820
|
/**
|
|
2733
2821
|
* Leave a strand joined from another party, for the whole party: remove its party-wide
|
|
2734
2822
|
* `JoinedStrand` row (owner-signed, with a `Revocation` tombstone), then this machine's
|
|
2735
|
-
* unpublished record, its
|
|
2823
|
+
* unpublished record, its formation-carried addresses, its saved network state and any
|
|
2824
|
+
* session-kept entry, then
|
|
2736
2825
|
* {@link stopStrand} it here. Every other machine's watcher then sees the row gone and
|
|
2737
2826
|
* detaches the strand, a storage replica included; a machine offline at the time reaps the
|
|
2738
2827
|
* row once the tombstone reaches it. The joiner's counterpart of {@link unpublishStrand},
|
|
@@ -2771,8 +2860,9 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2771
2860
|
* session here — the `strand:revoked` contract is that nothing is torn down for the app —
|
|
2772
2861
|
* and its party-wide row is queued for removal by the next connected owner reconcile pass
|
|
2773
2862
|
* (`JoinedStrandSession.forgetAfterThisSession`). A no-op for this party's own strands,
|
|
2774
|
-
* which have neither record; the
|
|
2775
|
-
* removed party must not keep dialing the
|
|
2863
|
+
* which have neither record; the formation-carried addresses and the saved network
|
|
2864
|
+
* state are forgotten either way, since a removed party must not keep dialing the
|
|
2865
|
+
* strand's peers.
|
|
2776
2866
|
*
|
|
2777
2867
|
* NOTE: accepted tradeoff — a sibling machine that has not raised `strand:revoked` itself
|
|
2778
2868
|
* detaches the strand (`strand:stopped`) when the party-wide removal reaches it, instead
|
|
@@ -2790,25 +2880,13 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2790
2880
|
*/
|
|
2791
2881
|
private forgetRevokedJoin;
|
|
2792
2882
|
/**
|
|
2793
|
-
* Forget a strand's
|
|
2794
|
-
*
|
|
2795
|
-
*
|
|
2883
|
+
* Forget what this node holds about a strand's peers: the addresses its formation
|
|
2884
|
+
* carried (see {@link formationStrandAddrs}) and its saved network state (see
|
|
2885
|
+
* {@link strandNetworkStateStore}). The store write is fire-and-log — the removal is
|
|
2886
|
+
* visible synchronously by the store's contract, and a failed persist only leaves the
|
|
2887
|
+
* entry on disk for the next start.
|
|
2796
2888
|
*/
|
|
2797
2889
|
private forgetStrandPeers;
|
|
2798
|
-
/**
|
|
2799
|
-
* The strand peer book's observation writer (`StartStrandConfig.onStrandPeerIdentified`):
|
|
2800
|
-
* a strand node identified a strand peer at `observation.addrs`, so remember it as an
|
|
2801
|
-
* unsigned entry seen just now. The observer never reports self, and the store binds
|
|
2802
|
-
* every address to the peer id before filing it.
|
|
2803
|
-
*/
|
|
2804
|
-
private observeStrandPeer;
|
|
2805
|
-
/**
|
|
2806
|
-
* Merge one entry into the peer book. Fire-and-log: the entry is visible
|
|
2807
|
-
* synchronously by the store's contract, and the promise tracks durability only. A
|
|
2808
|
-
* persist failure costs restart survival, never this session's seed — the same trade
|
|
2809
|
-
* {@link retainDialTarget} makes.
|
|
2810
|
-
*/
|
|
2811
|
-
private rememberStrandPeer;
|
|
2812
2890
|
/**
|
|
2813
2891
|
* Stop a strand on THIS node only: untrack it from hibernation, drop its sApp config,
|
|
2814
2892
|
* stop the local instance, and emit `strand:stopped`. The shared `Strand` row is left
|
|
@@ -3392,32 +3470,128 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3392
3470
|
*/
|
|
3393
3471
|
dialInvite(invite: CadreInvite): Promise<void>;
|
|
3394
3472
|
/**
|
|
3395
|
-
*
|
|
3396
|
-
*
|
|
3473
|
+
* Replace this node's strand solicitation service — the formation responder every node
|
|
3474
|
+
* installs at {@link start}, and the initiator side of {@link formStrand}. Optional: call it
|
|
3475
|
+
* only to customize the responder (an approver, a provisioner, formation deadlines). The
|
|
3476
|
+
* new service's handler replaces the previous one's on the control node, and invitations
|
|
3477
|
+
* the previous service minted stay outstanding.
|
|
3478
|
+
*
|
|
3479
|
+
* Without `options.formationUsageRecorder`, tokens are checked against this party's
|
|
3480
|
+
* replicated `FormationInvite`/`FormationUsage` rows ({@link ControlFormationUsageRecorder}).
|
|
3481
|
+
* A responder that accepts every token is reachable only by constructing
|
|
3482
|
+
* {@link StrandSolicitationService} directly.
|
|
3397
3483
|
*
|
|
3398
3484
|
* @param options - Configuration for the solicitation service
|
|
3399
3485
|
*/
|
|
3400
3486
|
initializeStrandSolicitation(options?: StrandSolicitationServiceOptions): Promise<void>;
|
|
3401
3487
|
/**
|
|
3402
|
-
*
|
|
3488
|
+
* Answer formation from start. Log-and-continue: a node that cannot is still useful, and
|
|
3489
|
+
* {@link createOpenInvitation} / {@link formStrand} install the responder when it is missing.
|
|
3490
|
+
*/
|
|
3491
|
+
private installDefaultFormationResponder;
|
|
3492
|
+
/**
|
|
3493
|
+
* Move the control node's formation handler from the registered service to `service`.
|
|
3494
|
+
* Queued by {@link initializeStrandSolicitation} so swaps run one at a time: libp2p allows
|
|
3495
|
+
* one handler per protocol id, and two overlapping swaps would each find the other's
|
|
3496
|
+
* handler in the way. A failed swap registers the previous service again, points
|
|
3497
|
+
* {@link strandSolicitationService} back at it unless a later call has replaced it, and
|
|
3498
|
+
* rethrows.
|
|
3499
|
+
*
|
|
3500
|
+
* NOTE: same stray-handler caveat as {@link installSeedBootstrapService} — a failed
|
|
3501
|
+
* peer-store merge leaves the formation handler registered, so the restore below (and a
|
|
3502
|
+
* retry) rejects as a duplicate.
|
|
3503
|
+
*/
|
|
3504
|
+
private swapFormationResponder;
|
|
3505
|
+
/**
|
|
3506
|
+
* Get the strand solicitation service (for advanced use). Non-null on a started node unless
|
|
3507
|
+
* the install at {@link start} failed.
|
|
3403
3508
|
*/
|
|
3404
3509
|
getStrandSolicitationService(): StrandSolicitationService | null;
|
|
3405
3510
|
/**
|
|
3406
3511
|
* Create an open invitation for others to form strands with this party.
|
|
3407
3512
|
*
|
|
3513
|
+
* The invitation's bootstrap list names this machine first (it is the one most likely to
|
|
3514
|
+
* run the host strand), then a few of the party's other machines
|
|
3515
|
+
* ({@link siblingInvitationAddrs}), so a joiner can still form while this one is offline.
|
|
3516
|
+
*
|
|
3408
3517
|
* @param sAppId - The sApp to use for formed strands
|
|
3409
3518
|
* @param expirationMs - How long the invitation is valid (ms from now)
|
|
3410
3519
|
* @returns The open invitation to share out-of-band
|
|
3520
|
+
* @throws when neither this machine nor any other machine of the party has an address
|
|
3411
3521
|
*/
|
|
3412
3522
|
createOpenInvitation(sAppId: string, expirationMs?: number): Promise<OpenInvitation>;
|
|
3413
3523
|
/**
|
|
3414
|
-
*
|
|
3524
|
+
* Addresses of the party's other machines for an invitation's bootstrap list
|
|
3525
|
+
* ({@link selectInvitationSiblingAddrs} picks which). The source is each authorized
|
|
3526
|
+
* member's signed `CadrePeer` record ({@link resolvePeerRecord}), so a machine whose record
|
|
3527
|
+
* is missing, stale or untrusted is left out; live connections only order them.
|
|
3528
|
+
*
|
|
3529
|
+
* Best-effort: a failed read leaves the invitation naming this machine alone, which is what
|
|
3530
|
+
* it named before siblings were added.
|
|
3531
|
+
*/
|
|
3532
|
+
private siblingInvitationAddrs;
|
|
3533
|
+
/**
|
|
3534
|
+
* Form a strand with a responder via an open invitation: one attempt, from this machine, with
|
|
3535
|
+
* nothing recorded party-wide. {@link requestJoin} is the path that keeps trying.
|
|
3415
3536
|
*
|
|
3416
3537
|
* @param invitation - The open invitation received out-of-band
|
|
3417
3538
|
* @param disclosure - Identity/context information to share with the responder
|
|
3418
3539
|
* @returns The member key and strand info if successful
|
|
3540
|
+
* @throws `FormationRejectedError` or `FormationUnreachableError` when the formation fails, and
|
|
3541
|
+
* `FormationPostApprovalError` when it was approved and a step on this machine then failed
|
|
3419
3542
|
*/
|
|
3420
3543
|
formStrand(invitation: OpenInvitation, disclosure?: StrandFormationDisclosure): Promise<FormStrandResult>;
|
|
3544
|
+
/**
|
|
3545
|
+
* Ask to join through `invitation` and have the party keep trying until the join works, the
|
|
3546
|
+
* invitation is used up or expires, or the request is dismissed: across restarts, and from
|
|
3547
|
+
* any owner machine of the party (`docs/strands.md` → "Joining while the inviter is
|
|
3548
|
+
* offline"). Records a party-wide `PendingJoin` row, runs one attempt on this machine at
|
|
3549
|
+
* once, and returns the status after it: `'joined'` when the inviter answered yes, `'waiting'`
|
|
3550
|
+
* when it was unreachable or not ready, `'failed'` when it refused for good.
|
|
3551
|
+
*
|
|
3552
|
+
* Asking again for an invitation whose request is still pending adopts that request as it
|
|
3553
|
+
* is; asking again after it finished starts a fresh one. Later changes arrive as
|
|
3554
|
+
* `pendingJoin:changed`. A joined strand is offered through `strand:discovered` like any
|
|
3555
|
+
* {@link formStrand} join. Do not also call {@link formStrand} with the same invitation:
|
|
3556
|
+
* nothing coordinates the two, and one of them gets `token-spent`.
|
|
3557
|
+
*
|
|
3558
|
+
* @throws on a machine that is not an enrolled owner (the row is owner-signed), and on an
|
|
3559
|
+
* invitation already past its expiration
|
|
3560
|
+
*/
|
|
3561
|
+
requestJoin(invitation: OpenInvitation, disclosure?: StrandFormationDisclosure): Promise<PendingJoinStatus>;
|
|
3562
|
+
/**
|
|
3563
|
+
* Every join asked for with {@link requestJoin} and not dismissed, pending or finished, as this
|
|
3564
|
+
* machine sees it (see `PendingJoinStatus` for which states are machine-local).
|
|
3565
|
+
*/
|
|
3566
|
+
listPendingJoins(): Promise<PendingJoinStatus[]>;
|
|
3567
|
+
/**
|
|
3568
|
+
* Remove a join request party-wide. On a pending request this cancels it: every owner machine
|
|
3569
|
+
* stops at its next read, and an attempt already running does not record its outcome (a join
|
|
3570
|
+
* it made stays on that machine, as any {@link formStrand} join does). Owner machines only.
|
|
3571
|
+
* Resolves `false` when there was no such request.
|
|
3572
|
+
*/
|
|
3573
|
+
dismissPendingJoin(id: string): Promise<boolean>;
|
|
3574
|
+
private requirePendingJoins;
|
|
3575
|
+
/** This machine's owner key and signer for an owner-signed control write, or a throw carrying `refusal`. */
|
|
3576
|
+
private requireOwnerSigner;
|
|
3577
|
+
/**
|
|
3578
|
+
* Write a join request's row, or adopt the party's existing row for the same invitation: a
|
|
3579
|
+
* pending one as it is, a finished one replaced by `requested` (the user asked again).
|
|
3580
|
+
*/
|
|
3581
|
+
private recordJoinRequest;
|
|
3582
|
+
/** Build and start the pending-join retry loop over this node (see {@link pendingJoinRunner}). */
|
|
3583
|
+
private startPendingJoinRunner;
|
|
3584
|
+
/** The invitation a `PendingJoin` row stores. A failure names the row, never the invitation, which is a bearer credential. */
|
|
3585
|
+
private pendingJoinInvitation;
|
|
3586
|
+
private pendingJoinSAppId;
|
|
3587
|
+
/**
|
|
3588
|
+
* Stage the membership invitation of each `joined` row this process has not staged yet, so a
|
|
3589
|
+
* closed strand joined on another owner machine is seated by whichever machine launches it
|
|
3590
|
+
* first; the party key it admits is the replicated `StrandPartyKey` row the finishing machine
|
|
3591
|
+
* seated. A strand that already has an invitation staged keeps it, for the reconciler to
|
|
3592
|
+
* settle first.
|
|
3593
|
+
*/
|
|
3594
|
+
private stageMembershipInvitesFromPendingJoins;
|
|
3421
3595
|
/**
|
|
3422
3596
|
* Remember the strand a formation just joined (see {@link joinedStrandStore}), so it
|
|
3423
3597
|
* is re-offered after a restart even when the app is killed before its `addStrand`, and
|
|
@@ -3550,21 +3724,27 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3550
3724
|
*/
|
|
3551
3725
|
private wakeHostStrandForFormation;
|
|
3552
3726
|
/**
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
3555
|
-
*
|
|
3556
|
-
* after every restart.
|
|
3727
|
+
* Keep the responder's strand-network addresses for a strand this node just formed
|
|
3728
|
+
* (see {@link formationStrandAddrs}), so the strand's discovery seed has something to
|
|
3729
|
+
* dial when the app launches it.
|
|
3557
3730
|
*
|
|
3558
3731
|
* The carried list is peer-agnostic (`sanitizeStrandAddrs` bounds and parses it,
|
|
3559
3732
|
* nothing more), so it is attributed per peer here (`groupAddrsByPeerId`, the same
|
|
3560
|
-
* rule the address-book merge applies) and
|
|
3561
|
-
*
|
|
3562
|
-
*
|
|
3563
|
-
*
|
|
3564
|
-
*
|
|
3565
|
-
*
|
|
3566
|
-
|
|
3567
|
-
|
|
3733
|
+
* rule the address-book merge applies) and kept grouped by peer; an entry naming no
|
|
3734
|
+
* destination peer is dropped there. Scoped strictly to `strandId`: these addresses
|
|
3735
|
+
* reach ONE strand node of ONE other party and must never seed another strand's mesh
|
|
3736
|
+
* or the control peerStore.
|
|
3737
|
+
*
|
|
3738
|
+
* A list that names a peer REPLACES the strand's earlier one: the responder
|
|
3739
|
+
* disclosed its current addresses, so the older list is stale. An empty list, or one
|
|
3740
|
+
* naming no peer, records nothing, so it cannot wipe an earlier disclosure.
|
|
3741
|
+
*
|
|
3742
|
+
* A strand already running when this lands (a re-formation, which is the recovery
|
|
3743
|
+
* path for a dead address) gets the new addresses merged into its address book now.
|
|
3744
|
+
* Nothing else would deliver them: the seed is read only at launch and resume, and the
|
|
3745
|
+
* refresh pass skips a peer FRET already holds a record for — the stale one, here.
|
|
3746
|
+
*/
|
|
3747
|
+
private recordFormationStrandAddrs;
|
|
3568
3748
|
/**
|
|
3569
3749
|
* Encode an open invitation for out-of-band delivery (QR, link, etc.).
|
|
3570
3750
|
*/
|