@serfab/cadre-core 0.13.0 → 1.1.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 +20 -6
- package/dist/bootstrap-peer-store-file.js +2 -2
- package/dist/bootstrap-peer-store.d.ts +32 -12
- package/dist/bootstrap-peer-store.js +41 -15
- package/dist/bootstrap-peer-store.js.map +1 -1
- package/dist/cadre-node.d.ts +558 -80
- package/dist/cadre-node.js +1060 -170
- 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 +13 -26
- package/dist/control-cohort.js +0 -26
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +299 -44
- package/dist/control-database.js +469 -69
- package/dist/control-database.js.map +1 -1
- package/dist/control-read-retry.d.ts +40 -11
- package/dist/control-read-retry.js +48 -15
- package/dist/control-read-retry.js.map +1 -1
- package/dist/control-retry.d.ts +58 -3
- package/dist/control-retry.js +58 -3
- package/dist/control-retry.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +103 -19
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +80 -11
- package/dist/control-write-retry.js +176 -29
- package/dist/control-write-retry.js.map +1 -1
- package/dist/enrolled-machine-store.js +2 -2
- package/dist/index.d.ts +14 -7
- package/dist/index.js +33 -6
- package/dist/index.js.map +1 -1
- package/dist/node-local-snapshot.d.ts +15 -7
- package/dist/node-local-snapshot.js +23 -8
- package/dist/node-local-snapshot.js.map +1 -1
- package/dist/peer-dial.d.ts +143 -0
- package/dist/peer-dial.js +176 -0
- package/dist/peer-dial.js.map +1 -0
- package/dist/relay-addrs.d.ts +90 -52
- package/dist/relay-addrs.js +91 -59
- package/dist/relay-addrs.js.map +1 -1
- package/dist/relay-reservation.d.ts +71 -3
- package/dist/relay-reservation.js +116 -8
- package/dist/relay-reservation.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +30 -1
- package/dist/seed-bootstrap.js +62 -17
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/storage-scope.d.ts +62 -0
- package/dist/storage-scope.js +75 -0
- package/dist/storage-scope.js.map +1 -0
- package/dist/strand-database.d.ts +34 -16
- package/dist/strand-database.js +38 -24
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +152 -0
- package/dist/strand-first-sync-gate.js +208 -0
- package/dist/strand-first-sync-gate.js.map +1 -0
- package/dist/strand-formation-manager.d.ts +87 -5
- package/dist/strand-formation-manager.js +109 -5
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +21 -1
- package/dist/strand-formation-protocol.js +30 -0
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +243 -6
- package/dist/strand-instance-manager.js +470 -37
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-key.d.ts +20 -12
- package/dist/strand-member-key.js +20 -12
- package/dist/strand-member-key.js.map +1 -1
- package/dist/strand-member-registry.js +3 -0
- package/dist/strand-member-registry.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +361 -0
- package/dist/strand-membership-reconciler.js +548 -0
- package/dist/strand-membership-reconciler.js.map +1 -0
- package/dist/strand-membership-writer.d.ts +131 -11
- package/dist/strand-membership-writer.js +396 -134
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-network-config.d.ts +46 -14
- package/dist/strand-network-config.js +79 -23
- package/dist/strand-network-config.js.map +1 -1
- package/dist/strand-solicitation.d.ts +10 -1
- package/dist/strand-solicitation.js +5 -0
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-protocol.d.ts +11 -7
- package/dist/strand-wake-protocol.js +20 -52
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/strand-watcher.js +6 -0
- package/dist/strand-watcher.js.map +1 -1
- package/dist/timed-step.d.ts +12 -0
- package/dist/timed-step.js +28 -0
- package/dist/timed-step.js.map +1 -0
- package/dist/timeout-scheduler.d.ts +19 -0
- package/dist/timeout-scheduler.js +22 -0
- package/dist/timeout-scheduler.js.map +1 -0
- package/dist/types.d.ts +262 -30
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/bootstrap-peer-store-file.ts +2 -2
- package/src/bootstrap-peer-store.ts +69 -27
- package/src/cadre-node.ts +7301 -6353
- package/src/control-authorization.ts +2 -1
- package/src/control-cohort.ts +122 -130
- package/src/control-database.ts +537 -69
- package/src/control-read-retry.ts +202 -167
- package/src/control-retry.ts +297 -190
- package/src/control-schema.ts +103 -19
- package/src/control-write-retry.ts +533 -383
- package/src/enrolled-machine-store.ts +2 -2
- package/src/index.ts +83 -6
- package/src/node-local-snapshot.ts +25 -8
- package/src/peer-dial.ts +215 -0
- package/src/relay-addrs.ts +458 -436
- package/src/relay-reservation.ts +951 -828
- package/src/seed-bootstrap.ts +76 -18
- package/src/storage-scope.ts +78 -0
- package/src/strand-database.ts +50 -27
- package/src/strand-first-sync-gate.ts +258 -0
- package/src/strand-formation-manager.ts +140 -5
- package/src/strand-formation-protocol.ts +43 -1
- package/src/strand-instance-manager.ts +577 -37
- package/src/strand-member-key.ts +20 -12
- package/src/strand-member-registry.ts +3 -0
- package/src/strand-membership-reconciler.ts +680 -0
- package/src/strand-membership-writer.ts +527 -189
- package/src/strand-network-config.ts +102 -24
- package/src/strand-solicitation.ts +16 -1
- package/src/strand-wake-protocol.ts +21 -66
- package/src/strand-watcher.ts +6 -0
- package/src/timed-step.ts +28 -0
- package/src/timeout-scheduler.ts +28 -0
- package/src/types.ts +1789 -1554
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Node-local, NON-replicated
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Node-local, NON-replicated bootstrap-peer store: dial targets a node learned
|
|
3
|
+
* out of band, kept so it can dial those peers when nothing better is known.
|
|
4
|
+
* Two sources feed it:
|
|
5
5
|
*
|
|
6
|
-
* A newcomer applies a signed seed nominating the
|
|
7
|
-
* addresses they answer on.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* only
|
|
13
|
-
*
|
|
6
|
+
* - **A seed's owner peers.** A newcomer applies a signed seed nominating the
|
|
7
|
+
* party's owner machines and the addresses they answer on.
|
|
8
|
+
* `SeedBootstrapService.applySeed` dials those owners exactly once,
|
|
9
|
+
* best-effort; when that dial fails (owner briefly down, relay reservation not
|
|
10
|
+
* up, not yet vouched) the node has an empty `CadrePeer` table and no
|
|
11
|
+
* connection, and `CadreNode.reconcileControlCohort`'s cold-start branch is
|
|
12
|
+
* the only way back — it re-dials these retained addresses every pass.
|
|
13
|
+
* - **Nodes this node added.** `CadreNode.addDrone` is handed the added node's
|
|
14
|
+
* addresses, but that node's `CadrePeer` row stays unsigned, and therefore
|
|
15
|
+
* unresolvable, until the node self-publishes — which needs a connection, and
|
|
16
|
+
* a node that cannot listen (a phone) is never dialed by it. The steady-state
|
|
17
|
+
* reconcile pass falls back to these addresses for a sibling whose signed
|
|
18
|
+
* record and address-book entry both yield nothing, including after a
|
|
19
|
+
* relaunch that outlived the record's freshness window.
|
|
20
|
+
*
|
|
21
|
+
* Held only in memory, either kind dies with the process and the node is left
|
|
22
|
+
* with no address to dial, which is what this store exists to prevent.
|
|
14
23
|
*
|
|
15
24
|
* Three implementations, mirroring `trusted-owner-store.ts` (read that first —
|
|
16
25
|
* it solves the same "must outlive the process, storage differs per platform"
|
|
@@ -28,10 +37,11 @@
|
|
|
28
37
|
*
|
|
29
38
|
* **Nothing here is trust-bearing, and a loader must not try to re-verify it.**
|
|
30
39
|
* Only *dial targets* are retained — never a seed, a signature, or an authority
|
|
31
|
-
* claim.
|
|
32
|
-
* anchor before its addresses were retained, and
|
|
33
|
-
*
|
|
34
|
-
*
|
|
40
|
+
* claim. A seed was signature-checked against the node-local trusted-owner
|
|
41
|
+
* anchor before its addresses were retained, and an added node's addresses were
|
|
42
|
+
* supplied by the owner that chose to add it. Either way a dial grants no
|
|
43
|
+
* authority: `CadreNode.bootstrapDialAddrs` binds every address to the peer id it
|
|
44
|
+
* was retained under, so a dial cannot be redirected to whoever answers. What a
|
|
35
45
|
* persistent backend's loader DOES owe is dropping structurally junk entries
|
|
36
46
|
* (unparseable peer id, empty address list, non-string address) rather than
|
|
37
47
|
* carrying them into the dial loop.
|
|
@@ -42,9 +52,12 @@ import { NodeLocalSnapshot, type DurableSlot, type NodeLocalSnapshotSpec } from
|
|
|
42
52
|
|
|
43
53
|
const log = debug('sereus:cadre:bootstrap-peer-store');
|
|
44
54
|
|
|
45
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* One retained dial target learned out of band: an owner peer a seed nominated,
|
|
57
|
+
* or a node this node added.
|
|
58
|
+
*/
|
|
46
59
|
export interface BootstrapPeerEntry {
|
|
47
|
-
/** Multiaddr strings exactly as
|
|
60
|
+
/** Multiaddr strings exactly as they were handed over (parsed at dial time). */
|
|
48
61
|
addrs: string[];
|
|
49
62
|
/** Wall-clock ms the entry was last recorded (diagnostics / future eviction). */
|
|
50
63
|
recordedAt: number;
|
|
@@ -56,9 +69,9 @@ export interface BootstrapPeerStore {
|
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
71
|
* Every retained target, peerId -> entry. Every backend copies the map per call,
|
|
59
|
-
* so the result is a snapshot decoupled from later {@link record}
|
|
60
|
-
* safe to iterate while recording. The entry objects
|
|
61
|
-
* REPLACES an entry rather than mutating it in place.
|
|
72
|
+
* so the result is a snapshot decoupled from later {@link record} and
|
|
73
|
+
* {@link forget} calls and is safe to iterate while recording. The entry objects
|
|
74
|
+
* need no copy: `record` REPLACES an entry rather than mutating it in place.
|
|
62
75
|
*/
|
|
63
76
|
all(): ReadonlyMap<string, BootstrapPeerEntry>;
|
|
64
77
|
|
|
@@ -72,15 +85,26 @@ export interface BootstrapPeerStore {
|
|
|
72
85
|
* `CadreNode.recordSeedBootstrapPeers` keep its signature while a file
|
|
73
86
|
* backend persists in the background.
|
|
74
87
|
*
|
|
75
|
-
* NOTE: entries are never evicted
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
88
|
+
* NOTE: entries are never evicted (only a local `removePeer` {@link forget}s
|
|
89
|
+
* one), and a persistent backend's file therefore grows across the node's whole
|
|
90
|
+
* lifetime rather than one process. Fine while a seed nominates one or a few
|
|
91
|
+
* owners, a node adds a handful of machines, and entries are keyed by peer id;
|
|
92
|
+
* if a node ever applies seeds naming many distinct owners or adds many
|
|
93
|
+
* machines, add eviction (oldest {@link BootstrapPeerEntry.recordedAt} first, or
|
|
94
|
+
* a cap) rather than letting the file grow unbounded — `recordedAt` exists so
|
|
95
|
+
* eviction has something to sort by.
|
|
82
96
|
*/
|
|
83
97
|
record(peerId: string, addrs: readonly string[]): Promise<void>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Drop a peer's retained dial addresses — for a peer this node removed from the
|
|
101
|
+
* party, which must not stay a dial target. Forgetting a peer with no entry is a
|
|
102
|
+
* no-op.
|
|
103
|
+
*
|
|
104
|
+
* Same contract as {@link record}: the removal is reflected in {@link all}
|
|
105
|
+
* SYNCHRONOUSLY, and the returned promise tracks durability only.
|
|
106
|
+
*/
|
|
107
|
+
forget(peerId: string): Promise<void>;
|
|
84
108
|
}
|
|
85
109
|
|
|
86
110
|
/**
|
|
@@ -101,6 +125,12 @@ export class MemoryBootstrapPeerStore implements BootstrapPeerStore {
|
|
|
101
125
|
this.peers.set(peerId, { addrs: [...addrs], recordedAt: Date.now() });
|
|
102
126
|
log('bootstrap peer retained (party=%s, peer=%s, addrs=%d)', this.partyId, peerId, addrs.length);
|
|
103
127
|
}
|
|
128
|
+
|
|
129
|
+
async forget(peerId: string): Promise<void> {
|
|
130
|
+
if (this.peers.delete(peerId)) {
|
|
131
|
+
log('bootstrap peer forgotten (party=%s, peer=%s)', this.partyId, peerId);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
104
134
|
}
|
|
105
135
|
|
|
106
136
|
/**
|
|
@@ -169,4 +199,16 @@ export class PersistentBootstrapPeerStore implements BootstrapPeerStore {
|
|
|
169
199
|
log('bootstrap peer retained (party=%s, peer=%s, addrs=%d); persisting', this.partyId, peerId, addrs.length);
|
|
170
200
|
return this.snapshot.put(peerId, { addrs: [...addrs], recordedAt: Date.now() });
|
|
171
201
|
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Drop a peer's dial addresses: gone from {@link all} synchronously, then the
|
|
205
|
+
* full snapshot is persisted — unless there was no entry, which writes nothing
|
|
206
|
+
* (see `NodeLocalSnapshot.remove`).
|
|
207
|
+
*/
|
|
208
|
+
forget(peerId: string): Promise<void> {
|
|
209
|
+
if (this.snapshot.has(peerId)) {
|
|
210
|
+
log('bootstrap peer forgotten (party=%s, peer=%s); persisting', this.partyId, peerId);
|
|
211
|
+
}
|
|
212
|
+
return this.snapshot.remove(peerId);
|
|
213
|
+
}
|
|
172
214
|
}
|