@serfab/cadre-core 1.7.0 → 1.9.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 +8 -6
- package/dist/cadre-node.d.ts +527 -206
- package/dist/cadre-node.js +1084 -528
- 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 +6 -0
- package/dist/control-cohort.js +6 -0
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +46 -8
- package/dist/control-database.js +97 -18
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +37 -14
- package/dist/control-formation-recorder.js +60 -10
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-read-retry.d.ts +13 -12
- package/dist/control-read-retry.js +14 -12
- package/dist/control-read-retry.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +67 -5
- package/dist/control-schema.js.map +1 -1
- package/dist/control-stream.d.ts +9 -1
- package/dist/control-stream.js +24 -1
- package/dist/control-stream.js.map +1 -1
- package/dist/control-write-retry.d.ts +12 -2
- package/dist/control-write-retry.js +13 -2
- package/dist/control-write-retry.js.map +1 -1
- package/dist/delegate-admission.d.ts +11 -8
- package/dist/delegate-admission.js +19 -11
- package/dist/delegate-admission.js.map +1 -1
- package/dist/diagnostics/connection-path.d.ts +0 -7
- package/dist/diagnostics/connection-path.js +0 -7
- package/dist/diagnostics/connection-path.js.map +1 -1
- package/dist/formation-approval.d.ts +7 -0
- package/dist/formation-approval.js +9 -3
- package/dist/formation-approval.js.map +1 -1
- package/dist/fs-atomic.d.ts +11 -2
- package/dist/fs-atomic.js +13 -3
- package/dist/fs-atomic.js.map +1 -1
- package/dist/hibernation-manager.d.ts +111 -8
- package/dist/hibernation-manager.js +234 -49
- package/dist/hibernation-manager.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +25 -20
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +90 -25
- package/dist/joined-strand-store.js +223 -55
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store-file.js +14 -5
- package/dist/key-store-file.js.map +1 -1
- package/dist/link-budget.d.ts +367 -69
- package/dist/link-budget.js +375 -72
- package/dist/link-budget.js.map +1 -1
- package/dist/membership-connection-gater.d.ts +30 -43
- package/dist/membership-connection-gater.js +31 -42
- package/dist/membership-connection-gater.js.map +1 -1
- 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 +24 -4
- package/dist/peer-dial.js +74 -5
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +2 -10
- package/dist/peer-join-backfill.js +8 -8
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/push-fanout.d.ts +6 -0
- package/dist/push-fanout.js +6 -0
- package/dist/push-fanout.js.map +1 -1
- package/dist/relay-reservation.d.ts +3 -1
- package/dist/relay-reservation.js +3 -1
- package/dist/relay-reservation.js.map +1 -1
- package/dist/relay-server.d.ts +79 -0
- package/dist/relay-server.js +74 -0
- package/dist/relay-server.js.map +1 -0
- package/dist/seed-bootstrap.d.ts +57 -4
- package/dist/seed-bootstrap.js +107 -83
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/storage-scope.d.ts +33 -17
- package/dist/storage-scope.js +44 -23
- package/dist/storage-scope.js.map +1 -1
- package/dist/strand-addr-protocol.d.ts +58 -21
- package/dist/strand-addr-protocol.js +133 -85
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-database.d.ts +20 -2
- package/dist/strand-database.js +42 -5
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +59 -21
- package/dist/strand-first-sync-gate.js +58 -19
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-deadlines.d.ts +151 -0
- package/dist/strand-formation-deadlines.js +171 -0
- package/dist/strand-formation-deadlines.js.map +1 -0
- package/dist/strand-formation-manager.d.ts +63 -30
- package/dist/strand-formation-manager.js +67 -41
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +45 -46
- package/dist/strand-formation-protocol.js +62 -126
- package/dist/strand-formation-protocol.js.map +1 -1
- 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 +122 -44
- package/dist/strand-instance-manager.js +270 -114
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +6 -0
- package/dist/strand-membership-writer.js +11 -0
- package/dist/strand-membership-writer.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-revocation-enforcer.js +2 -1
- package/dist/strand-revocation-enforcer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +36 -20
- package/dist/strand-solicitation.js +4 -4
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-protocol.d.ts +80 -23
- package/dist/strand-wake-protocol.js +89 -64
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/types.d.ts +148 -61
- package/dist/types.js +4 -3
- package/dist/types.js.map +1 -1
- package/package.json +11 -10
- package/src/cadre-node.ts +8400 -7776
- package/src/control-authorization.ts +2 -1
- package/src/control-cohort.ts +6 -0
- package/src/control-database.ts +122 -18
- package/src/control-formation-recorder.ts +354 -305
- package/src/control-read-retry.ts +14 -12
- package/src/control-schema.ts +67 -5
- package/src/control-stream.ts +25 -1
- package/src/control-write-retry.ts +13 -2
- package/src/delegate-admission.ts +23 -13
- package/src/diagnostics/connection-path.ts +0 -7
- package/src/formation-approval.ts +610 -604
- package/src/fs-atomic.ts +14 -4
- package/src/hibernation-manager.ts +638 -437
- package/src/index.ts +43 -65
- package/src/joined-strand-store.ts +247 -57
- package/src/key-store-file.ts +14 -5
- package/src/link-budget.ts +393 -74
- package/src/membership-connection-gater.ts +31 -45
- package/src/node-local-snapshot.ts +12 -7
- package/src/peer-dial.ts +81 -7
- package/src/peer-join-backfill.ts +10 -9
- package/src/push-fanout.ts +6 -0
- package/src/relay-reservation.ts +3 -1
- package/src/relay-server.ts +98 -0
- package/src/seed-bootstrap.ts +133 -91
- package/src/storage-scope.ts +44 -23
- package/src/strand-addr-protocol.ts +547 -458
- package/src/strand-database.ts +287 -242
- package/src/strand-first-sync-gate.ts +58 -19
- package/src/strand-formation-deadlines.ts +227 -0
- package/src/strand-formation-manager.ts +700 -647
- package/src/strand-formation-protocol.ts +106 -154
- package/src/strand-fret-addrs.ts +145 -0
- package/src/strand-instance-manager.ts +307 -140
- package/src/strand-membership-writer.ts +12 -0
- package/src/strand-network-state-file.ts +40 -0
- package/src/strand-network-state.ts +243 -0
- package/src/strand-revocation-enforcer.ts +2 -1
- package/src/strand-solicitation.ts +519 -500
- package/src/strand-wake-protocol.ts +401 -355
- package/src/types.ts +150 -61
- 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 -159
- package/dist/strand-peer-book-protocol.js +0 -360
- 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 -354
- 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 -463
- package/src/strand-peer-book-swap.ts +0 -338
- package/src/strand-peer-book.ts +0 -468
- package/src/strand-peer-observer.ts +0 -235
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the signed address records a running strand node's FRET routing table holds,
|
|
3
|
+
* as per-peer addresses ready for that node's own address book (`peer-addr-book.ts`).
|
|
4
|
+
*
|
|
5
|
+
* Why a strand node needs this. libp2p's peerStore hides every address one hour after
|
|
6
|
+
* it was first observed (the `NOTE:` on `mergePeerAddrs`), and FRET does not re-apply
|
|
7
|
+
* the records it holds: it hands a record to the peerStore when a neighbour's snapshot
|
|
8
|
+
* delivers it or a saved table is imported, and the peerStore refuses a record whose
|
|
9
|
+
* sequence number it already has. So a strand node that has been up for more than an
|
|
10
|
+
* hour would have no address for a peer whose connection then drops, although FRET
|
|
11
|
+
* still holds that peer's record. `CadreNode.refreshStrandPeerAddrs` re-merges the
|
|
12
|
+
* records on every pass, which is what keeps another party's strand nodes dialable;
|
|
13
|
+
* own-party siblings are re-resolved separately, over the strand-addr RPC.
|
|
14
|
+
*
|
|
15
|
+
* How long a record is available here is FRET's rule, not this module's: while FRET
|
|
16
|
+
* holds the entry, and at most 14 days after the record was last confirmed (a peer
|
|
17
|
+
* connected at export time counts as confirmed then).
|
|
18
|
+
*
|
|
19
|
+
* Every record is opened and verified here rather than taken on FRET's word. A record
|
|
20
|
+
* is self-certifying, the table is reached through a structural type rather than an
|
|
21
|
+
* interface this package depends on, and the address book write is attributed from what
|
|
22
|
+
* the record proves, not from the id the table filed it under.
|
|
23
|
+
*/
|
|
24
|
+
import debug from 'debug';
|
|
25
|
+
import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record';
|
|
26
|
+
import { peerIdFromPublicKey } from '@libp2p/peer-id';
|
|
27
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
28
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays';
|
|
29
|
+
import { withTrailingPeerId } from './peer-record.js';
|
|
30
|
+
const log = debug('sereus:cadre:strand-fret-addrs');
|
|
31
|
+
/**
|
|
32
|
+
* The addresses of every peer `host`'s FRET table holds a usable signed record for,
|
|
33
|
+
* `host` itself excluded. A node with no FRET service (a db-p2p build without it, a
|
|
34
|
+
* test double) reads as an empty table. One bad record never costs the others: it is
|
|
35
|
+
* counted in `rejected` and skipped.
|
|
36
|
+
*
|
|
37
|
+
* Throws only what `exportTable()` throws, which a caller treats like any other
|
|
38
|
+
* failure of a pass over a node that may be mid-teardown.
|
|
39
|
+
*/
|
|
40
|
+
export async function strandFretPeerAddrs(host) {
|
|
41
|
+
const result = { peers: new Map(), rejected: 0 };
|
|
42
|
+
const fret = host.services?.fret;
|
|
43
|
+
if (!isFretTableSource(fret)) {
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
const selfId = host.peerId.toString();
|
|
47
|
+
for (const entry of fret.exportTable().entries) {
|
|
48
|
+
if (entry.id === selfId || entry.addressRecord === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const addrs = await verifiedRecordAddrs(entry.id, entry.addressRecord.envelope);
|
|
52
|
+
if (addrs === null) {
|
|
53
|
+
result.rejected++;
|
|
54
|
+
}
|
|
55
|
+
else if (addrs.length > 0) {
|
|
56
|
+
result.peers.set(entry.id, addrs);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
function isFretTableSource(service) {
|
|
62
|
+
return typeof service === 'object' && service !== null
|
|
63
|
+
&& typeof service.exportTable === 'function';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The addresses one record lists, bound to `peerId`; null when the record must not be
|
|
67
|
+
* used. `openAndCertify` proves only that the envelope's own key signed it, so the
|
|
68
|
+
* signer and the peer the payload describes are each held against `peerId` here:
|
|
69
|
+
* without that, any peer could sign a record rewriting another peer's addresses.
|
|
70
|
+
*/
|
|
71
|
+
async function verifiedRecordAddrs(peerId, envelope) {
|
|
72
|
+
try {
|
|
73
|
+
const opened = await RecordEnvelope.openAndCertify(uint8ArrayFromString(envelope, 'base64url'), PeerRecord.DOMAIN);
|
|
74
|
+
const record = PeerRecord.createFromProtobuf(opened.payload);
|
|
75
|
+
const signer = peerIdFromPublicKey(opened.publicKey).toString();
|
|
76
|
+
const subject = record.peerId.toString();
|
|
77
|
+
if (signer !== peerId || subject !== peerId) {
|
|
78
|
+
log('skipping the address record filed under %s: signed by %s about %s', peerId, signer, subject);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return bindToPeer(record.multiaddrs.map((addr) => addr.toString()), peerId);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
log('skipping the address record filed under %s: %o', peerId, error);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A record names its peer once, in `peerId`, so its addresses carry no trailing
|
|
90
|
+
* `/p2p/<peerId>` and a relay-only peer's circuit address ends at the relay hop
|
|
91
|
+
* (`…/p2p/<relay>/p2p-circuit`). Each is given the suffix that makes it a complete
|
|
92
|
+
* dial target; one already terminating in a different peer id does not reach this peer
|
|
93
|
+
* and is dropped.
|
|
94
|
+
*
|
|
95
|
+
* Takes strings because `@libp2p/peer-record` carries its own `@multiformats/multiaddr`
|
|
96
|
+
* copy, a structurally different type from the one `withTrailingPeerId` takes.
|
|
97
|
+
*/
|
|
98
|
+
function bindToPeer(addrs, peerId) {
|
|
99
|
+
const bound = [];
|
|
100
|
+
for (const addr of addrs) {
|
|
101
|
+
const withPeer = withTrailingPeerId(multiaddr(addr), peerId);
|
|
102
|
+
if (withPeer !== null) {
|
|
103
|
+
bound.push(withPeer);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return bound;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=strand-fret-addrs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strand-fret-addrs.js","sourceRoot":"","sources":["../src/strand-fret-addrs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PrivateKey } from '@libp2p/interface';
|
|
2
2
|
import { type PeerJoinBackfillConfig } from './peer-join-backfill.js';
|
|
3
|
-
import { type
|
|
4
|
-
import type { StrandPeerBookStore } from './strand-peer-book.js';
|
|
3
|
+
import { type StrandNetworkStateStore } from './strand-network-state.js';
|
|
5
4
|
import { type StrandRevocationEnforcementConfig } from './strand-revocation-enforcer.js';
|
|
6
5
|
import { type PendingMembershipInviteSource, type StrandMembershipReconciliationConfig } from './strand-membership-reconciler.js';
|
|
7
6
|
import { type StrandFirstSyncConfig } from './strand-first-sync-gate.js';
|
|
@@ -34,8 +33,15 @@ export declare function liveStrandStatus(instance: StrandInstance): 'active' | '
|
|
|
34
33
|
*/
|
|
35
34
|
export interface StartStrandConfig {
|
|
36
35
|
strandRow: StrandRow;
|
|
37
|
-
/**
|
|
38
|
-
|
|
36
|
+
/**
|
|
37
|
+
* sApp configuration provided by the hosting application. Absent for a **storage
|
|
38
|
+
* replica** — a strand this node stores and serves without the app installed
|
|
39
|
+
* (`CadreNodeConfig.hostUnclaimedStrands`): no schema signature check, no `App`
|
|
40
|
+
* schema, no `sAppInfo` on the instance, and the default latency hint. A replica is
|
|
41
|
+
* always a joiner; `StrandDatabase` refuses to found one. An app that later claims the
|
|
42
|
+
* strand upgrades the running replica in place ({@link StrandInstanceManager.attachSApp}).
|
|
43
|
+
*/
|
|
44
|
+
sAppConfig?: SAppConfig;
|
|
39
45
|
storage?: StorageConfig;
|
|
40
46
|
network?: NetworkConfig;
|
|
41
47
|
profile: NodeProfile;
|
|
@@ -203,25 +209,14 @@ export interface StartStrandConfig {
|
|
|
203
209
|
*/
|
|
204
210
|
announceDelegateToRelay?: (strandId: string, relayAddr: string, delegatePeerId: string) => Promise<void>;
|
|
205
211
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
*/
|
|
215
|
-
onStrandPeerIdentified?: (strandId: string, observation: StrandPeerObservation) => void;
|
|
216
|
-
/**
|
|
217
|
-
* The node-local strand peer book the book SWAP reads and writes
|
|
218
|
-
* (`strand-peer-book-swap.ts`): the strand node signs its own addresses with
|
|
219
|
-
* {@link privateKey}, exchanges signed entries with every strand peer it identifies,
|
|
220
|
-
* and files what verifies. Absent ⇒ no swap runs — a peer that dials this node's
|
|
221
|
-
* swap handler gets no answer. `CadreNode` passes its book store. Retained with the
|
|
222
|
-
* launch config, so a hibernation wake re-arms the swap on the rebuilt node.
|
|
223
|
-
*/
|
|
224
|
-
strandPeerBook?: StrandPeerBookStore;
|
|
212
|
+
* The node-local strand network state (`strand-network-state.ts`): this strand's
|
|
213
|
+
* slice of it is handed to db-p2p as `persistence`, so the strand node saves its
|
|
214
|
+
* FRET routing table (with each peer's signed address record) on every connection
|
|
215
|
+
* and re-imports it when it is next built. Absent ⇒ nothing is saved and the node
|
|
216
|
+
* starts with an empty table. `CadreNode` passes its store. Retained with the launch
|
|
217
|
+
* config, so a hibernation wake rebuilds the node over the same state.
|
|
218
|
+
*/
|
|
219
|
+
networkState?: StrandNetworkStateStore;
|
|
225
220
|
}
|
|
226
221
|
/**
|
|
227
222
|
* Volatile inputs re-resolved when resuming a quiesced strand — the ones that can
|
|
@@ -281,23 +276,6 @@ export declare class StrandInstanceManager {
|
|
|
281
276
|
* missed writes).
|
|
282
277
|
*/
|
|
283
278
|
private backfills;
|
|
284
|
-
/**
|
|
285
|
-
* The per-strand peer-book observation writer (`strand-peer-observer.ts`), keyed
|
|
286
|
-
* by strand id. Same lifecycle rationale as {@link backfills}: started in
|
|
287
|
-
* `buildStrandRuntime` right after the libp2p node exists, stopped and dropped in
|
|
288
|
-
* `releaseRuntime`, so quiesce → resume re-arms it on the rebuilt node. Only
|
|
289
|
-
* present when the launch config supplied `onStrandPeerIdentified`.
|
|
290
|
-
*/
|
|
291
|
-
private peerObservers;
|
|
292
|
-
/**
|
|
293
|
-
* Per-strand strand peer book SWAP driver ({@link StrandPeerBookSwap}) — the signed
|
|
294
|
-
* exchange of book entries between strand peers. Same lifetime as the peer-book
|
|
295
|
-
* observer above: armed in `buildStrandRuntime` right after the libp2p node exists
|
|
296
|
-
* (its protocol handler must be registered before an early peer dials it), stopped
|
|
297
|
-
* and dropped in `releaseRuntime`. Only present when the launch config supplied
|
|
298
|
-
* `strandPeerBook`.
|
|
299
|
-
*/
|
|
300
|
-
private peerBookSwaps;
|
|
301
279
|
/**
|
|
302
280
|
* The per-strand revoked-peer enforcer (closed strands only), keyed by strand
|
|
303
281
|
* id. Same lifecycle rationale as {@link backfills}: created in
|
|
@@ -364,6 +342,23 @@ export declare class StrandInstanceManager {
|
|
|
364
342
|
* wake becomes the better trade.
|
|
365
343
|
*/
|
|
366
344
|
private strandStorages;
|
|
345
|
+
/**
|
|
346
|
+
* The runtime build in flight per strand id (`buildStrandRuntime`, from `startStrand` or
|
|
347
|
+
* `resumeStrand`), present until it settles. The instance is tracked for the whole build,
|
|
348
|
+
* with its database not yet constructed or not yet initialized, so a caller that must act
|
|
349
|
+
* on the FINISHED runtime ({@link attachSApp}, {@link whenRuntimeBuilt}) waits on this instead. A failed build's
|
|
350
|
+
* rejection belongs to the call that started it.
|
|
351
|
+
*/
|
|
352
|
+
private runtimeBuilds;
|
|
353
|
+
/**
|
|
354
|
+
* The latest resume or quiesce requested per strand id, present until it settles. Each one
|
|
355
|
+
* starts only once the one requested before it has settled, so a wake that lands during a
|
|
356
|
+
* quiesce rebuilds after it, and a quiesce requested during a rebuild releases what that
|
|
357
|
+
* rebuild finished. The WHOLE operation, not its entry in {@link runtimeBuilds}: that settles
|
|
358
|
+
* before a resume's own catch records `'error'`, so a joiner awaiting it could read a stale
|
|
359
|
+
* status.
|
|
360
|
+
*/
|
|
361
|
+
private transitions;
|
|
367
362
|
private stopping;
|
|
368
363
|
constructor();
|
|
369
364
|
/**
|
|
@@ -395,6 +390,18 @@ export declare class StrandInstanceManager {
|
|
|
395
390
|
* hibernation wake never re-enters the embedder's provider.
|
|
396
391
|
*/
|
|
397
392
|
startStrand(config: StartStrandConfig): Promise<StrandInstance>;
|
|
393
|
+
/** Hold `build` in {@link runtimeBuilds} until it settles, and settle as it does. */
|
|
394
|
+
private trackRuntimeBuild;
|
|
395
|
+
/**
|
|
396
|
+
* Wait until no runtime build of `strandId` is in flight. Never rejects: a failed build
|
|
397
|
+
* is reported by the call that started it, and the caller re-reads the instance after.
|
|
398
|
+
*
|
|
399
|
+
* NOTE: after a failed launch the re-read sees the instance gone only because
|
|
400
|
+
* `startStrand`'s catch deletes it synchronously, and its continuation is queued before
|
|
401
|
+
* this waiter's. If that cleanup ever awaits before `instances.delete`, a waiter can act
|
|
402
|
+
* on the dying record; move the cleanup inside the tracked promise then.
|
|
403
|
+
*/
|
|
404
|
+
private settleRuntimeBuilds;
|
|
398
405
|
/**
|
|
399
406
|
* Build (or rebuild) the libp2p node + StrandDatabase for an instance and
|
|
400
407
|
* attach them, transitioning it to `active`. Shared by `startStrand` (fresh
|
|
@@ -509,11 +516,26 @@ export declare class StrandInstanceManager {
|
|
|
509
516
|
* Quiesce a strand: release its strand-network resources (stop the libp2p node,
|
|
510
517
|
* close the StrandDatabase) while RETAINING the instance record — identity,
|
|
511
518
|
* sAppInfo, keys, latency hint, metadata — and its launch config so it can be
|
|
512
|
-
* resumed later
|
|
513
|
-
* deletion.
|
|
514
|
-
*
|
|
519
|
+
* resumed later, then mark it `hibernating`. Mechanically this is `stopStrand` minus
|
|
520
|
+
* the instance/config deletion. A tracked strand with no runtime left (a failed
|
|
521
|
+
* rebuild already released it) is only marked; an untracked one is left alone.
|
|
522
|
+
*
|
|
523
|
+
* Ordered with {@link resumeStrand} (see {@link transitions}): it starts once the resume
|
|
524
|
+
* or launch build before it has settled, so it releases a finished runtime, and the
|
|
525
|
+
* status write is its last step, so a resume requested meanwhile writes after it. A call
|
|
526
|
+
* made while another quiesce is the latest request joins it. A failed release leaves the
|
|
527
|
+
* status as it was and rejects.
|
|
515
528
|
*/
|
|
516
529
|
quiesceStrand(strandId: string): Promise<void>;
|
|
530
|
+
/** Body of {@link quiesceStrand}. */
|
|
531
|
+
private runQuiesce;
|
|
532
|
+
/**
|
|
533
|
+
* Whether the latest runtime transition requested for `strandId` is a quiesce that has
|
|
534
|
+
* not finished. Its handles may still be attached and its status still live, but it is on
|
|
535
|
+
* its way to `hibernating`, so a caller that needs it up must {@link resumeStrand} it — the
|
|
536
|
+
* resume runs after the quiesce — rather than treat it as live.
|
|
537
|
+
*/
|
|
538
|
+
isQuiescing(strandId: string): boolean;
|
|
517
539
|
/**
|
|
518
540
|
* Resume a previously-quiesced strand: rebuild its libp2p node + StrandDatabase
|
|
519
541
|
* from the retained launch config and re-attach them, transitioning it back to
|
|
@@ -521,8 +543,22 @@ export declare class StrandInstanceManager {
|
|
|
521
543
|
* launch (the cohort `bootstrapNodes` seed and the strand's `servingMachines`
|
|
522
544
|
* count) and updates the retained config so a later resume reuses the latest
|
|
523
545
|
* values. Returns the live instance unchanged if it is already running.
|
|
546
|
+
*
|
|
547
|
+
* Overlapping calls share one rebuild: a call made while a resume is the latest request
|
|
548
|
+
* for the strand — a wake landing during a check-in — joins it and settles exactly as it
|
|
549
|
+
* does, `'error'` status included. The joiner's own `overrides` are ignored; the first
|
|
550
|
+
* resume's seed wins, and both callers resolved the cohort seed moments apart. A call made
|
|
551
|
+
* while a quiesce is the latest request runs after that quiesce and rebuilds (see
|
|
552
|
+
* {@link transitions}), and one made while `startStrand` is still building waits for that
|
|
553
|
+
* build rather than starting a second.
|
|
524
554
|
*/
|
|
525
555
|
resumeStrand(strandId: string, overrides?: ResumeStrandOverrides): Promise<StrandInstance>;
|
|
556
|
+
/** Record `transition` as the latest for `strandId` until it settles. */
|
|
557
|
+
private holdTransition;
|
|
558
|
+
/** Wait for the transition requested before this one. Never rejects: its failure belongs to its caller. */
|
|
559
|
+
private settleTransition;
|
|
560
|
+
/** Body of {@link resumeStrand}; at most one runs per strand at a time. */
|
|
561
|
+
private runResume;
|
|
526
562
|
/**
|
|
527
563
|
* Honor a founder request against an ALREADY-TRACKED strand — the seam that
|
|
528
564
|
* closes the "whoever launches first decides whether the bootstrap runs" gap:
|
|
@@ -539,7 +575,8 @@ export declare class StrandInstanceManager {
|
|
|
539
575
|
* - `'already-founder'` — the retained config already founds; nothing to do.
|
|
540
576
|
* - `'bootstrapped'` — config flipped and the live database ran the bootstrap.
|
|
541
577
|
* - `'needs-resume'` — config flipped, but the instance is quiesced (no live
|
|
542
|
-
* database)
|
|
578
|
+
* database) or being quiesced (its database is closing), so the bootstrap could
|
|
579
|
+
* not run here: the CALLER must wake the
|
|
543
580
|
* strand (`CadreNode.wakeStrand`, which owns the hibernation bookkeeping this
|
|
544
581
|
* manager does not) so the rebuild — which now founds — runs it.
|
|
545
582
|
* @param resolvePartyKey - Asked for the party's own membership key when (and only
|
|
@@ -555,6 +592,39 @@ export declare class StrandInstanceManager {
|
|
|
555
592
|
* whose `'needs-resume'` wake fails owes the same withdrawal.
|
|
556
593
|
*/
|
|
557
594
|
foundExistingStrand(strandId: string, resolvePartyKey?: () => Promise<string | undefined>): Promise<'already-founder' | 'bootstrapped' | 'needs-resume'>;
|
|
595
|
+
/**
|
|
596
|
+
* Give a tracked storage replica ({@link StartStrandConfig.sAppConfig} absent) the app's
|
|
597
|
+
* schema in place — the seam for an app on this machine claiming a strand this node was
|
|
598
|
+
* already hosting. No runtime rebuild: the libp2p node, its peer id and connections, the
|
|
599
|
+
* store and its warm cache all stay, and the new `App` tables read the blocks the replica
|
|
600
|
+
* already holds. Callers attach BEFORE {@link foundExistingStrand}: the founder bootstrap
|
|
601
|
+
* writes the sApp into `Strand.Header` and refuses a database that has none.
|
|
602
|
+
*
|
|
603
|
+
* A runtime build in flight (the replica's launch, or a hibernation wake) is waited out
|
|
604
|
+
* first, so the attach acts on the database that build produced. Then, in order: the
|
|
605
|
+
* schema signature is checked before anything changes; the retained launch config takes
|
|
606
|
+
* the sApp, so every later rebuild applies it through `composeStrand`; the live database —
|
|
607
|
+
* published, or still held by the first-sync gate — gets the schema; and only then does
|
|
608
|
+
* the instance record `sAppInfo` and the sApp's latency hint. A quiesced instance gets the
|
|
609
|
+
* config alone, and its next resume applies the schema.
|
|
610
|
+
*
|
|
611
|
+
* @returns `'already-attached'` when the instance already runs an sApp — a DIFFERENT one
|
|
612
|
+
* is logged and left as it is, as a second claim of a claimed strand always has been —
|
|
613
|
+
* else `'attached'`.
|
|
614
|
+
* @throws when the strand is not tracked (a caller bug, or a launch that failed while
|
|
615
|
+
* this waited on it); when the schema signature is refused, having changed nothing; and
|
|
616
|
+
* whatever the live apply throws (e.g. a quiesce closed the database mid-apply) — the
|
|
617
|
+
* retained config then still carries the sApp and `sAppInfo` stays unset, so the next
|
|
618
|
+
* claim retries the apply.
|
|
619
|
+
*
|
|
620
|
+
* NOTE: two claims of one replica racing each other both pass the `sAppInfo` check and
|
|
621
|
+
* apply concurrently; the loser of the declarative diff can reject, and its `addStrand`
|
|
622
|
+
* retry then resolves `'already-attached'`. Needs an app calling `addStrand` twice at once
|
|
623
|
+
* (or beside a watcher retry); if it is ever seen, chain attaches per strand id.
|
|
624
|
+
*/
|
|
625
|
+
attachSApp(strandId: string, sAppConfig: SAppConfig, options?: {
|
|
626
|
+
requireSignedSchemas?: boolean;
|
|
627
|
+
}): Promise<'attached' | 'already-attached'>;
|
|
558
628
|
/**
|
|
559
629
|
* Whether `strandId` is launched but still waiting for its first sync — a joiner whose
|
|
560
630
|
* runtime is up while its database is withheld (status `'syncing'`, or `'idle'` after
|
|
@@ -575,6 +645,14 @@ export declare class StrandInstanceManager {
|
|
|
575
645
|
whenWritable(strandId: string, options?: {
|
|
576
646
|
timeoutMs?: number;
|
|
577
647
|
}): Promise<StrandInstance>;
|
|
648
|
+
/**
|
|
649
|
+
* The tracked instance once no runtime build of it is in flight, or `undefined` when none
|
|
650
|
+
* is tracked by then — never launched, or the launch waited on failed and dropped its
|
|
651
|
+
* record. For a caller about to hand a tracked instance to an app: until its build settles
|
|
652
|
+
* the instance is `'starting'` with no database, and a failed launch leaves no instance.
|
|
653
|
+
* Never rejects; a failed build is reported by the call that started it.
|
|
654
|
+
*/
|
|
655
|
+
whenRuntimeBuilt(strandId: string): Promise<StrandInstance | undefined>;
|
|
578
656
|
/**
|
|
579
657
|
* Hand a launch's database to the app: set `instance.database`, retire the gate that
|
|
580
658
|
* held it, release every {@link whenWritable} waiter, and — when the launch had already
|