@serfab/cadre-core 1.14.0 → 1.16.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 +293 -274
- package/dist/cadre-invite-protocol.d.ts +64 -29
- package/dist/cadre-invite-protocol.js +207 -38
- package/dist/cadre-invite-protocol.js.map +1 -1
- package/dist/cadre-join-request.d.ts +42 -0
- package/dist/cadre-join-request.js +144 -0
- package/dist/cadre-join-request.js.map +1 -0
- package/dist/cadre-node.d.ts +375 -79
- package/dist/cadre-node.js +758 -186
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-database.d.ts +92 -12
- package/dist/control-database.js +323 -142
- package/dist/control-database.js.map +1 -1
- package/dist/control-schema.d.ts +1 -1
- package/dist/control-schema.js +19 -3
- package/dist/control-schema.js.map +1 -1
- package/dist/ed25519-key.d.ts +7 -9
- package/dist/ed25519-key.js +20 -10
- package/dist/ed25519-key.js.map +1 -1
- package/dist/fetch-impl.d.ts +12 -0
- package/dist/fetch-impl.js +23 -0
- package/dist/fetch-impl.js.map +1 -0
- package/dist/file-durable-slot.js +2 -1
- package/dist/file-durable-slot.js.map +1 -1
- package/dist/file-safe-name.d.ts +25 -0
- package/dist/file-safe-name.js +29 -0
- package/dist/file-safe-name.js.map +1 -0
- package/dist/formation-approval.js +5 -11
- package/dist/formation-approval.js.map +1 -1
- package/dist/fs-atomic.d.ts +0 -19
- package/dist/fs-atomic.js +3 -24
- package/dist/fs-atomic.js.map +1 -1
- package/dist/index.d.ts +12 -5
- package/dist/index.js +31 -6
- package/dist/index.js.map +1 -1
- package/dist/invitation-bootstrap.d.ts +50 -12
- package/dist/invitation-bootstrap.js +76 -13
- package/dist/invitation-bootstrap.js.map +1 -1
- package/dist/joined-strand-store.d.ts +7 -0
- package/dist/joined-strand-store.js +9 -0
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store-file.js +2 -1
- package/dist/key-store-file.js.map +1 -1
- package/dist/link-budget.d.ts +9 -4
- package/dist/link-budget.js +9 -4
- package/dist/link-budget.js.map +1 -1
- package/dist/machine-removal.d.ts +78 -0
- package/dist/machine-removal.js +166 -0
- package/dist/machine-removal.js.map +1 -0
- package/dist/membership-connection-gater.d.ts +6 -5
- package/dist/membership-connection-gater.js +6 -5
- package/dist/membership-connection-gater.js.map +1 -1
- package/dist/node-claim-payload.d.ts +55 -0
- package/dist/node-claim-payload.js +108 -4
- package/dist/node-claim-payload.js.map +1 -1
- package/dist/node-default-transports.d.ts +27 -0
- package/dist/node-default-transports.js +35 -0
- package/dist/node-default-transports.js.map +1 -0
- package/dist/node-transports.d.ts +30 -0
- package/dist/node-transports.js +40 -0
- package/dist/node-transports.js.map +1 -0
- package/dist/peer-dial.d.ts +124 -27
- package/dist/peer-dial.js +254 -30
- package/dist/peer-dial.js.map +1 -1
- package/dist/peer-join-backfill.js +6 -0
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/peer-record.d.ts +6 -45
- package/dist/peer-record.js +8 -50
- package/dist/peer-record.js.map +1 -1
- package/dist/primary-lan-address.d.ts +8 -0
- package/dist/primary-lan-address.js +46 -0
- package/dist/primary-lan-address.js.map +1 -0
- package/dist/provider/client.d.ts +131 -0
- package/dist/provider/client.js +226 -0
- package/dist/provider/client.js.map +1 -0
- package/dist/provider/descriptor.d.ts +41 -0
- package/dist/provider/descriptor.js +103 -0
- package/dist/provider/descriptor.js.map +1 -0
- package/dist/provider/index.d.ts +9 -0
- package/dist/provider/index.js +10 -0
- package/dist/provider/index.js.map +1 -0
- package/dist/provider/oauth.d.ts +125 -0
- package/dist/provider/oauth.js +199 -0
- package/dist/provider/oauth.js.map +1 -0
- package/dist/provider/rent-node.d.ts +101 -0
- package/dist/provider/rent-node.js +220 -0
- package/dist/provider/rent-node.js.map +1 -0
- package/dist/relay-addrs.d.ts +9 -4
- package/dist/relay-addrs.js +9 -4
- package/dist/relay-addrs.js.map +1 -1
- package/dist/relay-reservation.d.ts +51 -16
- package/dist/relay-reservation.js +107 -24
- package/dist/relay-reservation.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +22 -5
- package/dist/seed-bootstrap.js +48 -25
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-commit-durability.d.ts +54 -0
- package/dist/strand-commit-durability.js +74 -0
- package/dist/strand-commit-durability.js.map +1 -0
- package/dist/strand-database.d.ts +23 -8
- package/dist/strand-database.js +41 -13
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +7 -1
- package/dist/strand-first-sync-gate.js +7 -1
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-protocol.js +4 -1
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-fret-addrs.d.ts +19 -1
- package/dist/strand-fret-addrs.js +27 -9
- package/dist/strand-fret-addrs.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +81 -19
- package/dist/strand-instance-manager.js +216 -105
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-move.d.ts +124 -0
- package/dist/strand-move.js +438 -0
- package/dist/strand-move.js.map +1 -0
- package/dist/strand-network-config.js +7 -6
- package/dist/strand-network-config.js.map +1 -1
- package/dist/strand-peer-redial.d.ts +113 -0
- package/dist/strand-peer-redial.js +236 -0
- package/dist/strand-peer-redial.js.map +1 -0
- package/dist/strand-wake-protocol.js +10 -7
- package/dist/strand-wake-protocol.js.map +1 -1
- package/dist/types.d.ts +212 -4
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -1
- package/package.json +18 -10
- package/src/cadre-invite-protocol.ts +1052 -864
- package/src/cadre-join-request.ts +167 -0
- package/src/cadre-node.ts +10003 -9381
- package/src/control-database.ts +4663 -4451
- package/src/control-schema.ts +19 -3
- package/src/ed25519-key.ts +20 -10
- package/src/fetch-impl.ts +23 -0
- package/src/file-durable-slot.ts +64 -63
- package/src/file-safe-name.ts +32 -0
- package/src/formation-approval.ts +604 -610
- package/src/fs-atomic.ts +92 -117
- package/src/index.ts +71 -4
- package/src/invitation-bootstrap.ts +91 -13
- package/src/joined-strand-store.ts +508 -498
- package/src/key-store-file.ts +142 -141
- package/src/link-budget.ts +9 -4
- package/src/machine-removal.ts +216 -0
- package/src/membership-connection-gater.ts +638 -637
- package/src/node-claim-payload.ts +138 -4
- package/src/node-default-transports.ts +38 -0
- package/src/node-transports.ts +49 -0
- package/src/peer-dial.ts +604 -336
- package/src/peer-join-backfill.ts +6 -0
- package/src/peer-record.ts +159 -202
- package/src/primary-lan-address.ts +47 -0
- package/src/provider/client.ts +326 -0
- package/src/provider/descriptor.ts +129 -0
- package/src/provider/index.ts +59 -0
- package/src/provider/oauth.ts +285 -0
- package/src/provider/rent-node.ts +275 -0
- package/src/relay-addrs.ts +9 -4
- package/src/relay-reservation.ts +1211 -1121
- package/src/seed-bootstrap.ts +1502 -1471
- package/src/strand-commit-durability.ts +116 -0
- package/src/strand-database.ts +46 -14
- package/src/strand-first-sync-gate.ts +7 -1
- package/src/strand-formation-protocol.ts +1039 -1036
- package/src/strand-fret-addrs.ts +179 -145
- package/src/strand-instance-manager.ts +2026 -1883
- package/src/strand-move.ts +585 -0
- package/src/strand-network-config.ts +7 -6
- package/src/strand-peer-redial.ts +307 -0
- package/src/strand-wake-protocol.ts +10 -7
- package/src/types.ts +220 -4
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A running strand node redialing the strand's other members itself, when it holds a
|
|
3
|
+
* connection to none of them, with the dial budget the host's declared link gives a
|
|
4
|
+
* relayed connection.
|
|
5
|
+
*
|
|
6
|
+
* Why. Below cadre-core the only thing that redials a strand peer is FRET's maintenance:
|
|
7
|
+
* its pings and neighbour announcements open the connection themselves (`dial: true`) under
|
|
8
|
+
* a fixed 2 000 ms limit on the whole call (`MAINTENANCE_RPC_TIMEOUT_MS` in `p2p-fret`'s
|
|
9
|
+
* `fret-service.ts`). Opening a relayed connection takes longer than that on a slow link:
|
|
10
|
+
* about 9 s on a 20 ms per-frame cap with a 70%-busy event loop
|
|
11
|
+
* (`joiner-first-commit-over-slow-relay`, whose slow-restart arm reproduces this), where
|
|
12
|
+
* {@link relayedDialBudgetMs} allows 21.5 s at the default declaration. Each such redial is
|
|
13
|
+
* cut off part-way through the handshake, from both sides, for as long as the link stays that
|
|
14
|
+
* slow. And after a restart nothing else dials a strand peer: a cross-party strand's launch
|
|
15
|
+
* seed is empty, and cadre-core's address passes only fill the address book. Two phones that
|
|
16
|
+
* restarted then never reconnect, and a write either made alone never reaches the other.
|
|
17
|
+
*
|
|
18
|
+
* What it does. One loop per strand runtime, started in `StrandInstanceManager`'s runtime
|
|
19
|
+
* build and stopped with the runtime (stop, quiesce, failed build), so a hibernating strand
|
|
20
|
+
* never dials. Each look at the node:
|
|
21
|
+
* - a member connected: nothing to do; look again in {@link STRAND_REDIAL_CHECK_MS}, or as
|
|
22
|
+
* soon as a peer disconnects.
|
|
23
|
+
* - no member connected and none known: likewise nothing (a founder alone, a storage replica
|
|
24
|
+
* before anyone arrives).
|
|
25
|
+
* - no member connected and some known: dial every known member at once
|
|
26
|
+
* ({@link dialPeerAddrs}, direct addresses before relayed ones), each address with the
|
|
27
|
+
* relayed-dial budget. A round that connects to one goes back to watching; one that does
|
|
28
|
+
* not waits a backoff starting at that budget and doubling to
|
|
29
|
+
* {@link STRAND_REDIAL_MAX_BACKOFF_MS}.
|
|
30
|
+
*
|
|
31
|
+
* Who is known: every peer the node's FRET table holds a verified signed address record for
|
|
32
|
+
* (`strand-fret-addrs.ts`), plus the launch seed (sibling strand addresses and a formation's
|
|
33
|
+
* carried addresses). Who counts as connected: a peer FRET labels `'member'` (it has seen it
|
|
34
|
+
* speak this strand's protocols), or a seed peer. Neither ever includes a configured relay, a
|
|
35
|
+
* peer FRET labels `'foreign'`, or a peer the revocation gate refuses. The relay matters most:
|
|
36
|
+
* the strand node is connected to it throughout and FRET files it with a record like any
|
|
37
|
+
* peer, so counting it would leave this loop idle exactly when it is needed.
|
|
38
|
+
*
|
|
39
|
+
* NOTE: this compensates for FRET's 2 000 ms maintenance dial limit, which cannot open a
|
|
40
|
+
* relayed connection on a slow link (upstream half:
|
|
41
|
+
* `blocked/fret-maintenance-ping-dial-budget-below-a-relayed-dial`). If FRET's maintenance
|
|
42
|
+
* dial ever takes a limit derived from the declared link, this loop becomes a backstop and
|
|
43
|
+
* may be deleted, as `peer-join-backfill.ts` says of itself.
|
|
44
|
+
*/
|
|
45
|
+
import debug from 'debug';
|
|
46
|
+
import { relayedDialBudgetMs } from './link-budget.js';
|
|
47
|
+
import { CONTROL_COHORT_DIAL_ADDRESS_ATTEMPTS, SelfRelayOnlyError, dialPeerAddrs } from './peer-dial.js';
|
|
48
|
+
import { groupAddrsByPeerId } from './peer-addr-book.js';
|
|
49
|
+
import { strandFretMembership, strandFretPeerAddrs } from './strand-fret-addrs.js';
|
|
50
|
+
import { defaultTimeoutScheduler } from './timeout-scheduler.js';
|
|
51
|
+
const log = debug('sereus:cadre:strand-redial');
|
|
52
|
+
/**
|
|
53
|
+
* Gap between looks while a member is connected or none is known. While a member is
|
|
54
|
+
* connected a look reads FRET's labels and the connection list and checks no signature
|
|
55
|
+
* ({@link strandFretMembership}); a disconnect also triggers a look at once.
|
|
56
|
+
*/
|
|
57
|
+
export const STRAND_REDIAL_CHECK_MS = 5000;
|
|
58
|
+
/**
|
|
59
|
+
* Ceiling on the wait between failed rounds. A member that is gone for good is dialed this
|
|
60
|
+
* often for as long as FRET keeps its record (up to 14 days after it was last confirmed).
|
|
61
|
+
*/
|
|
62
|
+
export const STRAND_REDIAL_MAX_BACKOFF_MS = 5 * 60000;
|
|
63
|
+
/**
|
|
64
|
+
* The timings at a declared link round trip: {@link relayedDialBudgetMs} per address, the
|
|
65
|
+
* same whole-budget count per member as the control cohort's dials (dead direct addresses
|
|
66
|
+
* a record lists ahead of the relayed one that works), and a first backoff of one per-address
|
|
67
|
+
* budget.
|
|
68
|
+
*/
|
|
69
|
+
export function strandRedialTimings(linkRoundTripMs) {
|
|
70
|
+
const perAddressMs = relayedDialBudgetMs(linkRoundTripMs);
|
|
71
|
+
return {
|
|
72
|
+
budget: { perAddressMs, totalMs: CONTROL_COHORT_DIAL_ADDRESS_ATTEMPTS * perAddressMs },
|
|
73
|
+
minBackoffMs: perAddressMs,
|
|
74
|
+
maxBackoffMs: STRAND_REDIAL_MAX_BACKOFF_MS,
|
|
75
|
+
checkMs: STRAND_REDIAL_CHECK_MS
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Start the loop; its first look runs at once. */
|
|
79
|
+
export function superviseStrandPeerRedial(deps, timings) {
|
|
80
|
+
return new StrandPeerRedialLoop(deps, timings);
|
|
81
|
+
}
|
|
82
|
+
class StrandPeerRedialLoop {
|
|
83
|
+
constructor(deps, timings) {
|
|
84
|
+
this.deps = deps;
|
|
85
|
+
this.timings = timings;
|
|
86
|
+
this.timer = null;
|
|
87
|
+
/**
|
|
88
|
+
* Whether the pending wait is a plain gap between looks, which a disconnect cuts short. A
|
|
89
|
+
* backoff after a failed round is not cut short, or a flapping relay connection would turn
|
|
90
|
+
* the backoff into a dial on every flap; and while a look or round runs there is no wait.
|
|
91
|
+
*/
|
|
92
|
+
this.watching = false;
|
|
93
|
+
this.stopped = false;
|
|
94
|
+
this.onDisconnect = () => {
|
|
95
|
+
if (this.watching && !this.stopped) {
|
|
96
|
+
this.cancelTimer();
|
|
97
|
+
void this.tick();
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
this.scheduler = deps.scheduler ?? defaultTimeoutScheduler;
|
|
101
|
+
this.seed = groupAddrsByPeerId([...deps.seed]);
|
|
102
|
+
this.selfId = deps.node.peerId.toString();
|
|
103
|
+
this.backoffMs = timings.minBackoffMs;
|
|
104
|
+
deps.node.addEventListener('peer:disconnect', this.onDisconnect);
|
|
105
|
+
void this.tick();
|
|
106
|
+
}
|
|
107
|
+
stop() {
|
|
108
|
+
if (this.stopped) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.stopped = true;
|
|
112
|
+
this.cancelTimer();
|
|
113
|
+
this.deps.node.removeEventListener('peer:disconnect', this.onDisconnect);
|
|
114
|
+
}
|
|
115
|
+
async tick() {
|
|
116
|
+
if (this.stopped) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.watching = false;
|
|
120
|
+
let outcome = 'watch';
|
|
121
|
+
try {
|
|
122
|
+
outcome = await this.lookAndDial();
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// A node torn down under the look throws from its table export or connection list.
|
|
126
|
+
log('strand %s: redial look failed (looking again in %dms): %o', this.deps.label, this.timings.checkMs, error);
|
|
127
|
+
}
|
|
128
|
+
if (this.stopped) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
this.watching = outcome === 'watch';
|
|
132
|
+
const waitMs = outcome === 'watch' ? this.resetBackoff() : this.nextBackoff();
|
|
133
|
+
this.timer = this.scheduler.setTimeout(() => {
|
|
134
|
+
this.timer = null;
|
|
135
|
+
void this.tick();
|
|
136
|
+
}, waitMs);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* One look, and a round of dials when it finds no member connected but some known. A node
|
|
140
|
+
* whose own party was removed dials nobody: the strand keeps running for the session, but a
|
|
141
|
+
* removed party must not keep dialing the strand's peers (`CadreNode.forgetRevokedJoin`).
|
|
142
|
+
*/
|
|
143
|
+
async lookAndDial() {
|
|
144
|
+
if (this.deps.isRevoked?.(this.selfId) === true) {
|
|
145
|
+
return 'watch';
|
|
146
|
+
}
|
|
147
|
+
const membership = strandFretMembership(this.deps.node);
|
|
148
|
+
if (this.memberConnected(membership)) {
|
|
149
|
+
return 'watch';
|
|
150
|
+
}
|
|
151
|
+
const known = await this.knownMembers(membership);
|
|
152
|
+
if (known.size === 0 || this.stopped) {
|
|
153
|
+
return 'watch';
|
|
154
|
+
}
|
|
155
|
+
log('strand %s: no member connected; dialing %d known member(s)', this.deps.label, known.size);
|
|
156
|
+
if (await this.dialAny(known)) {
|
|
157
|
+
log('strand %s: reconnected to a member', this.deps.label);
|
|
158
|
+
return 'watch';
|
|
159
|
+
}
|
|
160
|
+
log('strand %s: no known member answered; next round in %dms', this.deps.label, this.backoffMs);
|
|
161
|
+
return 'retry';
|
|
162
|
+
}
|
|
163
|
+
/** The gap between looks, with the backoff started over. */
|
|
164
|
+
resetBackoff() {
|
|
165
|
+
this.backoffMs = this.timings.minBackoffMs;
|
|
166
|
+
return this.timings.checkMs;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The wait after a round that reached no member, doubling the next one up to the cap.
|
|
170
|
+
*
|
|
171
|
+
* NOTE: a round whose dials failed within milliseconds (a relay connection that is still
|
|
172
|
+
* closing, the member's relay reservation not back yet) waits as long as one whose dials ran
|
|
173
|
+
* out their budget. In `joiner-first-commit-over-slow-relay`'s third arm that first wait is what
|
|
174
|
+
* leaves the joiner writable with no member connected. If reconnecting within seconds of a cut
|
|
175
|
+
* ever matters, retry a round that failed that fast after a short delay instead.
|
|
176
|
+
*
|
|
177
|
+
* NOTE: one such fast failure is `ConnectionClosedError: The connection muxer is "closed"`. A
|
|
178
|
+
* relay that aborts its connection to this node cannot tell it so (`@libp2p/websockets`'
|
|
179
|
+
* listener resets with close code 1006, which the `ws` package refuses to send;
|
|
180
|
+
* `blocked/report-libp2p-websockets-buffered-amount`, second arm), so this node keeps a dead
|
|
181
|
+
* relay connection until its own monitor drops it, up to 65 s, and every relayed dial reuses
|
|
182
|
+
* it. If rounds keep failing that way, close a relay connection whose muxer is closed before
|
|
183
|
+
* the next round instead of waiting it out.
|
|
184
|
+
*/
|
|
185
|
+
nextBackoff() {
|
|
186
|
+
const waitMs = this.backoffMs;
|
|
187
|
+
this.backoffMs = Math.min(waitMs * 2, this.timings.maxBackoffMs);
|
|
188
|
+
return waitMs;
|
|
189
|
+
}
|
|
190
|
+
eligible(peerId) {
|
|
191
|
+
return peerId !== this.selfId && !this.deps.excluded.has(peerId) && this.deps.isRevoked?.(peerId) !== true;
|
|
192
|
+
}
|
|
193
|
+
/** Whether an open connection reaches a peer FRET has seen speak this strand's protocols, or a seed peer. */
|
|
194
|
+
memberConnected(membership) {
|
|
195
|
+
return this.deps.node.getConnections().some((connection) => {
|
|
196
|
+
const peerId = connection.remotePeer.toString();
|
|
197
|
+
return this.eligible(peerId) && (membership.get(peerId) === 'member' || this.seed.has(peerId));
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/** The members to dial, each with its candidate addresses: verified FRET records first, then the seed's. */
|
|
201
|
+
async knownMembers(membership) {
|
|
202
|
+
const { peers } = await strandFretPeerAddrs(this.deps.node);
|
|
203
|
+
const known = new Map();
|
|
204
|
+
for (const [peerId, addrs] of [...peers, ...this.seed]) {
|
|
205
|
+
if (!this.eligible(peerId) || membership.get(peerId) === 'foreign') {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
known.set(peerId, unionAddrs(known.get(peerId) ?? [], addrs));
|
|
209
|
+
}
|
|
210
|
+
return known;
|
|
211
|
+
}
|
|
212
|
+
/** Dial every member in `known` at once; resolves to whether any connected. */
|
|
213
|
+
async dialAny(known) {
|
|
214
|
+
const members = [...known];
|
|
215
|
+
const outcomes = await Promise.allSettled(members.map(([peerId, addrs]) => dialPeerAddrs(this.deps.node, peerId, addrs, this.timings.budget, `strand ${this.deps.label} redial of ${peerId}`)));
|
|
216
|
+
outcomes.forEach((outcome, i) => {
|
|
217
|
+
if (outcome.status === 'rejected') {
|
|
218
|
+
const reason = outcome.reason instanceof SelfRelayOnlyError ? 'reachable only by relaying through this node' : outcome.reason;
|
|
219
|
+
log('strand %s: redial of %s failed: %o', this.deps.label, members[i][0], reason);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
return outcomes.some((outcome) => outcome.status === 'fulfilled');
|
|
223
|
+
}
|
|
224
|
+
cancelTimer() {
|
|
225
|
+
if (this.timer !== null) {
|
|
226
|
+
this.scheduler.clearTimeout(this.timer);
|
|
227
|
+
this.timer = null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** `primary` then the entries of `extra` it lacks, compared as strings. */
|
|
232
|
+
function unionAddrs(primary, extra) {
|
|
233
|
+
const seen = new Set(primary.map((addr) => addr.toString()));
|
|
234
|
+
return [...primary, ...extra.filter((addr) => !seen.has(addr.toString()))];
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=strand-peer-redial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strand-peer-redial.js","sourceRoot":"","sources":["../src/strand-peer-redial.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,oCAAoC,EAAE,kBAAkB,EAAE,aAAa,EAAwC,MAAM,gBAAgB,CAAC;AAC/I,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAA0C,MAAM,wBAAwB,CAAC;AAC3H,OAAO,EAAE,uBAAuB,EAAyB,MAAM,wBAAwB,CAAC;AAExF,MAAM,GAAG,GAAG,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAK,CAAC;AAE5C;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,KAAM,CAAC;AAcvD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,eAAwB;IAC1D,MAAM,YAAY,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAC;IAC1D,OAAO;QACL,MAAM,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,oCAAoC,GAAG,YAAY,EAAE;QACtF,YAAY,EAAE,YAAY;QAC1B,YAAY,EAAE,4BAA4B;QAC1C,OAAO,EAAE,sBAAsB;KAChC,CAAC;AACJ,CAAC;AAuCD,mDAAmD;AACnD,MAAM,UAAU,yBAAyB,CAAC,IAAsB,EAAE,OAA4B;IAC5F,OAAO,IAAI,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,oBAAoB;IAoBxB,YAA6B,IAAsB,EAAmB,OAA4B;QAArE,SAAI,GAAJ,IAAI,CAAkB;QAAmB,YAAO,GAAP,OAAO,CAAqB;QAf1F,UAAK,GAAY,IAAI,CAAC;QAC9B;;;;WAIG;QACK,aAAQ,GAAG,KAAK,CAAC;QACjB,YAAO,GAAG,KAAK,CAAC;QACP,iBAAY,GAAG,GAAS,EAAE;YACzC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACnC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACnB,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;QAGA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,uBAAuB,CAAC;QAC3D,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QAC1C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACjE,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3E,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,OAAO,GAAgB,OAAO,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mFAAmF;YACnF,GAAG,CAAC,2DAA2D,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjH,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,OAAO,KAAK,OAAO,CAAC;QACpC,MAAM,MAAM,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC9E,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE;YAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,WAAW;QACvB,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAChD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;YACrC,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACrC,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,GAAG,CAAC,4DAA4D,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/F,IAAI,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,GAAG,CAAC,oCAAoC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3D,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,GAAG,CAAC,yDAAyD,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAChG,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,4DAA4D;IACpD,YAAY;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACK,WAAW;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACjE,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,QAAQ,CAAC,MAAc;QAC7B,OAAO,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7G,CAAC;IAED,6GAA6G;IACrG,eAAe,CAAC,UAA+C;QACrE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;YACzD,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;YAChD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACjG,CAAC,CAAC,CAAC;IACL,CAAC;IAED,4GAA4G;IACpG,KAAK,CAAC,YAAY,CAAC,UAA+C;QACxE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC7C,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;gBACnE,SAAS;YACX,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+EAA+E;IACvE,KAAK,CAAC,OAAO,CAAC,KAAuC;QAC3D,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,CACxE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,cAAc,MAAM,EAAE,CAAC,CACnH,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;YAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAClC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,YAAY,kBAAkB,CAAC,CAAC,CAAC,8CAA8C,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;gBAC9H,GAAG,CAAC,oCAAoC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACpF,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;IACpE,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;CACF;AAED,2EAA2E;AAC3E,SAAS,UAAU,CAAC,OAA6B,EAAE,KAA2B;IAC5E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import debug from 'debug';
|
|
27
27
|
import { decodeLengthPrefixedFrame } from './seed-bootstrap.js';
|
|
28
28
|
import { exchangeFrame, readStreamToEnd, replyAndClose } from './control-stream.js';
|
|
29
|
-
import { tryAddrsInTurn } from './peer-dial.js';
|
|
29
|
+
import { dialAddr, tryAddrsInTurn } from './peer-dial.js';
|
|
30
30
|
import { relayedRequestBudgetMs } from './link-budget.js';
|
|
31
31
|
const log = debug('sereus:cadre:strand-wake');
|
|
32
32
|
/** Protocol id for control-network push-wake (parallel to `/sereus/seed/1.0.0`). */
|
|
@@ -268,20 +268,23 @@ export async function dialWake(node, addrs, request, options = {}) {
|
|
|
268
268
|
return await tryAddrsInTurn(addrs, budget, 'Wake dial', (addr, signal, attemptMs) => sendWake(node, addr, protocolId, request, attemptMs, signal));
|
|
269
269
|
}
|
|
270
270
|
/**
|
|
271
|
-
*
|
|
271
|
+
* Dial one address, open one stream, send the request, half-close, and read the ack.
|
|
272
272
|
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
273
|
+
* The address is dialed outside libp2p's dial queue (`dialAddr`), so another dial of
|
|
274
|
+
* the target in flight cannot capture this attempt; an open connection is still reused.
|
|
275
|
+
*
|
|
276
|
+
* `signal` is the per-attempt deadline from {@link dialWake}: it goes to the dial so a
|
|
277
|
+
* timeout during connect aborts it, and into {@link exchangeFrame} so a timeout after
|
|
278
|
+
* the stream is open resets it — releasing the otherwise unbounded ack-read.
|
|
277
279
|
*/
|
|
278
280
|
async function sendWake(node, addr, protocolId, request, timeoutMs, signal) {
|
|
281
|
+
const connection = await dialAddr(node, addr, signal, 'Wake dial');
|
|
279
282
|
// `runOnLimitedConnection: true`: the target may be reachable only over a
|
|
280
283
|
// circuit-relay connection (the signaling-first addr), which libp2p marks
|
|
281
284
|
// "limited". The wake exchange is a single tiny request→ack well within the
|
|
282
285
|
// relay's data/duration cap, so opening it on the limited connection is safe
|
|
283
286
|
// and is the whole point of dialing the relay address.
|
|
284
|
-
const rawStream = await
|
|
287
|
+
const rawStream = await connection.newStream(protocolId, { runOnLimitedConnection: true, signal });
|
|
285
288
|
const ack = await exchangeFrame(rawStream, signal, request, (stream) => readFrame(stream, timeoutMs), 'Wake dial aborted by timeout');
|
|
286
289
|
log('Wake ack from %s: accepted=%s status=%s', addr.toString(), ack.accepted, ack.status ?? '-');
|
|
287
290
|
return ack;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strand-wake-protocol.js","sourceRoot":"","sources":["../src/strand-wake-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAsB,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACxG,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"strand-wake-protocol.js","sourceRoot":"","sources":["../src/strand-wake-protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StrandRevocationEnforcementConfig } from './strand-revocation-enfo
|
|
|
8
8
|
import type { StrandMembershipReconciliationConfig } from './strand-membership-reconciler.js';
|
|
9
9
|
import type { StrandFirstSyncConfig } from './strand-first-sync-gate.js';
|
|
10
10
|
import type { StrandDatabase } from './strand-database.js';
|
|
11
|
+
import type { StrandCommitDurability, StrandCommitHeld } from './strand-commit-durability.js';
|
|
11
12
|
import type { SeedTrustPolicy } from './seed-trust-policy.js';
|
|
12
13
|
import type { KeyStore, KeyId } from './key-store.js';
|
|
13
14
|
import type { TrustedOwnerStore, TrustSource } from './trusted-owner-store.js';
|
|
@@ -17,9 +18,10 @@ import type { EnrolledMachineStore } from './enrolled-machine-store.js';
|
|
|
17
18
|
import type { JoinedStrandStore } from './joined-strand-store.js';
|
|
18
19
|
import type { PushNotifier } from './push-notifier.js';
|
|
19
20
|
import type { CadreInviteSignedFields, RevocableTable } from './control-authorization.js';
|
|
20
|
-
import type { CadreInvitation } from './cadre-invite-protocol.js';
|
|
21
|
+
import type { CadreInvitation, CadreInviteAddressOutcome } from './cadre-invite-protocol.js';
|
|
21
22
|
import type { ControlRetryAbandonment } from './control-retry.js';
|
|
22
23
|
import type { FormationRejectionCode } from './strand-formation-rejection.js';
|
|
24
|
+
import type { ListenTransportOptions } from './relay-addrs.js';
|
|
23
25
|
/**
|
|
24
26
|
* Extended Libp2p node with the coordinatedRepo attached by db-p2p's
|
|
25
27
|
* createLibp2pNode after node creation (not surfaced on the base Libp2p type).
|
|
@@ -369,6 +371,20 @@ export interface NetworkConfig {
|
|
|
369
371
|
* ```
|
|
370
372
|
*/
|
|
371
373
|
transports?: Libp2pTransports;
|
|
374
|
+
/**
|
|
375
|
+
* Builds `@optimystic/db-p2p`'s default transport list, for the one case where cadre has to
|
|
376
|
+
* pass a list itself while {@link transports} is unset: a node with configured relays, which
|
|
377
|
+
* is built with libp2p's relay discovery switched off (`node-transports.ts`). Called with the
|
|
378
|
+
* switches the node's listen entries imply (`wsPort` when one names WebSocket). Ignored when
|
|
379
|
+
* {@link transports} is set.
|
|
380
|
+
*
|
|
381
|
+
* A Node host passes `nodeDefaultTransports` from the Node-only
|
|
382
|
+
* `@serfab/cadre-core/node-default-transports` subpath, as `cadre-cli` does. It is injected
|
|
383
|
+
* rather than built in, because that list names `@libp2p/tcp`, which must stay out of the
|
|
384
|
+
* graph React Native and browser bundles reach. Left unset, such a node is built from
|
|
385
|
+
* db-p2p's own list with relay discovery on.
|
|
386
|
+
*/
|
|
387
|
+
defaultTransports?: (listen: ListenTransportOptions) => Libp2pTransports;
|
|
372
388
|
/**
|
|
373
389
|
* Crypto primitives for the Noise handshake and the encrypted connection that
|
|
374
390
|
* follows, threaded to both the control node and every strand's cohort node — every
|
|
@@ -592,6 +608,16 @@ export interface NetworkConfig {
|
|
|
592
608
|
* kept it (the same pair aborted at a 200ms stall only when the deadline was 300ms). An
|
|
593
609
|
* interval strictly above the deadline is what makes the 30 seconds real.
|
|
594
610
|
*
|
|
611
|
+
* WHY THE OTHER END'S PING HANDLER CAPS IT TOO. The node being pinged echoes through
|
|
612
|
+
* `@libp2p/ping`'s inbound handler, which aborts the ping stream when its own timer fires; the
|
|
613
|
+
* pinging node's monitor sees the reset and aborts the connection exactly as it would on its
|
|
614
|
+
* own timeout. So this deadline is only real up to the handler timeout of the node being
|
|
615
|
+
* pinged, which has to stay above it. The deployed relay sets its handler to 60 s for that
|
|
616
|
+
* reason (`ops/docker/libp2p-infra/src/main.ts`). Every cadre node's handler is Optimystic's
|
|
617
|
+
* bare `ping()`, `@libp2p/ping`'s 10 s, and nothing here can move it
|
|
618
|
+
* (`tickets/blocked/optimystic-ping-handler-timeout-below-the-monitor-deadline.md`): between
|
|
619
|
+
* two cadre nodes, a ping whose echo takes longer than 10 s still drops the connection.
|
|
620
|
+
*
|
|
595
621
|
* WHAT THE LINK NEEDS OF IT. One ping opens a fresh stream and echoes over it: a protocol
|
|
596
622
|
* negotiation plus the echo, two link round trips by `link-budget.ts`'s counts (a `newStream`
|
|
597
623
|
* over a relayed circuit measured 3016 ms at 1500 ms one-way). At the slowest link sereus
|
|
@@ -1539,6 +1565,24 @@ export interface CadreNodeEvents {
|
|
|
1539
1565
|
'strand:writable': {
|
|
1540
1566
|
strandId: string;
|
|
1541
1567
|
};
|
|
1568
|
+
/**
|
|
1569
|
+
* Emitted after every commit on a strand's database that wrote something, with whether
|
|
1570
|
+
* another member already holds it (`heldElsewhere`) and whether `strand:commit-held` will
|
|
1571
|
+
* say when it does (`followed`). Synchronous, inside the commit, before the app's statement
|
|
1572
|
+
* returns: keep handlers short. Covers every commit on the strand database, cadre-core's own
|
|
1573
|
+
* membership writes included, so filter by the ids you hold — the `StampId()` a
|
|
1574
|
+
* `returning StampId() as Tx` statement gave you. The same record is readable afterwards with
|
|
1575
|
+
* `StrandDatabase.commitDurability(tx)`. See docs/strands.md, "A commit's durability".
|
|
1576
|
+
*/
|
|
1577
|
+
'strand:commit-durability': StrandCommitDurability;
|
|
1578
|
+
/**
|
|
1579
|
+
* Emitted once when a commit reported `followed` below full replication becomes held by every
|
|
1580
|
+
* member of its cohort — the moment a write made while the others were away reaches them.
|
|
1581
|
+
* Synchronous, like `strand:commit-durability`, and can come right after it inside the same
|
|
1582
|
+
* commit. Never emitted for a commit made before your listener attached, or one forgotten
|
|
1583
|
+
* because its database closed, hibernated or the node restarted.
|
|
1584
|
+
*/
|
|
1585
|
+
'strand:commit-held': StrandCommitHeld;
|
|
1542
1586
|
/**
|
|
1543
1587
|
* Emitted when this node discovers it is no longer a member of a CLOSED
|
|
1544
1588
|
* strand — its party was removed by a manager, or it left. Detected by the
|
|
@@ -1689,6 +1733,18 @@ export interface CadreNodeEvents {
|
|
|
1689
1733
|
* matching predicate for a reader that subscribed too late to see the event.
|
|
1690
1734
|
*/
|
|
1691
1735
|
'claim:accepted': NodeClaimRecord;
|
|
1736
|
+
/**
|
|
1737
|
+
* Emitted once per node object when this node learns that an owner removed it from the
|
|
1738
|
+
* cadre: a `CadrePeer` tombstone names its peer id, it has no live `CadrePeer` row, and a
|
|
1739
|
+
* membership refresh of this process had seen its live row before. `CadreNode.removedFromCadre`
|
|
1740
|
+
* is the matching query for a reader that subscribed too late.
|
|
1741
|
+
*
|
|
1742
|
+
* BEST-EFFORT: it fires only if the tombstone reached this node before the other machines
|
|
1743
|
+
* cut it off, so a machine that was offline at removal time usually never sees it. Nothing
|
|
1744
|
+
* is stopped or deleted for you; the node only stops its owner re-issue drains, which can no
|
|
1745
|
+
* longer succeed. Stopping the node and deleting the cadre's data are the embedder's.
|
|
1746
|
+
*/
|
|
1747
|
+
'cadre:removed': CadreRemoval;
|
|
1692
1748
|
}
|
|
1693
1749
|
/**
|
|
1694
1750
|
* A peer's self-published, freshness-stamped, self-signed address record.
|
|
@@ -1699,8 +1755,8 @@ export interface CadreNodeEvents {
|
|
|
1699
1755
|
* PeerId by reading the record, re-verifying the self-signature against
|
|
1700
1756
|
* `publicKey`, checking freshness, and applying a trust gate.
|
|
1701
1757
|
*
|
|
1702
|
-
* The signature covers `peerId`, the comma-joined `addrs`, and `
|
|
1703
|
-
* `peerRecordSignedPayload`. `publicKey` is NOT inside the signed payload: it is
|
|
1758
|
+
* The signature covers `peerId`, the comma-joined `addrs`, `updatedAt` and `profile` —
|
|
1759
|
+
* see `peerRecordSignedPayload`. `publicKey` is NOT inside the signed payload: it is
|
|
1704
1760
|
* the key the signature is verified *with*, and its libp2p-identity binding to
|
|
1705
1761
|
* `peerId` is checked separately at resolve time, so re-signing it would be
|
|
1706
1762
|
* redundant.
|
|
@@ -1714,6 +1770,12 @@ export interface PeerAddressRecord {
|
|
|
1714
1770
|
addrs: string[];
|
|
1715
1771
|
/** epoch ms — freshness; strictly increasing per peer. */
|
|
1716
1772
|
updatedAt: number;
|
|
1773
|
+
/**
|
|
1774
|
+
* The publisher's own {@link CadreNodeConfig.profile}: `'transaction'` is an app (phone,
|
|
1775
|
+
* browser), `'storage'` an always-on node. Null on a row the machine has not yet
|
|
1776
|
+
* self-published (an owner or an invitation seated it).
|
|
1777
|
+
*/
|
|
1778
|
+
profile: NodeProfile | null;
|
|
1717
1779
|
/** ed25519 self-signature over the signed payload, base64url. */
|
|
1718
1780
|
sig: string;
|
|
1719
1781
|
}
|
|
@@ -1735,8 +1797,16 @@ export interface PeerAddressRecord {
|
|
|
1735
1797
|
export interface CadrePeerRow {
|
|
1736
1798
|
/** libp2p peer ID (base58btc) — the row key. */
|
|
1737
1799
|
peerId: string;
|
|
1800
|
+
/** ed25519 public key (base64url) stored for the peer, or null (not ed25519, or a row written before the column). */
|
|
1801
|
+
publicKey: string | null;
|
|
1738
1802
|
/** Comma-joined dialable multiaddrs as stored, or null when unpublished. */
|
|
1739
1803
|
multiaddr: string | null;
|
|
1804
|
+
/** The machine's freshness stamp (epoch ms); 0 when it has never self-published. */
|
|
1805
|
+
updatedAt: number;
|
|
1806
|
+
/** The machine's self-declared node profile; null until it self-publishes. */
|
|
1807
|
+
profile: NodeProfile | null;
|
|
1808
|
+
/** The machine's self-signature over its address record (`peerRecordSignedPayload`); null until it self-publishes. */
|
|
1809
|
+
sig: string | null;
|
|
1740
1810
|
/** Single-use anti-replay nonce the voucher signature, or the usage row, is bound to. */
|
|
1741
1811
|
stampId: string | null;
|
|
1742
1812
|
/** ed25519 public key (base64url) of the owner that vouched this row, or that issued the invitation that admitted it. */
|
|
@@ -1820,6 +1890,101 @@ export interface InvitationChain {
|
|
|
1820
1890
|
usages: Map<string, CadreInviteUsageRow>;
|
|
1821
1891
|
invites: Map<string, CadreInviteRow>;
|
|
1822
1892
|
}
|
|
1893
|
+
/**
|
|
1894
|
+
* One machine of the cadre as `CadreNode.listMachines` reports it: a live `CadrePeer` row,
|
|
1895
|
+
* or a live `OwnerKey` whose key derives a peer id with no `CadrePeer` row (an owner key
|
|
1896
|
+
* seated for a machine not yet admitted, or a founder that never self-published).
|
|
1897
|
+
*
|
|
1898
|
+
* `profile` and `lastPublishedAt` are the machine's own claim only when the row's
|
|
1899
|
+
* self-signature verifies; both are null otherwise, so an owner re-vouch that bumped
|
|
1900
|
+
* `UpdatedAt` without re-signing, or a row the machine never published, reports nothing
|
|
1901
|
+
* rather than someone else's stamp.
|
|
1902
|
+
*/
|
|
1903
|
+
export interface CadreMachine {
|
|
1904
|
+
peerId: string;
|
|
1905
|
+
/** ed25519 public key (base64url) behind `peerId`; null when the id is not ed25519. */
|
|
1906
|
+
publicKey: string | null;
|
|
1907
|
+
/** This node itself. */
|
|
1908
|
+
isSelf: boolean;
|
|
1909
|
+
/** `publicKey` is a live `OwnerKey` here. */
|
|
1910
|
+
isOwner: boolean;
|
|
1911
|
+
/** Has a live `CadrePeer` row; false for an owner key with no machine row. */
|
|
1912
|
+
isMember: boolean;
|
|
1913
|
+
/** Passes this node's authorized-membership predicate now (`CadreNode.listAuthorizedMembers`; always false for self, which that set excludes). */
|
|
1914
|
+
trusted: boolean;
|
|
1915
|
+
/** The machine's self-published node profile; null until it publishes, or when its signature does not verify. */
|
|
1916
|
+
profile: NodeProfile | null;
|
|
1917
|
+
/** `UpdatedAt` of its self-signed record, re-stamped while it runs; null on the same terms as `profile`. */
|
|
1918
|
+
lastPublishedAt: number | null;
|
|
1919
|
+
/** `CadrePeer.VouchOwner` (or `OwnerKey.VouchOwner` for an owner-only entry): the owner that vouched it, or the issuer of the invitation that admitted it. */
|
|
1920
|
+
vouchedBy: string | null;
|
|
1921
|
+
}
|
|
1922
|
+
/** Why `CadreNode.removeMachine` refuses by name (`MachineRemovalRefusedError.code`). */
|
|
1923
|
+
export type MachineRemovalRefusal =
|
|
1924
|
+
/** This node holds no enrolled owner key, so it cannot sign the removal. */
|
|
1925
|
+
'not-an-owner'
|
|
1926
|
+
/** The machine is this node: an owner cannot sign its own `OwnerKey` removal, so ask another owner. */
|
|
1927
|
+
| 'self'
|
|
1928
|
+
/** The machine holds the only live owner key here (`MinOneOwner`). */
|
|
1929
|
+
| 'last-owner';
|
|
1930
|
+
/**
|
|
1931
|
+
* What `CadreNode.removeMachine` would do for one machine, read without writing
|
|
1932
|
+
* (`CadreNode.planMachineRemoval`), for an app's confirmation step.
|
|
1933
|
+
*/
|
|
1934
|
+
export interface MachineRemovalPlan {
|
|
1935
|
+
/** The machine as listed, or null when no live row names it here (already removed). */
|
|
1936
|
+
machine: CadreMachine | null;
|
|
1937
|
+
refusal: MachineRemovalRefusal | null;
|
|
1938
|
+
/** The machine's key is a live owner key, so the removal also retires it. */
|
|
1939
|
+
removesOwnerKey: boolean;
|
|
1940
|
+
/** Rows the machine's owner key vouched, which stop passing the membership predicate everywhere once it is removed unless re-vouched first. Empty unless `removesOwnerKey`. */
|
|
1941
|
+
dependents: {
|
|
1942
|
+
/** Live `OwnerKey` rows whose `VouchOwner` is the machine's key, this node's own excluded. */
|
|
1943
|
+
owners: string[];
|
|
1944
|
+
/** Live `CadrePeer` rows whose `VouchOwner` is the machine's key, the machine itself and this node excluded. */
|
|
1945
|
+
peers: string[];
|
|
1946
|
+
};
|
|
1947
|
+
/** Live `CadreInvite` keys the machine could redeem to come back: targeted at it, or already redeemed by it with uses left. */
|
|
1948
|
+
invitations: string[];
|
|
1949
|
+
/** This node's own `OwnerKey` or `CadrePeer` row was vouched by the machine. It cannot re-vouch its own rows; another owner has to re-add it afterwards. */
|
|
1950
|
+
ownDependency: boolean;
|
|
1951
|
+
}
|
|
1952
|
+
/** Options for `CadreNode.removeMachine`. */
|
|
1953
|
+
export interface RemoveMachineOptions {
|
|
1954
|
+
/** Dependents to re-vouch under this node's key before the removal; each must appear in the plan's `dependents`. */
|
|
1955
|
+
revouch?: {
|
|
1956
|
+
owners?: readonly string[];
|
|
1957
|
+
peers?: readonly string[];
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
/** What `CadreNode.removeMachine` wrote. All false and empty when no live row named the machine here. */
|
|
1961
|
+
export interface MachineRemovalResult {
|
|
1962
|
+
removedPeer: boolean;
|
|
1963
|
+
removedOwnerKey: boolean;
|
|
1964
|
+
removedDeviceToken: boolean;
|
|
1965
|
+
/** `CadreInvite` keys whose withdrawal tombstone this call filed. */
|
|
1966
|
+
withdrawnInvitations: string[];
|
|
1967
|
+
/** Dependents re-vouched under this node's key before the removal. */
|
|
1968
|
+
revouched: {
|
|
1969
|
+
owners: string[];
|
|
1970
|
+
peers: string[];
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* This node's own removal from its cadre, as it learned it: the `CadrePeer` tombstone naming
|
|
1975
|
+
* its peer id, read after it had seen its own live row (`CadreNode.removedFromCadre`, the
|
|
1976
|
+
* `cadre:removed` event; "Removing a machine" in docs/architecture.md).
|
|
1977
|
+
*/
|
|
1978
|
+
export interface CadreRemoval {
|
|
1979
|
+
/** The cadre this node was removed from (`CadreNode.partyId`). */
|
|
1980
|
+
partyId: string;
|
|
1981
|
+
/** The `StampId` the tombstone retired. */
|
|
1982
|
+
stampId: string;
|
|
1983
|
+
/** The owner key that filed the tombstone, when its signature verifies and the key is in this node's trusted-owner anchor; null otherwise. */
|
|
1984
|
+
signerKey: string | null;
|
|
1985
|
+
/** When this node learned of the removal (epoch ms). */
|
|
1986
|
+
at: number;
|
|
1987
|
+
}
|
|
1823
1988
|
/**
|
|
1824
1989
|
* One {@link CadreInviteRow} with its standing, as `ControlDatabase.listCadreInviteStatuses`
|
|
1825
1990
|
* (and `CadreNode.listCadreInvitations`) reports it. `live` is the redemption's own test:
|
|
@@ -2278,12 +2443,55 @@ export interface CreateCadreInvitationOptions {
|
|
|
2278
2443
|
/** How many redemptions it allows; default 1. */
|
|
2279
2444
|
uses?: number;
|
|
2280
2445
|
}
|
|
2446
|
+
/**
|
|
2447
|
+
* Where a phone could redeem a cadre invitation from, judged on the addresses of machines
|
|
2448
|
+
* other than the one that minted it — the answer to "can the new app join once this one is
|
|
2449
|
+
* closed?". A minting machine that is itself always on can therefore read `issuer-only`.
|
|
2450
|
+
*/
|
|
2451
|
+
export type CadreInvitationReach =
|
|
2452
|
+
/** Another machine has a relayed (`/p2p-circuit`), public-name or public-IP WebSocket address. */
|
|
2453
|
+
'anywhere'
|
|
2454
|
+
/** Other machines are named, but only at private or loopback addresses: works on their network only. */
|
|
2455
|
+
| 'local-network'
|
|
2456
|
+
/** The bundle names no other machine at an address a phone can dial. */
|
|
2457
|
+
| 'issuer-only';
|
|
2281
2458
|
/** What `CadreNode.createCadreInvitation` returns: the bundle, and the same encoded for sharing. */
|
|
2282
2459
|
export interface CreateCadreInvitationResult {
|
|
2283
2460
|
invitation: CadreInvitation;
|
|
2284
|
-
/** `encodeCadreInvitation(invitation)`: base64url JSON for a QR code, a paste or a link. */
|
|
2461
|
+
/** `encodeCadreInvitation(invitation)`: `sereus-invite:1.` and base64url JSON, for a QR code, a paste or a link. */
|
|
2285
2462
|
encoded: string;
|
|
2463
|
+
/** Whether a device could redeem it once the minting machine is gone; see {@link CadreInvitationReach}. */
|
|
2464
|
+
reach: CadreInvitationReach;
|
|
2465
|
+
}
|
|
2466
|
+
/** How `CadreNode.redeemCadreInvitation` runs. */
|
|
2467
|
+
export interface RedeemCadreInvitationOptions {
|
|
2468
|
+
/**
|
|
2469
|
+
* Keep making passes over the bundle's addresses while every answer is retryable, until a
|
|
2470
|
+
* member accepts, one refuses finally, the invitation expires, or `signal` aborts.
|
|
2471
|
+
* Default false: one pass.
|
|
2472
|
+
*/
|
|
2473
|
+
waitForMember?: boolean;
|
|
2474
|
+
/** Ends the pause and the pass in flight; the call then throws the signal's reason. */
|
|
2475
|
+
signal?: AbortSignal;
|
|
2476
|
+
/** Called at each pass and each pause; an exception it throws is logged and ignored. */
|
|
2477
|
+
onProgress?: (progress: CadreJoinProgress) => void;
|
|
2286
2478
|
}
|
|
2479
|
+
/** A redemption's progress, as `RedeemCadreInvitationOptions.onProgress` reports it. */
|
|
2480
|
+
export type CadreJoinProgress = {
|
|
2481
|
+
state: 'redeeming';
|
|
2482
|
+
pass: number;
|
|
2483
|
+
} | {
|
|
2484
|
+
state: 'waiting';
|
|
2485
|
+
pass: number;
|
|
2486
|
+
/** Epoch ms of the next pass. */
|
|
2487
|
+
retryAtMs: number;
|
|
2488
|
+
/**
|
|
2489
|
+
* `'no-member-answered'`: every address failed to dial or answer. `'member-not-ready'`: at
|
|
2490
|
+
* least one member answered with a retryable refusal (issuer-unknown, busy, conflict, internal).
|
|
2491
|
+
*/
|
|
2492
|
+
reason: 'no-member-answered' | 'member-not-ready';
|
|
2493
|
+
outcomes: readonly CadreInviteAddressOutcome[];
|
|
2494
|
+
};
|
|
2287
2495
|
/** What `CadreNode.redeemCadreInvitation` returns once a member accepted. */
|
|
2288
2496
|
export interface RedeemCadreInvitationResult {
|
|
2289
2497
|
/** The member machine that admitted this device, when its address named one. */
|
package/dist/types.js
CHANGED
|
@@ -66,6 +66,16 @@ export const HIBERNATION_TIMEOUTS = {
|
|
|
66
66
|
* kept it (the same pair aborted at a 200ms stall only when the deadline was 300ms). An
|
|
67
67
|
* interval strictly above the deadline is what makes the 30 seconds real.
|
|
68
68
|
*
|
|
69
|
+
* WHY THE OTHER END'S PING HANDLER CAPS IT TOO. The node being pinged echoes through
|
|
70
|
+
* `@libp2p/ping`'s inbound handler, which aborts the ping stream when its own timer fires; the
|
|
71
|
+
* pinging node's monitor sees the reset and aborts the connection exactly as it would on its
|
|
72
|
+
* own timeout. So this deadline is only real up to the handler timeout of the node being
|
|
73
|
+
* pinged, which has to stay above it. The deployed relay sets its handler to 60 s for that
|
|
74
|
+
* reason (`ops/docker/libp2p-infra/src/main.ts`). Every cadre node's handler is Optimystic's
|
|
75
|
+
* bare `ping()`, `@libp2p/ping`'s 10 s, and nothing here can move it
|
|
76
|
+
* (`tickets/blocked/optimystic-ping-handler-timeout-below-the-monitor-deadline.md`): between
|
|
77
|
+
* two cadre nodes, a ping whose echo takes longer than 10 s still drops the connection.
|
|
78
|
+
*
|
|
69
79
|
* WHAT THE LINK NEEDS OF IT. One ping opens a fresh stream and echoes over it: a protocol
|
|
70
80
|
* negotiation plus the echo, two link round trips by `link-budget.ts`'s counts (a `newStream`
|
|
71
81
|
* over a relayed circuit measured 3016 ms at 1500 ms one-way). At the slowest link sereus
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAwFA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,QAAQ,EAAE;QACR,WAAW,EAAE,QAAQ,EAAS,aAAa;QAC3C,gBAAgB,EAAE,QAAQ,EAAI,kBAAkB;QAChD,eAAe,EAAE,QAAQ,EAAK,MAAM;QACpC,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,QAAQ,CAAE,MAAM;KACrC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,YAAY;QAC1C,gBAAgB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,wBAAwB;QAC1D,eAAe,EAAE,EAAE,GAAG,IAAI,EAAI,mBAAmB;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KACnD;IACD,UAAU,EAAE;QACV,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,WAAW;QACzC,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAG,uBAAuB;QACzD,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAI,kBAAkB;QACpD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB;KACxD;IACD,OAAO,EAAE;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,EAAQ,aAAa;QAC3C,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAG,wBAAwB;QACtD,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAG,eAAe;QACjD,oBAAoB,EAAE,CAAC;QACvB,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;KAC5D;CACF,CAAC;AAweF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC,MAAM,CAAC;IACtD,uFAAuF;IACvF,mFAAmF;IACnF,YAAY,EAAE,KAAM;IACpB,kFAAkF;IAClF,kFAAkF;IAClF,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAM,EAAE,UAAU,EAAE,KAAM,EAAE,CAAC;CACjC,CAAC,CAAC;AAmBzC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AAYnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,2BAA2B,EAC3B,sBAAsB,EACtB,2BAA2B,EAC3B,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,+BAA+B,CAAC;AAEvC;;;;;GAKG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC"}
|