@serfab/cadre-core 1.3.0 → 1.5.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/README.md +5 -3
- package/dist/cadre-node.d.ts +70 -34
- package/dist/cadre-node.js +197 -60
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-database.d.ts +24 -10
- package/dist/control-database.js +48 -16
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +4 -4
- package/dist/control-formation-recorder.js +6 -6
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-read-retry.d.ts +12 -0
- package/dist/control-read-retry.js +12 -0
- package/dist/control-read-retry.js.map +1 -1
- package/dist/control-write-retry.d.ts +5 -4
- package/dist/control-write-retry.js +24 -7
- package/dist/control-write-retry.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/link-budget.d.ts +182 -0
- package/dist/link-budget.js +195 -0
- package/dist/link-budget.js.map +1 -0
- package/dist/membership-connection-gater.d.ts +18 -5
- package/dist/membership-connection-gater.js +50 -10
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/peer-dial.d.ts +36 -17
- package/dist/peer-dial.js +37 -17
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +58 -4
- package/dist/peer-join-backfill.js +165 -20
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/relay-reservation.d.ts +59 -11
- package/dist/relay-reservation.js +169 -43
- package/dist/relay-reservation.js.map +1 -1
- package/dist/seed-bootstrap.js +2 -1
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/storage-scope.d.ts +50 -12
- package/dist/storage-scope.js +85 -12
- package/dist/storage-scope.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +43 -5
- package/dist/strand-first-sync-gate.js +55 -7
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-manager.js +2 -1
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-id.d.ts +35 -0
- package/dist/strand-id.js +46 -0
- package/dist/strand-id.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +27 -2
- package/dist/strand-instance-manager.js +75 -15
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +200 -45
- package/dist/strand-membership-reconciler.js +302 -86
- package/dist/strand-membership-reconciler.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +3 -2
- package/dist/strand-membership-writer.js +67 -90
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-network-config.d.ts +3 -3
- package/dist/strand-network-config.js +3 -3
- package/dist/strand-solicitation.js +2 -1
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-watcher.d.ts +45 -0
- package/dist/strand-watcher.js +74 -13
- package/dist/strand-watcher.js.map +1 -1
- package/dist/types.d.ts +190 -24
- package/dist/types.js +73 -4
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/cadre-node.ts +7445 -7302
- package/src/control-database.ts +48 -16
- package/src/control-formation-recorder.ts +6 -6
- package/src/control-read-retry.ts +214 -202
- package/src/control-write-retry.ts +24 -7
- package/src/index.ts +29 -2
- package/src/link-budget.ts +217 -0
- package/src/membership-connection-gater.ts +56 -11
- package/src/peer-dial.ts +39 -17
- package/src/peer-join-backfill.ts +192 -23
- package/src/relay-reservation.ts +1119 -951
- package/src/seed-bootstrap.ts +2 -1
- package/src/storage-scope.ts +163 -78
- package/src/strand-first-sync-gate.ts +55 -7
- package/src/strand-formation-manager.ts +647 -646
- package/src/strand-id.ts +48 -0
- package/src/strand-instance-manager.ts +1516 -1440
- package/src/strand-membership-reconciler.ts +334 -92
- package/src/strand-membership-writer.ts +1962 -1987
- package/src/strand-network-config.ts +250 -250
- package/src/strand-solicitation.ts +500 -499
- package/src/strand-watcher.ts +388 -325
- package/src/types.ts +192 -23
package/README.md
CHANGED
|
@@ -236,9 +236,11 @@ A **scope key** is what the factory receives. It is the strand id for each stran
|
|
|
236
236
|
which holds one party's own records and must not be shared between parties. Every key is
|
|
237
237
|
opaque and already safe as a file, directory or database name (always within
|
|
238
238
|
`[A-Za-z0-9._-]`): use it verbatim, do not parse it. `isControlStorageScope(scope)` tells
|
|
239
|
-
the two kinds apart.
|
|
240
|
-
|
|
241
|
-
|
|
239
|
+
the two kinds apart. The control key holds the charset by base64url encoding; a strand
|
|
240
|
+
id holds it by check — `assertStrandScopeKey` runs on every strand launch, so a strand
|
|
241
|
+
whose row replicated in from another node with an unusable id is refused rather than
|
|
242
|
+
handed to the factory, and on `publishStrand`, so this node never writes such an id into
|
|
243
|
+
the party's control database to begin with.
|
|
242
244
|
|
|
243
245
|
Available storage implementations:
|
|
244
246
|
| Package | Environment | Description |
|
package/dist/cadre-node.d.ts
CHANGED
|
@@ -279,8 +279,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
279
279
|
* dead entry behind; recovery today is a fresh invitation.
|
|
280
280
|
*
|
|
281
281
|
* NOTE: entries are kept for the node's lifetime, including across a
|
|
282
|
-
* {@link stopStrand} — a stopped strand may be
|
|
283
|
-
*
|
|
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
|
|
284
286
|
* number of KEYS is bounded only by the strands this node has ever formed as an
|
|
285
287
|
* initiator (not by time); if a node ever forms strands at scale, evict on
|
|
286
288
|
* `unpublishStrand` or cap the map.
|
|
@@ -306,8 +308,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
306
308
|
* (`strand-membership-reconciler.ts`, wired via `StartStrandConfig.pendingMembershipInvite`
|
|
307
309
|
* in {@link launchStrand}): it deletes the entry once the invitation is redeemed, burned
|
|
308
310
|
* against an already-seated member, or found dead (expired / cancelled / consumed
|
|
309
|
-
* elsewhere / the strand sealed)
|
|
310
|
-
*
|
|
311
|
+
* elsewhere / the strand sealed) — naming the invitation it settled, so a re-formation
|
|
312
|
+
* that replaced the entry meanwhile keeps its fresh one
|
|
313
|
+
* ({@link unstageMembershipInvite}). Until the strand is actually launched here the entry
|
|
314
|
+
* just waits; once launched, staging notifies the manager, which re-arms a finished loop.
|
|
311
315
|
*
|
|
312
316
|
* NOTE: entries live for the node's lifetime (one small pair per formed closed
|
|
313
317
|
* strand), the same unbounded-keys tripwire {@link crossPartyStrandAddrs} documents —
|
|
@@ -732,6 +736,12 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
732
736
|
* derivation from it (`db-p2p` namespaces all of the node's protocol ids as
|
|
733
737
|
* `/optimystic/<networkName>/...`), so the node options and the block-transfer
|
|
734
738
|
* protocol prefix the control backfill dials can never drift apart.
|
|
739
|
+
*
|
|
740
|
+
* NOTE: the party id goes in UNENCODED here, unlike in `controlStorageScope`. Safe
|
|
741
|
+
* today because a party id is locally configured rather than replicated in, and both
|
|
742
|
+
* ends of a connection derive this string identically — an odd party id yields an odd
|
|
743
|
+
* but consistent protocol id, not a mismatch or an escaped name. If a party id ever
|
|
744
|
+
* arrives from the network, encode it here as the storage scope key already does.
|
|
735
745
|
*/
|
|
736
746
|
private controlNetworkName;
|
|
737
747
|
/**
|
|
@@ -1349,9 +1359,14 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1349
1359
|
* {@link SeedBootstrapService} this node builds — `applySeed`'s owner dials and
|
|
1350
1360
|
* `dialInvite`.
|
|
1351
1361
|
*
|
|
1352
|
-
* See
|
|
1353
|
-
* bounded as a whole, and
|
|
1354
|
-
*
|
|
1362
|
+
* See `peer-dial.ts`'s `DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS` for why a peer's dial is
|
|
1363
|
+
* bounded as a whole, and `DEFAULT_CONTROL_COHORT_PER_ADDRESS_DIAL_TIMEOUT_MS` for why each
|
|
1364
|
+
* address is bounded as well.
|
|
1365
|
+
*
|
|
1366
|
+
* Both are DERIVED from `network.linkRoundTripMs` rather than fixed, because the slowest
|
|
1367
|
+
* address either has to cover is a relayed dial and that costs a fixed number of exchanges —
|
|
1368
|
+
* `link-budget.ts` has the counts. A host's explicit `controlCohort` values still win, so a
|
|
1369
|
+
* test that drives dead addresses on purpose keeps the duration it chose.
|
|
1355
1370
|
*/
|
|
1356
1371
|
private controlDialBudget;
|
|
1357
1372
|
/**
|
|
@@ -1862,17 +1877,17 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1862
1877
|
*
|
|
1863
1878
|
* A rejected call leaves nothing running but DOES leave the sApp config
|
|
1864
1879
|
* registered, deliberately: both an explicit retry and the {@link StrandWatcher}'s
|
|
1865
|
-
* automatic relaunch need it.
|
|
1866
|
-
*
|
|
1867
|
-
*
|
|
1868
|
-
*
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
1880
|
+
* automatic relaunch need it. A failed launch here hands the strand back to that
|
|
1881
|
+
* relaunch — `StrandWatcher.forgetStrand` drops the id from the watcher's
|
|
1882
|
+
* `knownStrands` and records the backoff, so a later poll re-attempts it on the same
|
|
1883
|
+
* `pollInterval * 2^(failures-1)` ladder a watcher-driven failure gets. Because the
|
|
1884
|
+
* config stays registered, the retry takes `handleStrandAdded`'s auto-launch branch:
|
|
1885
|
+
* what the app sees is `strand:error` per failed retry and `strand:started` when one
|
|
1886
|
+
* succeeds, never a second `strand:discovered`. {@link detachStrand} (reached via
|
|
1887
|
+
* {@link stopStrand}) is what abandons a strand for good, and its stop suppresses the
|
|
1888
|
+
* strand in the watcher so this retry cannot resurrect it — a call to THIS method lifts
|
|
1889
|
+
* that suppression again, since an explicit claim is a deliberate reversal of the
|
|
1890
|
+
* deliberate stop.
|
|
1876
1891
|
*/
|
|
1877
1892
|
addStrand(config: StrandConfig): Promise<StrandInstance>;
|
|
1878
1893
|
/**
|
|
@@ -1945,7 +1960,8 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
1945
1960
|
* @returns The live `Strand` row — the one just inserted, or the matching one already
|
|
1946
1961
|
* there. A closed strand's caller should carry THIS row's `MemberPrivateKey` forward:
|
|
1947
1962
|
* on a repeat it is the stored key, not the argument.
|
|
1948
|
-
* @throws if the node is not started, exposes no owner signing key, the id is blank
|
|
1963
|
+
* @throws if the node is not started, exposes no owner signing key, the id is blank or
|
|
1964
|
+
* unusable as a storage scope key (`InvalidStrandIdError` — see `storage-scope.ts`), a
|
|
1949
1965
|
* row with the same id holds different content, or the control DB rejects the
|
|
1950
1966
|
* (unauthorized) insert.
|
|
1951
1967
|
*/
|
|
@@ -2372,8 +2388,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2372
2388
|
* caller runs the drive regardless).
|
|
2373
2389
|
*
|
|
2374
2390
|
* NOTE: against a relay that is DOWN this hook costs up to two strand-addr
|
|
2375
|
-
* timeouts (10 s each: dial by peer id, then by addr) before the
|
|
2376
|
-
* starts, so one failed re-drive
|
|
2391
|
+
* timeouts (10 s each: dial by peer id, then by addr) before the reservation drive even
|
|
2392
|
+
* starts, so one failed re-drive holds the supervisor `driving` for those 20 s plus the
|
|
2393
|
+
* drive's own deadline — 28 s at the default declared link round trip, and longer on a host
|
|
2394
|
+
* that declared a slower one (`link-budget.ts`).
|
|
2377
2395
|
* Bounded and harmless while the relay is unreachable anyway; if recovery
|
|
2378
2396
|
* latency after a relay comes back ever matters, skip the announce when the
|
|
2379
2397
|
* control node holds no connection to the relay (the drive's own dial fails
|
|
@@ -2465,11 +2483,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2465
2483
|
* Stop a strand on THIS node only: untrack it from hibernation, drop its sApp config,
|
|
2466
2484
|
* stop the local instance, and emit `strand:stopped`. The shared `Strand` row is left
|
|
2467
2485
|
* intact, so on the next node RESTART the strand is rediscovered and surfaces as
|
|
2468
|
-
* `strand:discovered` again —
|
|
2469
|
-
*
|
|
2470
|
-
*
|
|
2471
|
-
*
|
|
2472
|
-
* {@link unpublishStrand}.
|
|
2486
|
+
* `strand:discovered` again — but never again in THIS session: the stop suppresses the
|
|
2487
|
+
* id in the watcher (`StrandWatcher.suppressStrand`) and drops it from
|
|
2488
|
+
* {@link getDiscoveredStrands}, so neither a later poll nor a drain can undo a
|
|
2489
|
+
* deliberate stop. Only an explicit {@link addStrand} does, which is the caller
|
|
2490
|
+
* reversing its own decision. Party-wide removal is {@link unpublishStrand}.
|
|
2473
2491
|
*/
|
|
2474
2492
|
stopStrand(strandId: string): Promise<void>;
|
|
2475
2493
|
/**
|
|
@@ -2490,6 +2508,10 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2490
2508
|
* readings are the intended one: `handleStrandRemoved` arrives because the control row
|
|
2491
2509
|
* is gone, and an explicit {@link stopStrand} is a deliberate abandonment — neither
|
|
2492
2510
|
* strand may be re-offered to a later `getDiscoveredStrands()` drain.
|
|
2511
|
+
*
|
|
2512
|
+
* The watcher-level suppression that makes a stop permanent is deliberately NOT here,
|
|
2513
|
+
* only in {@link stopStrand}: the two callers diverge on it. A vanished control row
|
|
2514
|
+
* that reappears is a fresh strand and must be offered again.
|
|
2493
2515
|
*/
|
|
2494
2516
|
private detachStrand;
|
|
2495
2517
|
/**
|
|
@@ -2589,13 +2611,15 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
2589
2611
|
* local), and only then does it reach out. Everything above in {@link start}
|
|
2590
2612
|
* has completed by the time this runs.
|
|
2591
2613
|
*
|
|
2592
|
-
* BUDGET: the supervisor's first attempt
|
|
2593
|
-
*
|
|
2594
|
-
*
|
|
2595
|
-
*
|
|
2596
|
-
*
|
|
2597
|
-
* on links that were merely slow.
|
|
2598
|
-
*
|
|
2614
|
+
* BUDGET: the supervisor's first attempt is what `start()` waits on — deliberately the drive's
|
|
2615
|
+
* ordinary deadline rather than a boot-specific one. That deadline is now COUNTED, four link
|
|
2616
|
+
* round trips at the declared `network.linkRoundTripMs` (8 s at its default, where it was a
|
|
2617
|
+
* fixed 10 s): a healthy dial-plus-reserve is sub-second even over a WAN, so this is slack for
|
|
2618
|
+
* a slow link, while going much longer would make a dead relay indistinguishable from a hung
|
|
2619
|
+
* start and much shorter would fail nodes on links that were merely slow. A host that declares
|
|
2620
|
+
* a slower link lengthens it without touching this path — `link-budget.ts`. The retries carry
|
|
2621
|
+
* on in the background after this resolves, exactly as they do for a {@link reserveRelays}
|
|
2622
|
+
* caller.
|
|
2599
2623
|
*
|
|
2600
2624
|
* `network.requireRelay === false` softens only the outcome below: a first
|
|
2601
2625
|
* attempt that lands no `/p2p-circuit` address is logged instead of thrown, and
|
|
@@ -3044,7 +3068,11 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3044
3068
|
* an intact control DB) and mints + persists a fresh one otherwise. The invitation
|
|
3045
3069
|
* will admit THIS key's public half as the `Strand.Member`.
|
|
3046
3070
|
* 2. Stage the invitation in {@link pendingMembershipInvites} for the strand
|
|
3047
|
-
* bring-up flow (`strand-node-binds-member-peer`) to redeem via `consumeInvite
|
|
3071
|
+
* bring-up flow (`strand-node-binds-member-peer`) to redeem via `consumeInvite`,
|
|
3072
|
+
* and tell the instance manager, which re-arms an already-finished membership
|
|
3073
|
+
* reconciler so a RE-formation against a launched strand is attempted at once — the
|
|
3074
|
+
* removed-party case, where the loop finished long before the removal. A strand not
|
|
3075
|
+
* launched here yet has no loop to re-arm, and its bring-up finds the entry.
|
|
3048
3076
|
*
|
|
3049
3077
|
* Throws — failing the whole {@link formStrand} — when the identity cannot be
|
|
3050
3078
|
* persisted: a joiner "joined" without a persistable identity could never become a
|
|
@@ -3054,6 +3082,14 @@ export declare class CadreNode implements SAppIdLookup {
|
|
|
3054
3082
|
* rejected) and redeeming a FRESH invitation.
|
|
3055
3083
|
*/
|
|
3056
3084
|
private adoptFormationMembershipInvite;
|
|
3085
|
+
/**
|
|
3086
|
+
* The reconciler's half of the {@link pendingMembershipInvites} seam: drop `settled`
|
|
3087
|
+
* (spent, burned, or dead) only while it is still the staged entry. A re-formation
|
|
3088
|
+
* replaces the entry between a pass's read and its settle, and the fresh invitation it
|
|
3089
|
+
* staged is the one the re-armed loop is about to redeem — deleting it here would lose
|
|
3090
|
+
* it silently, the very outcome the re-arm exists to prevent.
|
|
3091
|
+
*/
|
|
3092
|
+
private unstageMembershipInvite;
|
|
3057
3093
|
/**
|
|
3058
3094
|
* The pending single-use membership invitation a closed-strand formation carried back
|
|
3059
3095
|
* for `strandId`, or `undefined` when none is staged — the seam the strand bring-up
|