@serfab/cadre-core 1.17.0 → 1.18.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 +3 -2
- package/dist/cadre-invite-protocol.d.ts +35 -13
- package/dist/cadre-invite-protocol.js +90 -25
- package/dist/cadre-invite-protocol.js.map +1 -1
- package/dist/cadre-node.d.ts +586 -255
- package/dist/cadre-node.js +1176 -564
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-cohort.d.ts +66 -9
- package/dist/control-cohort.js +67 -9
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +451 -193
- package/dist/control-database.js +701 -359
- package/dist/control-database.js.map +1 -1
- package/dist/control-formation-recorder.d.ts +46 -43
- package/dist/control-formation-recorder.js +77 -78
- package/dist/control-formation-recorder.js.map +1 -1
- package/dist/control-protocol-guard.d.ts +6 -0
- package/dist/control-protocol-guard.js +14 -2
- package/dist/control-protocol-guard.js.map +1 -1
- package/dist/control-schema-version.d.ts +48 -31
- package/dist/control-schema-version.js +67 -45
- package/dist/control-schema-version.js.map +1 -1
- package/dist/control-schema.d.ts +8 -8
- package/dist/control-schema.js +16 -16
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +42 -7
- package/dist/control-write-retry.js +87 -19
- package/dist/control-write-retry.js.map +1 -1
- package/dist/enrolled-machine-store.d.ts +3 -3
- package/dist/enrolled-machine-store.js +3 -3
- package/dist/formation-token.d.ts +48 -0
- package/dist/formation-token.js +26 -0
- package/dist/formation-token.js.map +1 -0
- package/dist/index.d.ts +14 -13
- package/dist/index.js +16 -13
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +26 -9
- package/dist/joined-strand-store.js +63 -24
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/link-budget.d.ts +9 -7
- package/dist/link-budget.js +9 -7
- package/dist/link-budget.js.map +1 -1
- package/dist/member-redemption.d.ts +15 -9
- package/dist/member-redemption.js +13 -8
- package/dist/member-redemption.js.map +1 -1
- package/dist/membership-view.d.ts +91 -0
- package/dist/membership-view.js +110 -0
- package/dist/membership-view.js.map +1 -0
- package/dist/owner-grant-protocol.d.ts +11 -7
- package/dist/owner-grant-protocol.js +31 -17
- package/dist/owner-grant-protocol.js.map +1 -1
- package/dist/peer-addr-book.d.ts +10 -1
- package/dist/peer-addr-book.js +4 -3
- package/dist/peer-addr-book.js.map +1 -1
- package/dist/peer-join-backfill.d.ts +89 -20
- package/dist/peer-join-backfill.js +265 -108
- package/dist/peer-join-backfill.js.map +1 -1
- package/dist/pending-join-runner.d.ts +48 -18
- package/dist/pending-join-runner.js +74 -56
- package/dist/pending-join-runner.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +47 -40
- package/dist/seed-bootstrap.js +66 -61
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/strand-database.d.ts +23 -2
- package/dist/strand-database.js +26 -6
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +176 -89
- package/dist/strand-first-sync-gate.js +288 -122
- package/dist/strand-first-sync-gate.js.map +1 -1
- package/dist/strand-formation-deadlines.d.ts +9 -9
- package/dist/strand-formation-deadlines.js +9 -9
- package/dist/strand-formation-manager.d.ts +23 -17
- package/dist/strand-formation-manager.js +46 -44
- package/dist/strand-formation-manager.js.map +1 -1
- package/dist/strand-formation-protocol.d.ts +5 -8
- package/dist/strand-formation-protocol.js +101 -16
- package/dist/strand-formation-protocol.js.map +1 -1
- package/dist/strand-instance-manager.d.ts +26 -17
- package/dist/strand-instance-manager.js +119 -50
- package/dist/strand-instance-manager.js.map +1 -1
- package/dist/strand-membership-reconciler.d.ts +16 -13
- package/dist/strand-membership-reconciler.js +30 -22
- package/dist/strand-membership-reconciler.js.map +1 -1
- package/dist/strand-membership-writer.d.ts +40 -28
- package/dist/strand-membership-writer.js +212 -153
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-move.js +5 -2
- package/dist/strand-move.js.map +1 -1
- package/dist/strand-revocation-enforcer.d.ts +134 -60
- package/dist/strand-revocation-enforcer.js +144 -71
- package/dist/strand-revocation-enforcer.js.map +1 -1
- package/dist/strand-solicitation.d.ts +50 -39
- package/dist/strand-solicitation.js +10 -3
- package/dist/strand-solicitation.js.map +1 -1
- package/dist/strand-watcher.d.ts +80 -13
- package/dist/strand-watcher.js +152 -48
- package/dist/strand-watcher.js.map +1 -1
- package/dist/table-change-watch.d.ts +63 -0
- package/dist/table-change-watch.js +209 -0
- package/dist/table-change-watch.js.map +1 -0
- package/dist/timeout-scheduler.d.ts +4 -3
- package/dist/timeout-scheduler.js +4 -3
- package/dist/timeout-scheduler.js.map +1 -1
- package/dist/types.d.ts +90 -49
- package/dist/types.js +4 -4
- package/dist/types.js.map +1 -1
- package/package.json +8 -8
- package/src/cadre-invite-protocol.ts +119 -31
- package/src/cadre-node.ts +1282 -584
- package/src/control-cohort.ts +86 -9
- package/src/control-database.ts +848 -403
- package/src/control-formation-recorder.ts +359 -353
- package/src/control-protocol-guard.ts +16 -2
- package/src/control-schema-version.ts +101 -51
- package/src/control-schema.ts +16 -16
- package/src/control-write-retry.ts +91 -19
- package/src/delegate-admission.ts +351 -351
- package/src/enrolled-machine-store.ts +3 -3
- package/src/formation-token.ts +63 -0
- package/src/index.ts +30 -17
- package/src/joined-strand-store.ts +69 -24
- package/src/link-budget.ts +9 -7
- package/src/member-redemption.ts +20 -13
- package/src/membership-view.ts +144 -0
- package/src/owner-grant-protocol.ts +33 -18
- package/src/peer-addr-book.ts +4 -3
- package/src/peer-join-backfill.ts +971 -761
- package/src/pending-join-runner.ts +76 -53
- package/src/seed-bootstrap.ts +72 -67
- package/src/strand-database.ts +352 -322
- package/src/strand-first-sync-gate.ts +334 -134
- package/src/strand-formation-deadlines.ts +227 -227
- package/src/strand-formation-manager.ts +731 -725
- package/src/strand-formation-protocol.ts +122 -24
- package/src/strand-instance-manager.ts +2092 -2026
- package/src/strand-membership-reconciler.ts +33 -25
- package/src/strand-membership-writer.ts +2093 -2019
- package/src/strand-move.ts +5 -2
- package/src/strand-revocation-enforcer.ts +740 -654
- package/src/strand-solicitation.ts +61 -34
- package/src/strand-watcher.ts +175 -56
- package/src/table-change-watch.ts +285 -0
- package/src/timeout-scheduler.ts +29 -28
- package/src/types.ts +89 -51
|
@@ -35,15 +35,15 @@ const log = debug('sereus:cadre:formation-deadlines');
|
|
|
35
35
|
* trip, budgeted as a request over an open stream (2) for the same headroom as every other
|
|
36
36
|
* one-exchange read in `link-budget.ts`.
|
|
37
37
|
* - **validation** and the reads inside **provisionWork** are budgeted at two consulting
|
|
38
|
-
* reads each, not one per read the code issues. What actually runs: validation is
|
|
39
|
-
* control reads (`
|
|
40
|
-
*
|
|
41
|
-
* (`StrandFormationManager.provisionAsResponder`)
|
|
42
|
-
* resolve the host strand, the
|
|
43
|
-
* count around the outside approval hook (an HTTP call, so its
|
|
44
|
-
* `DEFAULT_APPROVAL_TIMEOUT_MS` is link-independent and added flat), the
|
|
45
|
-
* `StrandPartyKey` to issue the joiner's membership invite
|
|
46
|
-
*
|
|
38
|
+
* reads each, not one per read the code issues. What actually runs: validation is two
|
|
39
|
+
* control reads (`readToken` reads the invite and, for a metered unexpired one, counts its
|
|
40
|
+
* usages) plus whatever the disclosure validator does; the bound provisioning path
|
|
41
|
+
* (`StrandFormationManager.provisionAsResponder`) acts on that read, reads the strand row
|
|
42
|
+
* with its stamp to resolve the host strand, the approver's `ValidationKey` and the seat
|
|
43
|
+
* count around the outside approval hook when the invite names one (an HTTP call, so its
|
|
44
|
+
* own `DEFAULT_APPROVAL_TIMEOUT_MS` is link-independent and added flat), and the host
|
|
45
|
+
* strand's `StrandPartyKey` to issue the joiner's membership invite; then one
|
|
46
|
+
* strand-database commit issues the invite.
|
|
47
47
|
* Every one of those is a read of this party's own control database, which in steady state
|
|
48
48
|
* touches held blocks and consults nobody (`cadre-consistency.md` → "Deadlines Over
|
|
49
49
|
* Optimystic's Reads and Commits"), so `R` is charged as headroom for the ones that do
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Libp2p } from '@libp2p/interface';
|
|
2
2
|
import type { OpenInvitation, FormStrandResult, StrandFormationDisclosure, StrandMembershipInvite } from './types.js';
|
|
3
|
-
import type { DisclosureValidator, FormationUsageRecorder, StrandProvisioner, FormationResponseValidator } from './strand-solicitation.js';
|
|
3
|
+
import type { BoundHostStrand, DisclosureValidator, FormationUsageRecorder, StrandProvisioner, FormationResponseValidator } from './strand-solicitation.js';
|
|
4
4
|
/**
|
|
5
5
|
* How long a formation-issued strand membership invitation stays redeemable (7 days).
|
|
6
6
|
* The responder's {@link StrandFormationManagerOptions.issueMembershipInvite} hook stamps
|
|
@@ -35,11 +35,12 @@ export declare const MEMBERSHIP_INVITE_UNAVAILABLE_REASON = "Strand membership i
|
|
|
35
35
|
export declare const HOST_STRAND_MUST_BE_RECREATED_REASON = "Host strand must be recreated";
|
|
36
36
|
/**
|
|
37
37
|
* Responder-side seam that issues a bound joiner's membership invitation — see
|
|
38
|
-
* {@link StrandFormationManagerOptions.issueMembershipInvite} for the contract. `
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* {@link StrandFormationManagerOptions.issueMembershipInvite} for the contract. `host` is the
|
|
39
|
+
* host strand as the session resolved it, so the issuer reads no `Strand` row of its own.
|
|
40
|
+
* `signal` is the responder's provisioning budget: the issuer stops waiting (and throws) once
|
|
41
|
+
* it aborts.
|
|
41
42
|
*/
|
|
42
|
-
export type MembershipInviteIssuer = (
|
|
43
|
+
export type MembershipInviteIssuer = (host: BoundHostStrand, signal?: AbortSignal) => Promise<StrandMembershipInvite | null>;
|
|
43
44
|
/**
|
|
44
45
|
* Configuration for StrandFormationManager
|
|
45
46
|
*/
|
|
@@ -113,7 +114,8 @@ export interface StrandFormationManagerOptions {
|
|
|
113
114
|
* `StrandPartyKey` lookup.
|
|
114
115
|
*
|
|
115
116
|
* Contract: return the issued invitation for a CLOSED host strand; return `null`
|
|
116
|
-
* for an open one (no members, nothing to invite into)
|
|
117
|
+
* for an open one (no members, nothing to invite into), told apart by the resolved
|
|
118
|
+
* host's `strandType`; THROW when a closed strand's
|
|
117
119
|
* invitation cannot be issued (runtime not live, no party key, strand DB write
|
|
118
120
|
* rejected) — the manager then rejects the whole redemption with
|
|
119
121
|
* {@link MEMBERSHIP_INVITE_UNAVAILABLE_REASON} BEFORE recording consent, so the
|
|
@@ -212,9 +214,10 @@ export declare class StrandFormationManager {
|
|
|
212
214
|
*/
|
|
213
215
|
private initiatorProvisionTimeoutMs;
|
|
214
216
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
217
|
+
* The session's one read of its token ({@link FormationUsageRecorder.readToken}), classified
|
|
218
|
+
* by {@link classifyTokenRead}: an expired or used-up invitation is `'token-spent'` (final);
|
|
219
|
+
* one with no row here is `'token-unknown'` (retryable — the row may not have replicated to
|
|
220
|
+
* this machine yet). A valid check carries the read on to {@link provisionAsResponder}.
|
|
218
221
|
*/
|
|
219
222
|
private validateToken;
|
|
220
223
|
private validateDisclosure;
|
|
@@ -224,9 +227,12 @@ export declare class StrandFormationManager {
|
|
|
224
227
|
* {@link ResponderProvisionOutcome} with `approved: false` — `runSession` turns that
|
|
225
228
|
* into a clean, non-disclosing reply instead of a dropped result frame.
|
|
226
229
|
*
|
|
230
|
+
* Every step acts on `read`, the token as {@link validateToken} read it for this session,
|
|
231
|
+
* and on the host strand as resolved from it; none reads the invite or the `Strand` row again.
|
|
232
|
+
*
|
|
227
233
|
* - **bound** (host strand present): provision-then-record, in three steps —
|
|
228
234
|
* (1) authorize ({@link authorizeBoundUsage}: the outside approval when the invite
|
|
229
|
-
* demands one, and a seat
|
|
235
|
+
* demands one, and a seat re-check after it), so a refused join writes nothing into the host
|
|
230
236
|
* strand; (2) issue the joiner's single-use strand membership invitation via the wired
|
|
231
237
|
* `issueMembershipInvite` seam ({@link issueBoundMembershipInvite}; a closed strand whose
|
|
232
238
|
* invitation cannot be issued rejects retryably HERE, before any consent row spends the
|
|
@@ -252,6 +258,12 @@ export declare class StrandFormationManager {
|
|
|
252
258
|
* not control-flow-by-exception.
|
|
253
259
|
*/
|
|
254
260
|
private provisionAsResponder;
|
|
261
|
+
/**
|
|
262
|
+
* The session's token read. {@link validateToken} takes one whenever a recorder is wired and
|
|
263
|
+
* the listener hands it over, so a missing one is a wiring fault: refused rather than letting
|
|
264
|
+
* the redemption fall through to a path that records no usage.
|
|
265
|
+
*/
|
|
266
|
+
private requireRead;
|
|
255
267
|
/**
|
|
256
268
|
* Authorize a BOUND redemption without writing it, through the recorder's optional
|
|
257
269
|
* {@link FormationUsageRecorder.authorizeUsage}. A recorder without it has nothing to ask up
|
|
@@ -288,7 +300,7 @@ export declare class StrandFormationManager {
|
|
|
288
300
|
* 2. else `strandProvisioner` present → the mock/transport-test contract: provision a bare
|
|
289
301
|
* strand, NO inline usage write (those callers record usage explicitly via
|
|
290
302
|
* `recordFormationComplete`, or assert transport invariants only). Threads the invite's
|
|
291
|
-
* REAL `sAppId
|
|
303
|
+
* REAL `sAppId` from the session's read (empty when there is none).
|
|
292
304
|
* 3. else → a structural placeholder (no recorder + no provisioner ⇒ no single-use semantics
|
|
293
305
|
* exist to enforce).
|
|
294
306
|
*
|
|
@@ -304,12 +316,6 @@ export declare class StrandFormationManager {
|
|
|
304
316
|
private provisionUnbound;
|
|
305
317
|
/** Wrap a provision result as an approving {@link ResponderProvisionOutcome}. */
|
|
306
318
|
private approve;
|
|
307
|
-
/**
|
|
308
|
-
* The invite's authoritative `sAppId` for the responder-provisions fallback, read back
|
|
309
|
-
* from the recorder's `isTokenValid` invitation (the real `FormationInvite.sAppId`).
|
|
310
|
-
* Empty string when no recorder is wired or the invitation omits it.
|
|
311
|
-
*/
|
|
312
|
-
private resolveInviteSAppId;
|
|
313
319
|
private validateResponse;
|
|
314
320
|
}
|
|
315
321
|
/**
|
|
@@ -6,6 +6,7 @@ import { FormationAbortedError, InvitationExhaustedError } from './control-datab
|
|
|
6
6
|
import { PreSplitStrandIdentityError } from './strand-membership-writer.js';
|
|
7
7
|
import { mintPlaceholderStrandId } from './strand-id.js';
|
|
8
8
|
import { canonicalJson } from './canonical-json.js';
|
|
9
|
+
import { classifyTokenRead } from './formation-token.js';
|
|
9
10
|
import { FormationListener, INVALID_TOKEN_REASON, dialFormationByMachine, isValidResponderCreatesResult, isWellFormedMembershipInvite } from './strand-formation-protocol.js';
|
|
10
11
|
import { formationDeadlines } from './strand-formation-deadlines.js';
|
|
11
12
|
const log = debug('sereus:cadre:formation-manager');
|
|
@@ -91,7 +92,7 @@ export class StrandFormationManager {
|
|
|
91
92
|
this.listener = new FormationListener({
|
|
92
93
|
validateToken: (token) => this.validateToken(token),
|
|
93
94
|
validateDisclosure: (token, disclosure) => this.validateDisclosure(token, disclosure),
|
|
94
|
-
provisionStrand: (contact, signal) => this.provisionAsResponder(contact, signal),
|
|
95
|
+
provisionStrand: (contact, signal, read) => this.provisionAsResponder(contact, signal, read),
|
|
95
96
|
getResponderIdentity: () => ({ partyId: this.partyId, cadrePeerAddrs: this.currentCadrePeerAddrs() }),
|
|
96
97
|
// Forwarded only when wired, so `FormationListenerOptions.resolveStrandAddrs`
|
|
97
98
|
// stays genuinely absent (and the listener short-circuits) for an unwired manager.
|
|
@@ -227,25 +228,21 @@ export class StrandFormationManager {
|
|
|
227
228
|
}
|
|
228
229
|
// ── Responder-side hooks ─────────────────────────────────────────────────────
|
|
229
230
|
/**
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
231
|
+
* The session's one read of its token ({@link FormationUsageRecorder.readToken}), classified
|
|
232
|
+
* by {@link classifyTokenRead}: an expired or used-up invitation is `'token-spent'` (final);
|
|
233
|
+
* one with no row here is `'token-unknown'` (retryable — the row may not have replicated to
|
|
234
|
+
* this machine yet). A valid check carries the read on to {@link provisionAsResponder}.
|
|
233
235
|
*/
|
|
234
236
|
async validateToken(token) {
|
|
235
237
|
if (!this.formationUsageRecorder) {
|
|
236
238
|
// No recorder configured — accept all tokens.
|
|
237
239
|
return { valid: true };
|
|
238
240
|
}
|
|
239
|
-
const
|
|
240
|
-
if (!
|
|
241
|
-
log('Token
|
|
242
|
-
return { valid: false, code: tokenCheck.reason === 'expired' ? 'token-spent' : 'token-unknown' };
|
|
241
|
+
const check = classifyTokenRead(await this.formationUsageRecorder.readToken(token), Date.now());
|
|
242
|
+
if (!check.valid) {
|
|
243
|
+
log('Token refused (%s): %s', check.code, token);
|
|
243
244
|
}
|
|
244
|
-
|
|
245
|
-
log('Token already used: %s', token);
|
|
246
|
-
return { valid: false, code: 'token-spent' };
|
|
247
|
-
}
|
|
248
|
-
return { valid: true };
|
|
245
|
+
return check;
|
|
249
246
|
}
|
|
250
247
|
async validateDisclosure(token, disclosure) {
|
|
251
248
|
if (!this.disclosureValidator) {
|
|
@@ -260,9 +257,12 @@ export class StrandFormationManager {
|
|
|
260
257
|
* {@link ResponderProvisionOutcome} with `approved: false` — `runSession` turns that
|
|
261
258
|
* into a clean, non-disclosing reply instead of a dropped result frame.
|
|
262
259
|
*
|
|
260
|
+
* Every step acts on `read`, the token as {@link validateToken} read it for this session,
|
|
261
|
+
* and on the host strand as resolved from it; none reads the invite or the `Strand` row again.
|
|
262
|
+
*
|
|
263
263
|
* - **bound** (host strand present): provision-then-record, in three steps —
|
|
264
264
|
* (1) authorize ({@link authorizeBoundUsage}: the outside approval when the invite
|
|
265
|
-
* demands one, and a seat
|
|
265
|
+
* demands one, and a seat re-check after it), so a refused join writes nothing into the host
|
|
266
266
|
* strand; (2) issue the joiner's single-use strand membership invitation via the wired
|
|
267
267
|
* `issueMembershipInvite` seam ({@link issueBoundMembershipInvite}; a closed strand whose
|
|
268
268
|
* invitation cannot be issued rejects retryably HERE, before any consent row spends the
|
|
@@ -287,7 +287,7 @@ export class StrandFormationManager {
|
|
|
287
287
|
* internal-error→protocol-rejection conversion (AGENTS.md: don't eat exceptions silently),
|
|
288
288
|
* not control-flow-by-exception.
|
|
289
289
|
*/
|
|
290
|
-
async provisionAsResponder(contact, signal) {
|
|
290
|
+
async provisionAsResponder(contact, signal, read) {
|
|
291
291
|
const token = contact.token;
|
|
292
292
|
// CANONICALLY serialized — both sides derive the identical string: this is the exact
|
|
293
293
|
// text the joiner signed (consent), the approver signs (vouch), and the recorder writes
|
|
@@ -300,12 +300,13 @@ export class StrandFormationManager {
|
|
|
300
300
|
}
|
|
301
301
|
const recorder = this.formationUsageRecorder;
|
|
302
302
|
const resolved = recorder?.resolveStrand
|
|
303
|
-
? await recorder.resolveStrand(token)
|
|
303
|
+
? await recorder.resolveStrand(this.requireRead(token, read))
|
|
304
304
|
: { kind: 'unbound' };
|
|
305
305
|
try {
|
|
306
306
|
switch (resolved.kind) {
|
|
307
307
|
case 'bound': {
|
|
308
|
-
// recorder
|
|
308
|
+
// recorder and read are guaranteed here: only resolveStrand can yield 'bound', and it
|
|
309
|
+
// ran with the read.
|
|
309
310
|
const authorized = await this.authorizeBoundUsage(recorder, {
|
|
310
311
|
token,
|
|
311
312
|
peerKey: contact.peerKey,
|
|
@@ -314,16 +315,17 @@ export class StrandFormationManager {
|
|
|
314
315
|
strandId: resolved.strandId,
|
|
315
316
|
disclosure: disclosureText,
|
|
316
317
|
signal
|
|
317
|
-
});
|
|
318
|
+
}, read, resolved);
|
|
318
319
|
// Issued only once authorized (a refused join writes nothing into the strand) and
|
|
319
320
|
// BEFORE consent is recorded (an issue failure leaves the token unspent, retryable).
|
|
320
321
|
// The remaining window — invite issued, then record() fails or aborts (a write that
|
|
321
|
-
// exhausted its retries, an abort,
|
|
322
|
-
// `ControlFormationUsageRecorder.assertSeatFree
|
|
323
|
-
//
|
|
324
|
-
//
|
|
322
|
+
// exhausted its retries, an abort, the same-node seat race noted at
|
|
323
|
+
// `ControlFormationUsageRecorder.assertSeatFree`, or the host strand's row removed
|
|
324
|
+
// since `resolveStrand` read it, which the `StrandExists` CHECK refuses at commit) —
|
|
325
|
+
// orphans a live `Strand.Invite` no joiner ever received; bounded deliberately by its
|
|
326
|
+
// expiry ({@link MEMBERSHIP_INVITE_TTL_MS}) rather than compensated, since nothing
|
|
325
327
|
// here can atomically un-issue a strand-DB row.
|
|
326
|
-
const issued = await this.issueBoundMembershipInvite(token, resolved
|
|
328
|
+
const issued = await this.issueBoundMembershipInvite(token, resolved, signal);
|
|
327
329
|
if (!issued.ok) {
|
|
328
330
|
return issued.rejection;
|
|
329
331
|
}
|
|
@@ -342,7 +344,7 @@ export class StrandFormationManager {
|
|
|
342
344
|
return { approved: false, code: 'host-strand-unavailable', reason: 'Host strand not yet available on this responder' };
|
|
343
345
|
}
|
|
344
346
|
case 'unbound':
|
|
345
|
-
return await this.provisionUnbound(contact, disclosureText, signal);
|
|
347
|
+
return await this.provisionUnbound(contact, disclosureText, signal, read);
|
|
346
348
|
}
|
|
347
349
|
}
|
|
348
350
|
catch (err) {
|
|
@@ -371,14 +373,25 @@ export class StrandFormationManager {
|
|
|
371
373
|
return { approved: false, code: 'conflict', reason: 'Formation conflict, retry' };
|
|
372
374
|
}
|
|
373
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* The session's token read. {@link validateToken} takes one whenever a recorder is wired and
|
|
378
|
+
* the listener hands it over, so a missing one is a wiring fault: refused rather than letting
|
|
379
|
+
* the redemption fall through to a path that records no usage.
|
|
380
|
+
*/
|
|
381
|
+
requireRead(token, read) {
|
|
382
|
+
if (!read) {
|
|
383
|
+
throw new Error(`Formation for token ${token} reached provisioning without the session's token read`);
|
|
384
|
+
}
|
|
385
|
+
return read;
|
|
386
|
+
}
|
|
374
387
|
/**
|
|
375
388
|
* Authorize a BOUND redemption without writing it, through the recorder's optional
|
|
376
389
|
* {@link FormationUsageRecorder.authorizeUsage}. A recorder without it has nothing to ask up
|
|
377
390
|
* front, so its handle defers everything to `recordUsage`.
|
|
378
391
|
*/
|
|
379
|
-
async authorizeBoundUsage(recorder, params) {
|
|
392
|
+
async authorizeBoundUsage(recorder, params, read, host) {
|
|
380
393
|
if (recorder.authorizeUsage) {
|
|
381
|
-
return await recorder.authorizeUsage(params);
|
|
394
|
+
return await recorder.authorizeUsage(params, read, host);
|
|
382
395
|
}
|
|
383
396
|
return { record: () => recorder.recordUsage(params) };
|
|
384
397
|
}
|
|
@@ -402,12 +415,13 @@ export class StrandFormationManager {
|
|
|
402
415
|
* The LOG-before-reject keeps both a deliberate internal-error→protocol-rejection
|
|
403
416
|
* conversion, same as the catch-all in {@link provisionAsResponder}.
|
|
404
417
|
*/
|
|
405
|
-
async issueBoundMembershipInvite(token,
|
|
418
|
+
async issueBoundMembershipInvite(token, host, signal) {
|
|
406
419
|
if (!this.issueMembershipInvite) {
|
|
407
420
|
return { ok: true };
|
|
408
421
|
}
|
|
422
|
+
const strandId = host.strandId;
|
|
409
423
|
try {
|
|
410
|
-
const invite = await this.issueMembershipInvite(
|
|
424
|
+
const invite = await this.issueMembershipInvite(host, signal);
|
|
411
425
|
return { ok: true, invite: invite ?? undefined };
|
|
412
426
|
}
|
|
413
427
|
catch (err) {
|
|
@@ -434,7 +448,7 @@ export class StrandFormationManager {
|
|
|
434
448
|
* 2. else `strandProvisioner` present → the mock/transport-test contract: provision a bare
|
|
435
449
|
* strand, NO inline usage write (those callers record usage explicitly via
|
|
436
450
|
* `recordFormationComplete`, or assert transport invariants only). Threads the invite's
|
|
437
|
-
* REAL `sAppId
|
|
451
|
+
* REAL `sAppId` from the session's read (empty when there is none).
|
|
438
452
|
* 3. else → a structural placeholder (no recorder + no provisioner ⇒ no single-use semantics
|
|
439
453
|
* exist to enforce).
|
|
440
454
|
*
|
|
@@ -447,11 +461,11 @@ export class StrandFormationManager {
|
|
|
447
461
|
* responder-provisions placeholder as failure). Revisit if production starts publishing
|
|
448
462
|
* unbound invites, or the mock-transport tests go away.
|
|
449
463
|
*/
|
|
450
|
-
async provisionUnbound(contact, disclosureText, signal) {
|
|
464
|
+
async provisionUnbound(contact, disclosureText, signal, read) {
|
|
451
465
|
const token = contact.token;
|
|
452
466
|
const recorder = this.formationUsageRecorder;
|
|
467
|
+
const sAppId = read?.invite?.sAppId ?? '';
|
|
453
468
|
if (recorder?.provisionAndRecord) {
|
|
454
|
-
const sAppId = await this.resolveInviteSAppId(token);
|
|
455
469
|
const provisioned = await recorder.provisionAndRecord({
|
|
456
470
|
token,
|
|
457
471
|
peerKey: contact.peerKey,
|
|
@@ -460,7 +474,7 @@ export class StrandFormationManager {
|
|
|
460
474
|
sAppId,
|
|
461
475
|
disclosure: disclosureText,
|
|
462
476
|
signal
|
|
463
|
-
});
|
|
477
|
+
}, this.requireRead(token, read));
|
|
464
478
|
return this.approve({
|
|
465
479
|
strand: { strandId: provisioned.strandId, createdBy: 'responder' },
|
|
466
480
|
memberPrivateKey: provisioned.memberPrivateKey ?? undefined,
|
|
@@ -468,7 +482,6 @@ export class StrandFormationManager {
|
|
|
468
482
|
});
|
|
469
483
|
}
|
|
470
484
|
if (this.strandProvisioner) {
|
|
471
|
-
const sAppId = await this.resolveInviteSAppId(token);
|
|
472
485
|
const result = await this.strandProvisioner.provisionStrand(sAppId, contact.partyId, this.partyId);
|
|
473
486
|
return this.approve({
|
|
474
487
|
strand: { strandId: result.strandId, createdBy: 'responder' },
|
|
@@ -486,17 +499,6 @@ export class StrandFormationManager {
|
|
|
486
499
|
approve(result) {
|
|
487
500
|
return { approved: true, result };
|
|
488
501
|
}
|
|
489
|
-
/**
|
|
490
|
-
* The invite's authoritative `sAppId` for the responder-provisions fallback, read back
|
|
491
|
-
* from the recorder's `isTokenValid` invitation (the real `FormationInvite.sAppId`).
|
|
492
|
-
* Empty string when no recorder is wired or the invitation omits it.
|
|
493
|
-
*/
|
|
494
|
-
async resolveInviteSAppId(token) {
|
|
495
|
-
if (!this.formationUsageRecorder)
|
|
496
|
-
return '';
|
|
497
|
-
const check = await this.formationUsageRecorder.isTokenValid(token);
|
|
498
|
-
return check.invitation?.sAppId ?? '';
|
|
499
|
-
}
|
|
500
502
|
// ── Initiator-side result validation ─────────────────────────────────────────
|
|
501
503
|
async validateResponse(invitation, disclosure, response) {
|
|
502
504
|
if (this.formationResponseValidator) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strand-formation-manager.js","sourceRoot":"","sources":["../src/strand-formation-manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"strand-formation-manager.js","sourceRoot":"","sources":["../src/strand-formation-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAQjE,OAAO,EACL,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,qFAAqF;AACrF,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWpD,OAAO,EAAE,iBAAiB,EAAqD,MAAM,sBAAsB,CAAC;AAC5G,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,6BAA6B,EAC7B,4BAA4B,EAM7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAErE,MAAM,GAAG,GAAG,KAAK,CAAC,gCAAgC,CAAC,CAAC;AAEpD;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,CAAC;AAEtC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,GAAG,EAAE,GAAG,OAAQ,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,iDAAiD,CAAC;AAEtG;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oCAAoC,GAAG,+BAA+B,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAyD;IAChF,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,4BAA4B,EAAE;IAC5F,WAAW,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,uCAAuC,EAAE;IAC/G,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,4BAA4B,EAAE;IAC9F,UAAU,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,wCAAwC,EAAE;IAC3G,aAAa,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,kCAAkC,EAAE;CACzG,CAAC;AA4GF;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,sBAAsB;IAcjC,YAAY,OAAsC;QAHjC,oBAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAC7C,mBAAc,GAAG,CAAC,CAAC;QAGzB,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACvD,IAAI,CAAC,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC;QAC7D,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACnD,IAAI,CAAC,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;QACrE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;QACnD,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;QACrD,IAAI,CAAC,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAC;QAC3D,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAC;YACpC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;YACnD,kBAAkB,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,UAAU,CAAC;YACrF,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CACzC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC;YAClD,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;YACrG,8EAA8E;YAC9E,mFAAmF;YACnF,GAAG,CAAC,IAAI,CAAC,kBAAkB,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC/E,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;YAC5C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;YAC9C,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;YACxC,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB;YAClD,qBAAqB,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB;SACzD,CAAC,CAAC;QAEH,GAAG,CAAC,8CAA8C,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IAEO,qBAAqB;QAC3B,OAAO,OAAO,IAAI,CAAC,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;IACjG,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,IAAY,EAAE,UAAmB;QACvD,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YAC/B,OAAO;QACT,CAAC;QACD,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACzE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,GAAG,CAAC,iCAAiC,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,IAAY,EAAE,UAAmB;QACzD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,OAAO;QACT,CAAC;QACD,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3E,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IAChC,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,UAAU,CACd,UAA0B,EAC1B,UAAqC,EACrC,OAAyE,EACzE,IAAY;QAEZ,GAAG,CAAC,0CAA0C,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAElE,MAAM,OAAO,GAA4B;YACvC,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO;YAC3C,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,UAAU;YACV,cAAc,EAAE,IAAI,CAAC,qBAAqB,EAAE;SAC7C,CAAC;QAEF,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,IAAI,EAAE;gBAChD,OAAO;gBACP,cAAc,EAAE,UAAU,CAAC,SAAS;gBACpC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC;gBACvF,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe;gBAC5C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;gBAC9C,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;gBACxC,kBAAkB,EAAE,IAAI,CAAC,2BAA2B,EAAE;gBACtD,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;aACnC,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;YACnC,GAAG,CAAC,mDAAmD,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAE/G,OAAO;gBACL,SAAS,EAAE,OAAO,CAAC,OAAO;gBAC1B,gBAAgB,EAAE,EAAE;gBACpB,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ;gBACnC,4FAA4F;gBAC5F,qFAAqF;gBACrF,+EAA+E;gBAC/E,gBAAgB,EAAE,SAAS,CAAC,gBAAgB;gBAC5C,gFAAgF;gBAChF,+EAA+E;gBAC/E,kFAAkF;gBAClF,gBAAgB,EAAE,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;gBACtD,mEAAmE;gBACnE,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,sBAAsB;QACpB,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;IAChF,CAAC;IAED;;;;;OAKG;IACK,oBAAoB,CAAC,SAAmC;QAC9D,IAAI,SAAS,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YAC7C,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,4BAA4B,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,8EAA8E,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC/G,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,CAAC;IAC5H,CAAC;IAED;;;;;;;;;OASG;IACK,2BAA2B;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;QAC5C,OAAO,IAAI,IAAI,IAAI,GAAG,CAAC;YACrB,CAAC,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,sBAAsB;YAC/E,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,gFAAgF;IAEhF;;;;;OAKG;IACK,KAAK,CAAC,aAAa,CAAC,KAAa;QACvC,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,8CAA8C;YAC9C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAChG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,GAAG,CAAC,wBAAwB,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,KAAa,EAAE,UAAqC;QACnF,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC9B,oDAAoD;YACpD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAmCG;IACK,KAAK,CAAC,oBAAoB,CAChC,OAAgC,EAChC,MAA+B,EAC/B,IAAoC;QAEpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,qFAAqF;QACrF,wFAAwF;QACxF,qFAAqF;QACrF,yCAAyC;QACzC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,oBAAoB,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,UAAU,GAAG,oBAAoB,EAAE,CAAC;YACnF,GAAG,CAAC,8CAA8C,EAAE,oBAAoB,EAAE,KAAK,CAAC,CAAC;YACjF,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;QAC3F,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC;QAC7C,MAAM,QAAQ,GAAuB,QAAQ,EAAE,aAAa;YAC1D,CAAC,CAAC,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAC7D,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAExB,IAAI,CAAC;YACH,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACtB,KAAK,OAAO,CAAC,CAAC,CAAC;oBACb,sFAAsF;oBACtF,qBAAqB;oBACrB,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAS,EAAE;wBAC3D,KAAK;wBACL,OAAO,EAAE,OAAO,CAAC,OAAO;wBACxB,aAAa,EAAE,OAAO,CAAC,aAAa;wBACpC,YAAY,EAAE,OAAO,CAAC,YAAY;wBAClC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;wBAC3B,UAAU,EAAE,cAAc;wBAC1B,MAAM;qBACP,EAAE,IAAK,EAAE,QAAQ,CAAC,CAAC;oBACpB,kFAAkF;oBAClF,qFAAqF;oBACrF,oFAAoF;oBACpF,oEAAoE;oBACpE,mFAAmF;oBACnF,qFAAqF;oBACrF,sFAAsF;oBACtF,mFAAmF;oBACnF,gDAAgD;oBAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAC9E,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;wBACf,OAAO,MAAM,CAAC,SAAS,CAAC;oBAC1B,CAAC;oBACD,MAAM,UAAU,CAAC,MAAM,EAAE,CAAC;oBAC1B,OAAO,IAAI,CAAC,OAAO,CAAC;wBAClB,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;wBAC/D,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,IAAI,SAAS;wBACxD,0EAA0E;wBAC1E,+DAA+D;wBAC/D,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC7D,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE;qBAC5D,CAAC,CAAC;gBACL,CAAC;gBACD,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,GAAG,CAAC,wEAAwE,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBACxG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,EAAE,iDAAiD,EAAE,CAAC;gBACzH,CAAC;gBACD,KAAK,SAAS;oBACZ,OAAO,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,qBAAqB,EAAE,CAAC;gBACzC,oFAAoF;gBACpF,0EAA0E;gBAC1E,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;gBAC1C,GAAG,CAAC,uCAAuC,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;gBACtE,OAAO,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC1C,CAAC;YACD,IAAI,GAAG,YAAY,wBAAwB,EAAE,CAAC;gBAC5C,sFAAsF;gBACtF,uFAAuF;gBACvF,sFAAsF;gBACtF,kDAAkD;gBAClD,GAAG,CACD,qEAAqE,EACrE,GAAG,CAAC,KAAK,EACT,GAAG,CAAC,YAAY,EAChB,GAAG,CAAC,SAAS,CACd,CAAC;gBACF,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;YAChF,CAAC;YACD,sFAAsF;YACtF,uFAAuF;YACvF,oFAAoF;YACpF,6EAA6E;YAC7E,GAAG,CAAC,8CAA8C,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAChE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC;QACpF,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,WAAW,CAAC,KAAa,EAAE,IAAoC;QACrE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,uBAAuB,KAAK,wDAAwD,CAAC,CAAC;QACxG,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,mBAAmB,CAC/B,QAAgC,EAChC,MAA4B,EAC5B,IAAwB,EACxB,IAAqB;QAErB,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC5B,OAAO,MAAM,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACK,KAAK,CAAC,0BAA0B,CACtC,KAAa,EACb,IAAqB,EACrB,MAAoB;QAEpB,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAChC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,IAAI,SAAS,EAAE,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,2BAA2B,EAAE,CAAC;gBAC/C,GAAG,CAAC,8EAA8E,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;gBAC1G,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,+BAA+B,EAAE,MAAM,EAAE,oCAAoC,EAAE;iBACpH,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,kFAAkF,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9G,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,EAAE,oCAAoC,EAAE;aAC9G,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACK,KAAK,CAAC,gBAAgB,CAC5B,OAAgC,EAChC,cAAsB,EACtB,MAA+B,EAC/B,IAAoC;QAEpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC;QAC1C,IAAI,QAAQ,EAAE,kBAAkB,EAAE,CAAC;YACjC,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC;gBACpD,KAAK;gBACL,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,MAAM;gBACN,UAAU,EAAE,cAAc;gBAC1B,MAAM;aACP,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC,OAAO,CAAC;gBAClB,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;gBAClE,gBAAgB,EAAE,WAAW,CAAC,gBAAgB,IAAI,SAAS;gBAC3D,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACnG,OAAO,IAAI,CAAC,OAAO,CAAC;gBAClB,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;gBAC7D,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE;aAC5D,CAAC,CAAC;QACL,CAAC;QAED,4FAA4F;QAC5F,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE;YAC5C,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,iFAAiF;IACzE,OAAO,CAAC,MAAgC;QAC9C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACpC,CAAC;IAED,gFAAgF;IAExE,KAAK,CAAC,gBAAgB,CAC5B,UAA0B,EAC1B,UAAqC,EACrC,QAAgC;QAEhC,IAAI,IAAI,CAAC,0BAA0B,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAC1C,OAAsC;IAEtC,OAAO,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import type { Libp2p } from '@libp2p/interface';
|
|
21
21
|
import type { StrandFormationDisclosure, StrandMembershipInvite } from './types.js';
|
|
22
22
|
import { type FormationRejectionCode } from './strand-formation-rejection.js';
|
|
23
|
+
import type { FormationTokenCheck, FormationTokenRead } from './formation-token.js';
|
|
23
24
|
/** Protocol id for the native formation transport (parallel to `/sereus/seed/1.0.0`). */
|
|
24
25
|
export declare const FORMATION_PROTOCOL = "/sereus/formation/1.0.0";
|
|
25
26
|
/**
|
|
@@ -85,13 +86,6 @@ export interface FormationRejection {
|
|
|
85
86
|
/** Human-facing text for logs; joiners branch on `code`. */
|
|
86
87
|
reason: string;
|
|
87
88
|
}
|
|
88
|
-
/** What the responder's token check yields; an invalid token names which way it failed. */
|
|
89
|
-
export type FormationTokenCheck = {
|
|
90
|
-
valid: true;
|
|
91
|
-
} | {
|
|
92
|
-
valid: false;
|
|
93
|
-
code: Extract<FormationRejectionCode, 'token-unknown' | 'token-spent'>;
|
|
94
|
-
};
|
|
95
89
|
/** Initiator → Responder: carries the real token + disclosure + initiator cadre. */
|
|
96
90
|
export interface FormationContactMessage {
|
|
97
91
|
/** The real invitation token. */
|
|
@@ -201,8 +195,11 @@ export interface FormationListenerOptions {
|
|
|
201
195
|
* `signal` is aborted when the listener's work budget expires: a hook that observes it
|
|
202
196
|
* BEFORE writing abandons the redemption and leaves the invite unspent. Optional so
|
|
203
197
|
* signal-unaware hooks (tests, mocks) stay assignable.
|
|
198
|
+
*
|
|
199
|
+
* `read` is the token as {@link validateToken} read it for this session, so the hook acts on
|
|
200
|
+
* that read instead of reading the invite again; absent when the token check read nothing.
|
|
204
201
|
*/
|
|
205
|
-
provisionStrand(contact: FormationContactMessage, signal?: AbortSignal): Promise<ResponderProvisionOutcome>;
|
|
202
|
+
provisionStrand(contact: FormationContactMessage, signal?: AbortSignal, read?: FormationTokenRead): Promise<ResponderProvisionOutcome>;
|
|
206
203
|
/** Responder identity, disclosed only AFTER token + disclosure validation passes. */
|
|
207
204
|
getResponderIdentity(): {
|
|
208
205
|
partyId: string;
|
|
@@ -301,10 +301,10 @@ export class FormationListener {
|
|
|
301
301
|
* Deliberately not `withDeadline`: that exposes neither the timed-out flag nor the signal
|
|
302
302
|
* outside its `op`, and both are needed here.
|
|
303
303
|
*/
|
|
304
|
-
async provision(id, contact) {
|
|
304
|
+
async provision(id, contact, read) {
|
|
305
305
|
const controller = new AbortController();
|
|
306
306
|
let timedOut = false;
|
|
307
|
-
const pending = this.options.provisionStrand(contact, controller.signal);
|
|
307
|
+
const pending = this.options.provisionStrand(contact, controller.signal, read);
|
|
308
308
|
try {
|
|
309
309
|
return await withTimeout(this.provisionWorkMs, `Formation provisioning#${id}`, () => pending, () => { timedOut = true; controller.abort(); });
|
|
310
310
|
}
|
|
@@ -442,7 +442,7 @@ export class FormationListener {
|
|
|
442
442
|
send({ approved: false, code: 'disclosure-invalid', reason: 'Invalid disclosure' });
|
|
443
443
|
return;
|
|
444
444
|
}
|
|
445
|
-
const outcome = await this.provision(id, contact);
|
|
445
|
+
const outcome = await this.provision(id, contact, tokenResult.read);
|
|
446
446
|
if (!outcome) {
|
|
447
447
|
// Reported as its own retryable reason rather than falling through to the generic
|
|
448
448
|
// catch below, which would report the misleading 'Internal formation error'.
|
|
@@ -488,16 +488,27 @@ export class FormationListener {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Connections a formation dial opened, each with the number of formation exchanges still using
|
|
493
|
+
* it; the entry is dropped when the last one finishes and closes the connection
|
|
494
|
+
* ({@link releaseFormationConnection}). A connection the node already held when its dial started
|
|
495
|
+
* is never entered, so formation never closes someone else's connection.
|
|
496
|
+
*
|
|
497
|
+
* Counted per connection rather than per dial: two formations to one responder machine at once
|
|
498
|
+
* (two pending joins on invitations from one inviter) share the connection libp2p's dial queue
|
|
499
|
+
* opened for the first, and the first to finish must leave it to the second.
|
|
500
|
+
*/
|
|
501
|
+
const formationConnectionUsers = new WeakMap();
|
|
491
502
|
/**
|
|
492
503
|
* Open the formation stream under the dial deadline, cancelling the dial when it expires.
|
|
493
504
|
*
|
|
494
|
-
* The deadline's signal goes into
|
|
495
|
-
* rather than left running. A dial that settles in the same tick the
|
|
496
|
-
* the race to the timeout rejection and would leave its stream open with
|
|
497
|
-
* it, so a
|
|
498
|
-
* `exchangeFrame` (`control-stream.ts`) gives a stream
|
|
499
|
-
* rejection is the abort itself, or reaches the caller through
|
|
500
|
-
* handler below only stops it being reported as unhandled.
|
|
505
|
+
* The deadline's signal goes into the dial and the stream negotiation, so an expired dial is
|
|
506
|
+
* abandoned by libp2p rather than left running. A dial that settles in the same tick the
|
|
507
|
+
* deadline fires loses the race to the timeout rejection and would leave its stream open with
|
|
508
|
+
* nobody to close it, so a channel that arrives after the signal aborted is reset here, and its
|
|
509
|
+
* connection released — the same treatment `exchangeFrame` (`control-stream.ts`) gives a stream
|
|
510
|
+
* dialed past its deadline. A late rejection is the abort itself, or reaches the caller through
|
|
511
|
+
* the awaited copy, so the handler below only stops it being reported as unhandled.
|
|
501
512
|
*
|
|
502
513
|
* NOTE: libp2p tries `addrs` one after another, and they all share this one dial budget. Its
|
|
503
514
|
* per-address limit (`addressDialTimeout`: ten link round trips plus two admission decisions, as
|
|
@@ -515,11 +526,10 @@ export class FormationListener {
|
|
|
515
526
|
*/
|
|
516
527
|
function openFormationStream(node, addrs, protocolId, dialTimeoutMs) {
|
|
517
528
|
return withDeadline(dialTimeoutMs, 'Formation dial-connect', async (signal) => {
|
|
518
|
-
const pending = node
|
|
519
|
-
void pending.then((
|
|
520
|
-
if (signal.aborted)
|
|
521
|
-
|
|
522
|
-
}
|
|
529
|
+
const pending = dialFormationChannel(node, addrs, protocolId, signal);
|
|
530
|
+
void pending.then((channel) => {
|
|
531
|
+
if (signal.aborted)
|
|
532
|
+
abandonLateChannel(channel);
|
|
523
533
|
}, () => { });
|
|
524
534
|
try {
|
|
525
535
|
return await pending;
|
|
@@ -529,6 +539,80 @@ function openFormationStream(node, addrs, protocolId, dialTimeoutMs) {
|
|
|
529
539
|
}
|
|
530
540
|
});
|
|
531
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Dial the responder machine, then open the formation stream on the connection. The ids of the
|
|
544
|
+
* node's connections are read before the dial: a connection not among them was opened by this
|
|
545
|
+
* dial (or by another formation dial it was joined to), and is closed when formation is done
|
|
546
|
+
* with it. A stream that cannot be opened releases the connection at once.
|
|
547
|
+
*
|
|
548
|
+
* NOTE: a dial of the responder that something other than formation started, and this dial was
|
|
549
|
+
* joined to, also counts as opened by formation and is closed afterwards. Nothing else dials an
|
|
550
|
+
* inviter's control node before formation does; if something starts to, tell the two apart by
|
|
551
|
+
* the connection's own opening time rather than by this snapshot.
|
|
552
|
+
*/
|
|
553
|
+
async function dialFormationChannel(node, addrs, protocolId, signal) {
|
|
554
|
+
const heldBefore = new Set(node.getConnections().map((connection) => connection.id));
|
|
555
|
+
const connection = await node.dial(addrs, { signal });
|
|
556
|
+
useFormationConnection(connection, heldBefore.has(connection.id));
|
|
557
|
+
try {
|
|
558
|
+
signal.throwIfAborted();
|
|
559
|
+
const stream = await connection.newStream(protocolId, { signal });
|
|
560
|
+
return { stream: stream, connection };
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
void releaseFormationConnection(connection);
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function abandonLateChannel({ stream, connection }) {
|
|
568
|
+
stream.abort(new Error('Formation dial-connect resolved after its deadline'));
|
|
569
|
+
void releaseFormationConnection(connection);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Count one more formation exchange on `connection` when a formation dial opened it — this one
|
|
573
|
+
* (`heldBefore` false) or an earlier one still using it.
|
|
574
|
+
*/
|
|
575
|
+
function useFormationConnection(connection, heldBefore) {
|
|
576
|
+
const users = formationConnectionUsers.get(connection);
|
|
577
|
+
if (users !== undefined)
|
|
578
|
+
formationConnectionUsers.set(connection, users + 1);
|
|
579
|
+
else if (!heldBefore)
|
|
580
|
+
formationConnectionUsers.set(connection, 1);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* End one formation exchange's use of `connection`, closing it when a formation dial opened it
|
|
584
|
+
* and no other exchange still uses it. Never throws.
|
|
585
|
+
*
|
|
586
|
+
* Only the joiner closes: it opened the connection, so it is the side that knows the connection
|
|
587
|
+
* did not exist before. The joiner's and the inviter's control nodes run on different FRET
|
|
588
|
+
* networks, so a connection left open after formation carries nothing but FRET pings that fail,
|
|
589
|
+
* until FRET has been refused three times and leaves that peer alone (p2p-fret 1.2.1). FRET can
|
|
590
|
+
* still redial the other control node on its own while it re-probes a peer it has seen
|
|
591
|
+
* (`complete/fret-maintenance-probes-peers-off-its-ring`).
|
|
592
|
+
*
|
|
593
|
+
* The close is graceful, so the responder's side can finish its own stream close; a close that
|
|
594
|
+
* fails or overruns libp2p's close timeout is logged and the connection aborted, as libp2p's own
|
|
595
|
+
* `hangUp` does. When the responder is a machine of the joiner's own party the connection
|
|
596
|
+
* normally pre-exists (the cadre mesh) and is left alone; if this dial opened it, it is closed,
|
|
597
|
+
* and the mesh re-dials that sibling as after any dropped connection.
|
|
598
|
+
*/
|
|
599
|
+
async function releaseFormationConnection(connection) {
|
|
600
|
+
const users = formationConnectionUsers.get(connection);
|
|
601
|
+
if (users === undefined)
|
|
602
|
+
return;
|
|
603
|
+
if (users > 1) {
|
|
604
|
+
formationConnectionUsers.set(connection, users - 1);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
formationConnectionUsers.delete(connection);
|
|
608
|
+
try {
|
|
609
|
+
await connection.close();
|
|
610
|
+
}
|
|
611
|
+
catch (error) {
|
|
612
|
+
log('closing the formation connection to %s failed; aborting it: %o', connection.remotePeer.toString(), error);
|
|
613
|
+
connection.abort(error instanceof Error ? error : new Error(String(error)));
|
|
614
|
+
}
|
|
615
|
+
}
|
|
532
616
|
const NO_RESPONDER_ADDRS = 'No responder addresses available for formation';
|
|
533
617
|
/**
|
|
534
618
|
* Parse the responder addresses, skipping any entry that does not parse: the list comes from
|
|
@@ -626,7 +710,7 @@ function asUnreachable(error) {
|
|
|
626
710
|
* included, since it is not an answer either.
|
|
627
711
|
*/
|
|
628
712
|
async function exchangeContact(node, addrs, contact, budgets) {
|
|
629
|
-
const stream = await openFormationStream(node, addrs, budgets.protocolId, budgets.dialTimeoutMs);
|
|
713
|
+
const { stream, connection } = await openFormationStream(node, addrs, budgets.protocolId, budgets.dialTimeoutMs);
|
|
630
714
|
try {
|
|
631
715
|
const reader = new FrameReader(stream);
|
|
632
716
|
writeFrame(stream, contact);
|
|
@@ -637,6 +721,7 @@ async function exchangeContact(node, addrs, contact, budgets) {
|
|
|
637
721
|
await stream.close();
|
|
638
722
|
}
|
|
639
723
|
catch { /* ignore */ }
|
|
724
|
+
void releaseFormationConnection(connection);
|
|
640
725
|
}
|
|
641
726
|
}
|
|
642
727
|
/**
|