@serfab/cadre-core 0.7.1 → 0.8.1
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 +9 -8
- package/dist/authority-key.d.ts +41 -0
- package/dist/authority-key.js +52 -0
- package/dist/authority-key.js.map +1 -0
- package/dist/cadre-node.d.ts +770 -11
- package/dist/cadre-node.js +1900 -88
- package/dist/cadre-node.js.map +1 -1
- package/dist/canonical-datetime.d.ts +33 -0
- package/dist/canonical-datetime.js +38 -0
- package/dist/canonical-datetime.js.map +1 -0
- package/dist/canonical-json.d.ts +12 -0
- package/dist/canonical-json.js +33 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/control-cohort.d.ts +63 -0
- package/dist/control-cohort.js +80 -0
- package/dist/control-cohort.js.map +1 -0
- package/dist/control-database.d.ts +259 -5
- package/dist/control-database.js +541 -128
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +89 -0
- package/dist/control-formation-recorder.js +139 -0
- package/dist/control-formation-recorder.js.map +1 -0
- package/dist/control-schema.d.ts +12 -0
- package/dist/control-schema.js +199 -0
- package/dist/control-schema.js.map +1 -0
- package/dist/control-stream.d.ts +54 -0
- package/dist/control-stream.js +104 -0
- package/dist/control-stream.js.map +1 -0
- package/dist/device-token.d.ts +50 -0
- package/dist/device-token.js +66 -0
- package/dist/device-token.js.map +1 -0
- package/dist/diagnostics/connection-path.d.ts +118 -0
- package/dist/diagnostics/connection-path.js +204 -0
- package/dist/diagnostics/connection-path.js.map +1 -0
- package/dist/diagnostics/webrtc-turn-tracker.d.ts +50 -0
- package/dist/diagnostics/webrtc-turn-tracker.js +196 -0
- package/dist/diagnostics/webrtc-turn-tracker.js.map +1 -0
- package/dist/hibernation-manager.d.ts +79 -0
- package/dist/hibernation-manager.js +173 -23
- package/dist/hibernation-manager.js.map +1 -1
- package/dist/index.d.ts +25 -4
- package/dist/index.js +59 -4
- package/dist/index.js.map +1 -1
- package/dist/key-store-file.d.ts +52 -0
- package/dist/key-store-file.js +194 -0
- package/dist/key-store-file.js.map +1 -0
- package/dist/key-store.d.ts +75 -0
- package/dist/key-store.js +66 -0
- package/dist/key-store.js.map +1 -0
- package/dist/peer-authorization.d.ts +26 -0
- package/dist/peer-authorization.js +40 -0
- package/dist/peer-authorization.js.map +1 -0
- package/dist/peer-record.d.ts +89 -0
- package/dist/peer-record.js +117 -0
- package/dist/peer-record.js.map +1 -0
- package/dist/push-credentials.d.ts +34 -0
- package/dist/push-credentials.js +81 -0
- package/dist/push-credentials.js.map +1 -0
- package/dist/push-fanout.d.ts +137 -0
- package/dist/push-fanout.js +197 -0
- package/dist/push-fanout.js.map +1 -0
- package/dist/push-notifier-apns.d.ts +53 -0
- package/dist/push-notifier-apns.js +195 -0
- package/dist/push-notifier-apns.js.map +1 -0
- package/dist/push-notifier-fcm.d.ts +38 -0
- package/dist/push-notifier-fcm.js +183 -0
- package/dist/push-notifier-fcm.js.map +1 -0
- package/dist/push-notifier-shared.d.ts +18 -0
- package/dist/push-notifier-shared.js +25 -0
- package/dist/push-notifier-shared.js.map +1 -0
- package/dist/push-notifier.d.ts +71 -0
- package/dist/push-notifier.js +50 -0
- package/dist/push-notifier.js.map +1 -0
- package/dist/schema-verification.d.ts +11 -2
- package/dist/schema-verification.js +15 -4
- package/dist/schema-verification.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +197 -9
- package/dist/seed-bootstrap.js +396 -137
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.d.ts +63 -0
- package/dist/seed-trust-policy.js +56 -0
- package/dist/seed-trust-policy.js.map +1 -0
- package/dist/strand-addr-protocol.d.ts +132 -0
- package/dist/strand-addr-protocol.js +313 -0
- package/dist/strand-addr-protocol.js.map +1 -0
- package/dist/strand-cohort.d.ts +54 -0
- package/dist/strand-cohort.js +38 -0
- package/dist/strand-cohort.js.map +1 -0
- package/dist/strand-database.d.ts +54 -6
- package/dist/strand-database.js +88 -100
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-formation-manager.d.ts +79 -19
- package/dist/strand-formation-manager.js +196 -104
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +162 -0
- package/dist/strand-formation-protocol.js +279 -0
- package/dist/strand-formation-protocol.js.map +1 -0
- package/dist/strand-instance-manager.d.ts +73 -4
- package/dist/strand-instance-manager.js +167 -41
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-member-key.d.ts +29 -0
- package/dist/strand-member-key.js +38 -0
- package/dist/strand-member-key.js.map +1 -0
- package/dist/strand-member-registry.d.ts +98 -0
- package/dist/strand-member-registry.js +129 -0
- package/dist/strand-member-registry.js.map +1 -0
- package/dist/strand-membership-writer.d.ts +361 -0
- package/dist/strand-membership-writer.js +449 -0
- package/dist/strand-membership-writer.js.map +1 -0
- package/dist/strand-solicitation.d.ts +77 -2
- package/dist/strand-solicitation.js +25 -4
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-wake-payload.d.ts +30 -0
- package/dist/strand-wake-payload.js +20 -0
- package/dist/strand-wake-payload.js.map +1 -0
- package/dist/strand-wake-protocol.d.ts +114 -0
- package/dist/strand-wake-protocol.js +257 -0
- package/dist/strand-wake-protocol.js.map +1 -0
- package/dist/strand-watcher.d.ts +6 -2
- package/dist/strand-watcher.js +57 -17
- package/dist/strand-watcher.js.map +1 -1
- package/dist/types.d.ts +406 -23
- package/dist/types.js +22 -5
- package/dist/types.js.map +1 -1
- package/package.json +14 -8
- package/src/authority-key.ts +68 -0
- package/src/cadre-node.ts +2937 -948
- package/src/canonical-datetime.ts +39 -0
- package/src/canonical-json.ts +30 -0
- package/src/control-cohort.ts +103 -0
- package/src/control-database.ts +931 -383
- package/src/control-formation-recorder.ts +151 -0
- package/src/control-schema.ts +198 -0
- package/src/control-stream.ts +128 -0
- package/src/device-token.ts +89 -0
- package/src/diagnostics/connection-path.ts +277 -0
- package/src/diagnostics/webrtc-turn-tracker.ts +222 -0
- package/src/hibernation-manager.ts +197 -28
- package/src/index.ts +273 -79
- package/src/key-store-file.ts +203 -0
- package/src/key-store.ts +99 -0
- package/src/peer-authorization.ts +53 -0
- package/src/peer-record.ts +146 -0
- package/src/push-credentials.ts +84 -0
- package/src/push-fanout.ts +272 -0
- package/src/push-notifier-apns.ts +243 -0
- package/src/push-notifier-fcm.ts +221 -0
- package/src/push-notifier-shared.ts +28 -0
- package/src/push-notifier.ts +93 -0
- package/src/schema-verification.ts +18 -4
- package/src/seed-bootstrap.ts +464 -188
- package/src/seed-trust-policy.ts +107 -0
- package/src/strand-addr-protocol.ts +410 -0
- package/src/strand-cohort.ts +77 -0
- package/src/strand-database.ts +113 -141
- package/src/strand-formation-manager.ts +233 -142
- package/src/strand-formation-protocol.ts +391 -0
- package/src/strand-instance-manager.ts +207 -56
- package/src/strand-member-key.ts +39 -0
- package/src/strand-member-registry.ts +177 -0
- package/src/strand-membership-writer.ts +640 -0
- package/src/strand-solicitation.ts +93 -4
- package/src/strand-wake-payload.ts +32 -0
- package/src/strand-wake-protocol.ts +331 -0
- package/src/strand-watcher.ts +61 -17
- package/src/types.ts +1012 -582
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native cadre-core strand-formation transport.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the non-deprecated `seed-bootstrap.ts` protocol service: a dedicated
|
|
5
|
+
* libp2p protocol id, length-prefixed JSON frames, and small single-purpose
|
|
6
|
+
* session helpers. It replaces the deprecated `@serfab/strand-proto` transport,
|
|
7
|
+
* carrying the caller's REAL invitation token + disclosure and BOTH parties'
|
|
8
|
+
* real cadre peer addresses end-to-end (no `{ partyId: sessionId }` / `cadre-*.local`
|
|
9
|
+
* placeholders), and validating the responder's result on the initiator side.
|
|
10
|
+
*
|
|
11
|
+
* Provisioning flow (`responderCreates`, 2 messages): the responder provisions (or, for
|
|
12
|
+
* provision-then-record, resolves + records consent against) the strand and returns the
|
|
13
|
+
* result on approval.
|
|
14
|
+
*
|
|
15
|
+
* Cadre-disclosure timing (see docs/strand-proto.md "Security & Privacy"): the
|
|
16
|
+
* responder reveals its own party id + cadre addresses — and, for a closed strand
|
|
17
|
+
* returned via provision-then-record, that strand's membership key — ONLY after the
|
|
18
|
+
* token and disclosure validate; a rejection discloses none of them.
|
|
19
|
+
*/
|
|
20
|
+
import debug from 'debug';
|
|
21
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
|
22
|
+
import { writeFrame, withTimeout } from './control-stream.js';
|
|
23
|
+
const log = debug('sereus:cadre:formation-proto');
|
|
24
|
+
/** Protocol id for the native formation transport (parallel to `/sereus/seed/1.0.0`). */
|
|
25
|
+
export const FORMATION_PROTOCOL = '/sereus/formation/1.0.0';
|
|
26
|
+
/** Maximum formation message size (1MB). */
|
|
27
|
+
const MAX_FORMATION_MSG_SIZE = 1024 * 1024;
|
|
28
|
+
/** Default whole-session timeout (ms). */
|
|
29
|
+
const DEFAULT_SESSION_TIMEOUT_MS = 30000;
|
|
30
|
+
/** Default per-step (single read/write) timeout (ms). */
|
|
31
|
+
const DEFAULT_STEP_TIMEOUT_MS = 5000;
|
|
32
|
+
/** Default cap on concurrent inbound formation sessions. */
|
|
33
|
+
const DEFAULT_MAX_CONCURRENT_SESSIONS = 100;
|
|
34
|
+
// ── Stream framing helpers ───────────────────────────────────────────────────
|
|
35
|
+
/**
|
|
36
|
+
* Reads length-prefixed JSON frames from a libp2p stream one frame at a time.
|
|
37
|
+
*
|
|
38
|
+
* Unlike seed delivery (which reads a stream to EOF then parses once), formation
|
|
39
|
+
* is request/response on a single live stream, so reading must stop at each frame
|
|
40
|
+
* boundary. The reader buffers across chunk boundaries and retains any overflow
|
|
41
|
+
* (a following frame coalesced into the same chunk) for the next read.
|
|
42
|
+
*/
|
|
43
|
+
class FrameReader {
|
|
44
|
+
constructor(stream, maxLength = MAX_FORMATION_MSG_SIZE) {
|
|
45
|
+
this.buffer = new Uint8Array(0);
|
|
46
|
+
this.iterator = stream[Symbol.asyncIterator]();
|
|
47
|
+
this.maxLength = maxLength;
|
|
48
|
+
}
|
|
49
|
+
append(chunk) {
|
|
50
|
+
const next = new Uint8Array(this.buffer.length + chunk.length);
|
|
51
|
+
next.set(this.buffer, 0);
|
|
52
|
+
next.set(chunk, this.buffer.length);
|
|
53
|
+
this.buffer = next;
|
|
54
|
+
}
|
|
55
|
+
/** Pull chunks until the buffer holds ≥ `need` bytes; false if the stream ended first. */
|
|
56
|
+
async fill(need) {
|
|
57
|
+
while (this.buffer.length < need) {
|
|
58
|
+
const { value, done } = await this.iterator.next();
|
|
59
|
+
if (done)
|
|
60
|
+
return false;
|
|
61
|
+
const bytes = value instanceof Uint8Array
|
|
62
|
+
? value
|
|
63
|
+
: value.subarray();
|
|
64
|
+
this.append(bytes);
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
async read() {
|
|
69
|
+
if (!(await this.fill(4))) {
|
|
70
|
+
throw new Error('Formation stream closed before length prefix');
|
|
71
|
+
}
|
|
72
|
+
const length = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength).getUint32(0, false);
|
|
73
|
+
if (length > this.maxLength) {
|
|
74
|
+
throw new Error(`Formation frame declares length ${length} exceeding max ${this.maxLength}`);
|
|
75
|
+
}
|
|
76
|
+
if (!(await this.fill(4 + length))) {
|
|
77
|
+
throw new Error(`Formation frame declares length ${length} but stream ended early`);
|
|
78
|
+
}
|
|
79
|
+
const json = new TextDecoder().decode(this.buffer.subarray(4, 4 + length));
|
|
80
|
+
this.buffer = this.buffer.subarray(4 + length);
|
|
81
|
+
return JSON.parse(json);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ── Result validation ────────────────────────────────────────────────────────
|
|
85
|
+
/** Matches the deprecated strand-proto placeholder cadre addrs (`cadre-a-1.local`, …). */
|
|
86
|
+
const PLACEHOLDER_CADRE_ADDR = /^cadre-[ab]-\d+\.local$/;
|
|
87
|
+
/**
|
|
88
|
+
* Structural check on a `responderCreates` result: the responder must have approved,
|
|
89
|
+
* disclosed a non-empty real identity + cadre (not the deprecated `cadre-*.local`
|
|
90
|
+
* placeholders), and returned a strand vouched for by the responder party with a real id.
|
|
91
|
+
*
|
|
92
|
+
* `createdBy: 'responder'` means "the responder party vouches for / returns this strand."
|
|
93
|
+
* Under provision-then-record that strand was minted authority-signed earlier (not created
|
|
94
|
+
* in-session), but it is still the responder party returning its own strand, so the marker
|
|
95
|
+
* — and this structural validator — stay unchanged.
|
|
96
|
+
*
|
|
97
|
+
* The behavioral floor for the initiator: a responder that returns an arbitrary/empty
|
|
98
|
+
* `strandId` or omits its disclosed identity is rejected, not silently accepted.
|
|
99
|
+
*/
|
|
100
|
+
export function isValidResponderCreatesResult(response) {
|
|
101
|
+
if (!response.approved)
|
|
102
|
+
return false;
|
|
103
|
+
if (!response.partyId)
|
|
104
|
+
return false;
|
|
105
|
+
const addrs = response.cadrePeerAddrs;
|
|
106
|
+
if (!addrs || addrs.length === 0)
|
|
107
|
+
return false;
|
|
108
|
+
if (addrs.some((a) => PLACEHOLDER_CADRE_ADDR.test(a)))
|
|
109
|
+
return false;
|
|
110
|
+
const provision = response.provisionResult;
|
|
111
|
+
if (!provision?.strand?.strandId)
|
|
112
|
+
return false;
|
|
113
|
+
if (provision.strand.createdBy !== 'responder')
|
|
114
|
+
return false;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Responder side of the native formation protocol. Registers a libp2p handler and
|
|
119
|
+
* drives each inbound stream through token + disclosure validation, provisioning,
|
|
120
|
+
* and result delivery — enforcing the cadre-disclosure timing rule (responder cadre
|
|
121
|
+
* is revealed only after validation; rejections disclose nothing).
|
|
122
|
+
*/
|
|
123
|
+
export class FormationListener {
|
|
124
|
+
constructor(options) {
|
|
125
|
+
this.registered = new Set();
|
|
126
|
+
this.activeSessions = 0;
|
|
127
|
+
this.sessionCounter = 0;
|
|
128
|
+
this.options = options;
|
|
129
|
+
this.sessionTimeoutMs = options.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
|
|
130
|
+
this.stepTimeoutMs = options.stepTimeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
131
|
+
this.maxConcurrentSessions = options.maxConcurrentSessions ?? DEFAULT_MAX_CONCURRENT_SESSIONS;
|
|
132
|
+
}
|
|
133
|
+
/** Number of in-flight inbound sessions. */
|
|
134
|
+
get activeCount() {
|
|
135
|
+
return this.activeSessions;
|
|
136
|
+
}
|
|
137
|
+
register(node, protocolId = FORMATION_PROTOCOL) {
|
|
138
|
+
if (this.registered.has(node)) {
|
|
139
|
+
log('node already registered');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
void node.handle(protocolId, async (rawStream, _connection) => {
|
|
143
|
+
await this.handleStream(rawStream);
|
|
144
|
+
});
|
|
145
|
+
this.registered.add(node);
|
|
146
|
+
log('formation listener registered (%s)', protocolId);
|
|
147
|
+
}
|
|
148
|
+
unregister(node, protocolId = FORMATION_PROTOCOL) {
|
|
149
|
+
if (!this.registered.has(node))
|
|
150
|
+
return;
|
|
151
|
+
void node.unhandle(protocolId);
|
|
152
|
+
this.registered.delete(node);
|
|
153
|
+
log('formation listener unregistered (%s)', protocolId);
|
|
154
|
+
}
|
|
155
|
+
async handleStream(stream) {
|
|
156
|
+
if (this.activeSessions >= this.maxConcurrentSessions) {
|
|
157
|
+
const rejection = { approved: false, reason: 'Too many concurrent formation sessions' };
|
|
158
|
+
try {
|
|
159
|
+
writeFrame(stream, rejection);
|
|
160
|
+
}
|
|
161
|
+
catch { /* best effort */ }
|
|
162
|
+
try {
|
|
163
|
+
await stream.close();
|
|
164
|
+
}
|
|
165
|
+
catch { /* ignore */ }
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const id = ++this.sessionCounter;
|
|
169
|
+
this.activeSessions++;
|
|
170
|
+
try {
|
|
171
|
+
await withTimeout(this.sessionTimeoutMs, `Formation session#${id}`, () => this.runSession(id, stream));
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
log('formation session #%d failed: %o', id, err);
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
this.activeSessions--;
|
|
178
|
+
try {
|
|
179
|
+
await stream.close();
|
|
180
|
+
}
|
|
181
|
+
catch { /* ignore */ }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async runSession(id, stream) {
|
|
185
|
+
// Track whether ANY frame has been written so the catch below can convert an
|
|
186
|
+
// unexpected internal error into a non-disclosing rejection ONLY when nothing has
|
|
187
|
+
// gone out yet. This closes the "stream closed with no result frame" class of bug.
|
|
188
|
+
let wroteFrame = false;
|
|
189
|
+
const send = (msg) => {
|
|
190
|
+
writeFrame(stream, msg);
|
|
191
|
+
wroteFrame = true;
|
|
192
|
+
};
|
|
193
|
+
try {
|
|
194
|
+
const reader = new FrameReader(stream);
|
|
195
|
+
const contact = await withTimeout(this.stepTimeoutMs, `Formation await-contact#${id}`, () => reader.read());
|
|
196
|
+
log('formation session #%d contact: token=%s party=%s', id, contact.token, contact.partyId);
|
|
197
|
+
const tokenResult = await this.options.validateToken(contact.token);
|
|
198
|
+
if (!tokenResult.valid) {
|
|
199
|
+
send({ approved: false, reason: 'Invalid token' });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const disclosureOk = await this.options.validateDisclosure(contact.token, contact.disclosure);
|
|
203
|
+
if (!disclosureOk) {
|
|
204
|
+
send({ approved: false, reason: 'Invalid disclosure' });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const outcome = await this.options.provisionStrand(contact.token, contact.partyId, contact.disclosure);
|
|
208
|
+
if (!outcome.approved) {
|
|
209
|
+
// A post-validation rejection still discloses NEITHER identity NOR cadre,
|
|
210
|
+
// exactly like the token/disclosure rejections above.
|
|
211
|
+
send({ approved: false, reason: outcome.reason });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Validation + provisioning passed → safe to disclose responder identity/cadre.
|
|
215
|
+
const identity = this.options.getResponderIdentity();
|
|
216
|
+
send({
|
|
217
|
+
approved: true,
|
|
218
|
+
partyId: identity.partyId,
|
|
219
|
+
cadrePeerAddrs: identity.cadrePeerAddrs,
|
|
220
|
+
provisionResult: outcome.result
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
// Defense-in-depth: if an unexpected internal error escapes BEFORE any frame was
|
|
225
|
+
// written (e.g. a future provisionStrand-hook bug), convert it into a non-disclosing
|
|
226
|
+
// protocol rejection so the initiator sees a clean error instead of a read-error/
|
|
227
|
+
// timeout. If a frame was already sent, leave the stream as-is and let handleStream
|
|
228
|
+
// log + close. Re-throw either way so the failure is still recorded — this is a
|
|
229
|
+
// deliberate, logged conversion, not silent.
|
|
230
|
+
if (!wroteFrame) {
|
|
231
|
+
const internalError = { approved: false, reason: 'Internal formation error' };
|
|
232
|
+
try {
|
|
233
|
+
writeFrame(stream, internalError);
|
|
234
|
+
}
|
|
235
|
+
catch { /* stream already broken */ }
|
|
236
|
+
}
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Initiator side of the native formation protocol. Dials the responder, sends the
|
|
243
|
+
* contact (carrying the real disclosure/token/cadre), validates the responder's
|
|
244
|
+
* result, and returns the strand the responder provisioned.
|
|
245
|
+
*/
|
|
246
|
+
export async function dialFormation(node, options) {
|
|
247
|
+
if (options.responderAddrs.length === 0) {
|
|
248
|
+
throw new Error('No responder addresses available for formation');
|
|
249
|
+
}
|
|
250
|
+
const protocolId = options.protocolId ?? FORMATION_PROTOCOL;
|
|
251
|
+
const sessionTimeoutMs = options.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
|
|
252
|
+
const stepTimeoutMs = options.stepTimeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
253
|
+
const addr = multiaddr(options.responderAddrs[0]);
|
|
254
|
+
return withTimeout(sessionTimeoutMs, 'Formation dial', async () => {
|
|
255
|
+
const rawStream = await withTimeout(stepTimeoutMs, 'Formation dial-connect', async () => node.dialProtocol(addr, protocolId));
|
|
256
|
+
const stream = rawStream;
|
|
257
|
+
try {
|
|
258
|
+
const reader = new FrameReader(stream);
|
|
259
|
+
writeFrame(stream, options.contact);
|
|
260
|
+
const response = await withTimeout(stepTimeoutMs, 'Formation await-response', () => reader.read());
|
|
261
|
+
if (!response.approved) {
|
|
262
|
+
throw new Error(`Formation rejected: ${response.reason ?? 'no reason provided'}`);
|
|
263
|
+
}
|
|
264
|
+
const ok = await options.validateResponse(response);
|
|
265
|
+
if (!ok)
|
|
266
|
+
throw new Error('Responder result failed validation');
|
|
267
|
+
if (!response.provisionResult)
|
|
268
|
+
throw new Error('Missing provision result for responderCreates mode');
|
|
269
|
+
return response.provisionResult;
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
try {
|
|
273
|
+
await stream.close();
|
|
274
|
+
}
|
|
275
|
+
catch { /* ignore */ }
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=strand-formation-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strand-formation-protocol.js","sourceRoot":"","sources":["../src/strand-formation-protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,18 +12,46 @@ export interface StartStrandConfig {
|
|
|
12
12
|
profile: NodeProfile;
|
|
13
13
|
defaultLatencyHint: LatencyHint;
|
|
14
14
|
privateKey?: PrivateKey;
|
|
15
|
+
/** Cohort-derived discovery seed (multiaddr strings). Defaults to [] when omitted. */
|
|
16
|
+
bootstrapNodes?: string[];
|
|
15
17
|
/**
|
|
16
18
|
* Lifecycle mode for this strand; selects the default transactor used by the
|
|
17
|
-
* StrandDatabase.
|
|
19
|
+
* StrandDatabase. When omitted, the StrandDatabase falls back to `'networked'`;
|
|
20
|
+
* callers (CadreNode) infer it from cohort membership before reaching here.
|
|
18
21
|
*/
|
|
19
22
|
mode?: StrandMode;
|
|
23
|
+
/**
|
|
24
|
+
* Require a valid author signature on the sApp schema before bring-up.
|
|
25
|
+
* Defaults to true (fail closed) when omitted; set false only for dev/test
|
|
26
|
+
* with unsigned demo schemas. Mirrors {@link CadreNodeConfig.requireSignedSchemas}.
|
|
27
|
+
*/
|
|
28
|
+
requireSignedSchemas?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Whether this node founds the strand (vs. joins it). Forwarded to the
|
|
31
|
+
* StrandDatabase so the founder bootstrap (Header, founding Member/Authority)
|
|
32
|
+
* runs once at bring-up. Joiners leave this unset and write nothing. See
|
|
33
|
+
* {@link StrandConfig.founder}.
|
|
34
|
+
*/
|
|
35
|
+
founder?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Volatile inputs re-resolved when resuming a quiesced strand. These may have
|
|
39
|
+
* changed since the strand first launched — the cohort discovery seed grows as
|
|
40
|
+
* peers are learned, and cohort membership can push a strand `bootstrap → networked`.
|
|
41
|
+
*/
|
|
42
|
+
export interface ResumeStrandOverrides {
|
|
43
|
+
/** Freshly-resolved cohort discovery seed (multiaddr strings). */
|
|
44
|
+
bootstrapNodes?: string[];
|
|
45
|
+
/** Freshly-resolved lifecycle mode. */
|
|
46
|
+
mode?: StrandMode;
|
|
20
47
|
}
|
|
21
48
|
/**
|
|
22
49
|
* Get the isolated storage path for a specific strand.
|
|
23
50
|
*
|
|
24
|
-
* @deprecated This
|
|
25
|
-
* Use a storage provider factory function instead, which
|
|
26
|
-
* create strand-specific storage paths using
|
|
51
|
+
* @deprecated This helper is Node-only and throws in React Native (it assumes a
|
|
52
|
+
* filesystem layout). Use a storage provider factory function instead, which
|
|
53
|
+
* receives the strandId and can create strand-specific storage paths using
|
|
54
|
+
* platform-appropriate methods.
|
|
27
55
|
*
|
|
28
56
|
* @example
|
|
29
57
|
* // Instead of using getStrandStoragePath, use a storage provider factory:
|
|
@@ -38,6 +66,12 @@ export declare function getStrandStoragePath(basePath: string, strandId: string)
|
|
|
38
66
|
*/
|
|
39
67
|
export declare class StrandInstanceManager {
|
|
40
68
|
private instances;
|
|
69
|
+
/**
|
|
70
|
+
* Retained launch config per strand, captured in `startStrand` and cleared in
|
|
71
|
+
* `stopStrand`. `resumeStrand` reuses it to rebuild a quiesced strand's runtime
|
|
72
|
+
* without the caller re-threading storage/network/profile/key/sApp config.
|
|
73
|
+
*/
|
|
74
|
+
private launchConfigs;
|
|
41
75
|
private stopping;
|
|
42
76
|
constructor();
|
|
43
77
|
/**
|
|
@@ -56,6 +90,41 @@ export declare class StrandInstanceManager {
|
|
|
56
90
|
* Start a new strand instance
|
|
57
91
|
*/
|
|
58
92
|
startStrand(config: StartStrandConfig): Promise<StrandInstance>;
|
|
93
|
+
/**
|
|
94
|
+
* Build (or rebuild) the libp2p node + StrandDatabase for an instance and
|
|
95
|
+
* attach them, transitioning it to `active`. Shared by `startStrand` (fresh
|
|
96
|
+
* launch) and `resumeStrand` (rehydrating a quiesced instance). Reads all
|
|
97
|
+
* volatile inputs (bootstrapNodes, mode, storage, network, profile,
|
|
98
|
+
* privateKey, sApp config) from `config`, so the caller controls the
|
|
99
|
+
* cohort-derived values.
|
|
100
|
+
*/
|
|
101
|
+
private buildStrandRuntime;
|
|
102
|
+
/**
|
|
103
|
+
* Release an instance's strand-network runtime: close the StrandDatabase, then
|
|
104
|
+
* stop the libp2p node (construction order in reverse), clearing both fields
|
|
105
|
+
* and zeroing connectedPeers. Tolerant of partially-built state — either handle
|
|
106
|
+
* may be absent — so it doubles as rollback for a failed `buildStrandRuntime`.
|
|
107
|
+
* Shared by `quiesceStrand`, `stopStrand`, and that rollback path.
|
|
108
|
+
*/
|
|
109
|
+
private releaseRuntime;
|
|
110
|
+
/**
|
|
111
|
+
* Quiesce a strand: release its strand-network resources (stop the libp2p node,
|
|
112
|
+
* close the StrandDatabase) while RETAINING the instance record — identity,
|
|
113
|
+
* sAppInfo, keys, latency hint, metadata — and its launch config so it can be
|
|
114
|
+
* resumed later. Mechanically this is `stopStrand` minus the instance/config
|
|
115
|
+
* deletion. The caller sets the post-quiesce status (e.g. `hibernating`).
|
|
116
|
+
* No-ops when the strand is missing or already quiesced.
|
|
117
|
+
*/
|
|
118
|
+
quiesceStrand(strandId: string): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Resume a previously-quiesced strand: rebuild its libp2p node + StrandDatabase
|
|
121
|
+
* from the retained launch config and re-attach them, transitioning it back to
|
|
122
|
+
* `active`. `overrides` re-applies volatile inputs that may have changed since
|
|
123
|
+
* launch (cohort `bootstrapNodes`, lifecycle `mode`) and updates the retained
|
|
124
|
+
* config so a later resume reuses the latest values. Returns the live instance
|
|
125
|
+
* unchanged if it is already running.
|
|
126
|
+
*/
|
|
127
|
+
resumeStrand(strandId: string, overrides?: ResumeStrandOverrides): Promise<StrandInstance>;
|
|
59
128
|
/**
|
|
60
129
|
* Stop a strand instance
|
|
61
130
|
*/
|