@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
package/dist/control-schema.js
CHANGED
|
@@ -2,19 +2,19 @@ import { Parser } from '@quereus/quereus';
|
|
|
2
2
|
/**
|
|
3
3
|
* The version of the declared control schema, carried in the schema text as the
|
|
4
4
|
* {@link CONTROL_SCHEMA_VERSION_TAG} tag on the `OwnerKey` table. A warm start compares
|
|
5
|
-
* it with the version the store records before applying anything
|
|
6
|
-
* (`control-schema-version.ts
|
|
7
|
-
* created under).
|
|
5
|
+
* it with the version the store records before applying anything, and the apply then
|
|
6
|
+
* migrates the store to this version and records it (`control-schema-version.ts`).
|
|
8
7
|
*
|
|
9
8
|
* When it changes, what a new version may change, and the fixture each version keeps:
|
|
10
|
-
* docs/architecture.md → "Control schema
|
|
9
|
+
* docs/architecture.md → "Control schema versions and migrations", enforced by
|
|
11
10
|
* `control-schema-versions.spec.ts`.
|
|
12
11
|
*/
|
|
13
12
|
export const CONTROL_SCHEMA_VERSION = 3;
|
|
14
13
|
/**
|
|
15
14
|
* The first control schema version whose fixture is kept, and the oldest a store can be
|
|
16
|
-
* migrated from.
|
|
17
|
-
*
|
|
15
|
+
* migrated from. A store that records a version below it (written by 1.16.0 and earlier,
|
|
16
|
+
* which recorded none) is refused with reason `before-migrations`; docs/architecture.md
|
|
17
|
+
* says why it is not migrated.
|
|
18
18
|
*/
|
|
19
19
|
export const CONTROL_SCHEMA_BASELINE_VERSION = 3;
|
|
20
20
|
/** The `OwnerKey` table tag that records {@link CONTROL_SCHEMA_VERSION} in the schema and in every store. */
|
|
@@ -663,7 +663,7 @@ declare schema CadreControl {
|
|
|
663
663
|
) with context (Now datetime, ValidationKey text null, ValidationSignature text null);
|
|
664
664
|
|
|
665
665
|
-- Serves the per-token reads (the cap count above; cadre-core's countFormationUsage,
|
|
666
|
-
--
|
|
666
|
+
-- readToken and hasOutstandingFormationInvite) on an append-only table. Its cross-machine
|
|
667
667
|
-- convergence is guarded by the integration scenario strand-formation-concurrent-redemption.
|
|
668
668
|
index FormationUsageByToken on FormationUsage (Token);
|
|
669
669
|
|
|
@@ -899,16 +899,15 @@ declare schema CadreControl {
|
|
|
899
899
|
|
|
900
900
|
-- Append-only retirement record for the stamps of removed rows of every guarded table, with
|
|
901
901
|
-- the removed row's key. Every append is owner-signed, so the growth surface is the owner
|
|
902
|
-
-- keys.
|
|
903
|
-
--
|
|
904
|
-
-- table
|
|
905
|
-
-- for on every guarded insert and membership lookup. Readers filter on their own guarded
|
|
902
|
+
-- keys. A party founded before genesis created every control collection may hold one marker
|
|
903
|
+
-- row, ('Revocation', 'ledger', 'opened'), which retires nothing: an owner filed it so this
|
|
904
|
+
-- table had a collection. Nothing files it now. Readers filter on their own guarded
|
|
906
905
|
-- TableName, and queryRevocations skips it. A 'CadreInvite' or 'OwnerGrant' row withdraws
|
|
907
906
|
-- an invitation or a grant whose row stays (the table comments).
|
|
908
907
|
table Revocation (
|
|
909
908
|
TableName text, -- 'OwnerKey' | 'ValidationKey' | 'Strand' | 'StrandPartyKey' | 'JoinedStrand' |
|
|
910
909
|
-- 'JoinRequest' | 'CadrePeer' | 'DeviceToken' | 'CadreInvite' | 'OwnerGrant', or
|
|
911
|
-
-- 'Revocation' for
|
|
910
|
+
-- 'Revocation' for an older party's marker
|
|
912
911
|
RowKey text, -- primary key of the removed row
|
|
913
912
|
StampId text, -- the retired stamp
|
|
914
913
|
ReissuedAt integer default 0, -- bumped by an owner-signed re-issue so a tombstone committed while the
|
|
@@ -938,7 +937,9 @@ declare schema CadreControl {
|
|
|
938
937
|
-- never existed is harmless: stamps carry 128 random bits (generateStampId). For
|
|
939
938
|
-- 'CadreInvite' and 'OwnerGrant' there is no row-gone test: a tombstone there is a
|
|
940
939
|
-- withdrawal, and the row stays (the table comments). The last branch admits the marker
|
|
941
|
-
-- row and nothing else under 'Revocation'.
|
|
940
|
+
-- row an older party may hold, and nothing else under 'Revocation'; nothing files it now.
|
|
941
|
+
-- NOTE: drop this branch, REVOCATION_LEDGER_MARKER and the readers' skip together with the
|
|
942
|
+
-- next CONTROL_SCHEMA_VERSION change that already needs a migration.
|
|
942
943
|
constraint RowIsGone check on insert (
|
|
943
944
|
(new.TableName = 'OwnerKey' and not exists (select 1 from OwnerKey K where K.StampId = new.StampId))
|
|
944
945
|
or (new.TableName = 'CadrePeer' and not exists (select 1 from CadrePeer P where P.StampId = new.StampId))
|
|
@@ -957,9 +958,8 @@ declare schema CadreControl {
|
|
|
957
958
|
-- writer could evict a peer party-wide and block its re-admission. RowKey is not checked
|
|
958
959
|
-- against the retired row here (that would reject a tombstone re-issued later, or filed on
|
|
959
960
|
-- a node that never held the row); each guarded table's RevocationRecorded binds it
|
|
960
|
-
-- instead. Reads live OwnerKey like the sibling tables.
|
|
961
|
-
-- rule too
|
|
962
|
-
-- pair verified here.
|
|
961
|
+
-- instead. Reads live OwnerKey like the sibling tables. An older party's marker was signed
|
|
962
|
+
-- under this rule too. The stored signer pair must be the pair verified here.
|
|
963
963
|
constraint Authorized check on insert (
|
|
964
964
|
exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and not exists (select 1 from Revocation R where R.TableName = 'OwnerKey' and R.StampId = A.StampId) and verify(digest('CadreControl.Revocation', 'remove', party_id(), new.TableName, new.RowKey, new.StampId), context.Signature, A.Key, 'ed25519'))
|
|
965
965
|
and coalesce(new.SignerKey, '') = context.OwnerKey
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-schema.js","sourceRoot":"","sources":["../src/control-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C
|
|
1
|
+
{"version":3,"file":"control-schema.js","sourceRoot":"","sources":["../src/control-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,12 +28,13 @@ import type { ControlRetryOptions } from './control-retry.js';
|
|
|
28
28
|
* before any matcher runs. The one half-landed write that IS re-presented is a torn write the
|
|
29
29
|
* library marks final — not saved and unable to land ({@link isFinalTornWrite}).
|
|
30
30
|
*
|
|
31
|
-
*
|
|
31
|
+
* THREE policies ship from here, and the split is deliberate: the default
|
|
32
32
|
* ({@link isRetriableControlWriteFailure}, {@link CONTROL_WRITE_ATTEMPTS}) sits under every
|
|
33
|
-
* control write
|
|
34
|
-
* `ControlDatabase.applyControlSchema` alone
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
* control write; {@link SCHEMA_INIT_RETRY_POLICY} is opted into by
|
|
34
|
+
* `ControlDatabase.applyControlSchema` alone; {@link LOST_UPDATE_RETRY_POLICY} is opted into by
|
|
35
|
+
* the `CadrePeer` writers whose bodies re-read the row and decide again. Each widened one absorbs
|
|
36
|
+
* one extra failure class whose re-run safety holds for its opted-in bodies and NOT for writes in
|
|
37
|
+
* general; anything added to the default list must be safe for all ~19 callers.
|
|
37
38
|
*
|
|
38
39
|
* Lives outside `control-database.ts` so a spec can drive the classifier against real engine
|
|
39
40
|
* errors without importing the whole database class. The loop itself lives in
|
|
@@ -218,6 +219,14 @@ export declare function isRetriableControlWriteFailure(error: unknown): boolean;
|
|
|
218
219
|
* default classifier untouched.
|
|
219
220
|
*/
|
|
220
221
|
export declare function isRetriableSchemaInitFailure(error: unknown): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* {@link isRetriableControlWriteFailure} widened by exactly one class — a lost update
|
|
224
|
+
* ({@link isLostUpdate}), claimed by type — for the `CadrePeer` writers that re-read the row inside
|
|
225
|
+
* their locked body. Opt-in per call site, via {@link LOST_UPDATE_RETRY_POLICY}; both vetoes still
|
|
226
|
+
* run first, so a lost update carried inside a partial commit, a spent sync budget or a non-final
|
|
227
|
+
* torn write stays declined.
|
|
228
|
+
*/
|
|
229
|
+
export declare function isRetriableLostUpdateFailure(error: unknown): boolean;
|
|
221
230
|
/**
|
|
222
231
|
* Policy and pacing overrides for {@link retryControlWrite}. Production callers pass nothing
|
|
223
232
|
* (or a named policy such as {@link SCHEMA_INIT_RETRY_POLICY}); specs inject a recorded
|
|
@@ -230,7 +239,7 @@ export declare function isRetriableSchemaInitFailure(error: unknown): boolean;
|
|
|
230
239
|
*/
|
|
231
240
|
export type ControlWriteRetryOptions = ControlRetryOptions;
|
|
232
241
|
/**
|
|
233
|
-
* The
|
|
242
|
+
* The schema-init policy: `ControlDatabase.applyControlSchema`'s distributed DDL, which
|
|
234
243
|
* additionally absorbs optimystic's self-coordination grace refusal and gets more attempts over a
|
|
235
244
|
* longer backoff to do it (see {@link SCHEMA_INIT_ATTEMPTS} and
|
|
236
245
|
* {@link SCHEMA_INIT_RETRY_DELAYS_MS}). Still bounded by the shared
|
|
@@ -241,9 +250,35 @@ export type ControlWriteRetryOptions = ControlRetryOptions;
|
|
|
241
250
|
* and verified against the pre-apply catalog (full argument at the `applyControlSchema` call site
|
|
242
251
|
* in `control-database.ts`). A second opt-in must re-derive that argument for its own write body
|
|
243
252
|
* first; if this policy ever grows a third consumer, rename it for what the callers share rather
|
|
244
|
-
* than widening it by default.
|
|
253
|
+
* than widening it by default. {@link LOST_UPDATE_RETRY_POLICY} is a separate policy for a
|
|
254
|
+
* separate class, not a second consumer of this one.
|
|
245
255
|
*/
|
|
246
256
|
export declare const SCHEMA_INIT_RETRY_POLICY: Readonly<ControlWriteRetryOptions>;
|
|
257
|
+
/**
|
|
258
|
+
* The lost-update policy: the default classifier plus a lost update claimed by type
|
|
259
|
+
* ({@link isRetriableLostUpdateFailure}), over the default attempts, backoff and budget. A re-run
|
|
260
|
+
* here is a RE-DECISION, not a re-presentation: the body reads the row again under the lock and
|
|
261
|
+
* signs over what it finds, so the write that lost to a rival is replaced by one made over the
|
|
262
|
+
* rival's result. The budget bounds it as it bounds every write — a losing attempt whose read
|
|
263
|
+
* phase waited out one per-peer read deadline (~7.5 s measured in the degraded-cohort scenario's
|
|
264
|
+
* trio boot) gets exactly one retry, which is the ceiling to expect; one that waited out two
|
|
265
|
+
* (14.7 s, measured once in 18 of that scenario's boots, on the member that cannot reach one
|
|
266
|
+
* sibling) gets none and is abandoned on the budget, and the lost publish is then the reconcile
|
|
267
|
+
* pass's or the heartbeat's to redo, as every abandoned self-publish is.
|
|
268
|
+
*
|
|
269
|
+
* NOTE: the re-run safety this policy assumes is each opted-in body's, not a general property. A
|
|
270
|
+
* body may opt in only when its read of the row, its decision and its signature ALL run inside
|
|
271
|
+
* the locked body, so that the re-run presents a write made over the row as it now stands rather
|
|
272
|
+
* than the first attempt's signed record (which the rival may have stamped past, or which may
|
|
273
|
+
* overwrite what the rival wrote). Three `CadrePeer` writers opt in, through
|
|
274
|
+
* `ControlDatabase.mutateCadrePeer`'s policy parameter or `lockedWithRetry` directly:
|
|
275
|
+
* `updateSelfPeerRecord` (re-reads and re-signs the node's own record), `reauthorizeCadrePeer`
|
|
276
|
+
* (re-reads the stamp and decides again whether the row is still the owner's to re-touch) and
|
|
277
|
+
* the two removals `deleteCadrePeer` / `removeMachine` (stamp read and signature already inside
|
|
278
|
+
* the body, and a self-publish never changes the stamp the `'remove'` digest binds). A new opt-in
|
|
279
|
+
* must re-derive that argument for its own body first.
|
|
280
|
+
*/
|
|
281
|
+
export declare const LOST_UPDATE_RETRY_POLICY: Readonly<ControlWriteRetryOptions>;
|
|
247
282
|
/**
|
|
248
283
|
* Run `attempt` up to {@link CONTROL_WRITE_ATTEMPTS} times (or `options.attempts`), retrying only
|
|
249
284
|
* failures the policy's classifier — {@link isRetriableControlWriteFailure} by default —
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CoordinatorPartialCommitError, SyncRetryExhaustedError, TornActionError } from '@optimystic/db-core';
|
|
2
|
-
import { PartialCommitError } from '@optimystic/quereus-plugin-optimystic';
|
|
2
|
+
import { ConcurrentModificationError, PartialCommitError } from '@optimystic/quereus-plugin-optimystic';
|
|
3
3
|
import { causeChain, chainMessages, retryControlOperation } from './control-retry.js';
|
|
4
4
|
/**
|
|
5
5
|
* Bounded retry for TRANSIENT control-write failures — the classifier and loop behind
|
|
@@ -30,12 +30,13 @@ import { causeChain, chainMessages, retryControlOperation } from './control-retr
|
|
|
30
30
|
* before any matcher runs. The one half-landed write that IS re-presented is a torn write the
|
|
31
31
|
* library marks final — not saved and unable to land ({@link isFinalTornWrite}).
|
|
32
32
|
*
|
|
33
|
-
*
|
|
33
|
+
* THREE policies ship from here, and the split is deliberate: the default
|
|
34
34
|
* ({@link isRetriableControlWriteFailure}, {@link CONTROL_WRITE_ATTEMPTS}) sits under every
|
|
35
|
-
* control write
|
|
36
|
-
* `ControlDatabase.applyControlSchema` alone
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* control write; {@link SCHEMA_INIT_RETRY_POLICY} is opted into by
|
|
36
|
+
* `ControlDatabase.applyControlSchema` alone; {@link LOST_UPDATE_RETRY_POLICY} is opted into by
|
|
37
|
+
* the `CadrePeer` writers whose bodies re-read the row and decide again. Each widened one absorbs
|
|
38
|
+
* one extra failure class whose re-run safety holds for its opted-in bodies and NOT for writes in
|
|
39
|
+
* general; anything added to the default list must be safe for all ~19 callers.
|
|
39
40
|
*
|
|
40
41
|
* Lives outside `control-database.ts` so a spec can drive the classifier against real engine
|
|
41
42
|
* errors without importing the whole database class. The loop itself lives in
|
|
@@ -324,6 +325,33 @@ function isFinalTornWrite(link) {
|
|
|
324
325
|
function isUnansweredSuperMajorityShortfall(message) {
|
|
325
326
|
return SUPER_MAJORITY_SHORTFALL_UNANSWERED.test(message);
|
|
326
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* A LOST UPDATE: the optimystic bridge refusing a commit because another writer changed or
|
|
330
|
+
* removed a row this statement read (`TransactionBridge.mapCommitRefusal` over a
|
|
331
|
+
* `TreeEntryChangedError`, `quereus-plugin-optimystic/src/optimystic-adapter/txn-bridge.ts`).
|
|
332
|
+
* Claimed by TYPE for {@link LOST_UPDATE_RETRY_POLICY} only.
|
|
333
|
+
*
|
|
334
|
+
* Why it is a proven non-commit: the refusal is raised inside the action's atomic handler, so
|
|
335
|
+
* none of that action's entries land. A refusal after a sibling tree or collection of the same
|
|
336
|
+
* transaction already synced is not delivered bare — the per-tree sweep wraps it in
|
|
337
|
+
* `PartialCommitError`, the coordinator path in `CoordinatorPartialCommitError` — and
|
|
338
|
+
* {@link reportsPossiblyStoredWrite} vetoes both by type before this predicate runs. A bare chain
|
|
339
|
+
* carrying this class therefore means nothing of the write is durable.
|
|
340
|
+
*
|
|
341
|
+
* Why it is not in the default list: the rejection is of the write's READ SET, not of its
|
|
342
|
+
* signature, so re-presenting the same statement is only right when the body re-reads the row and
|
|
343
|
+
* decides again over what it finds. That is a property of each opted-in body (see the policy's
|
|
344
|
+
* `NOTE:`), not of control writes in general.
|
|
345
|
+
*
|
|
346
|
+
* Not matched by text: `ConcurrentModificationError` is exported from both the plugin's root and
|
|
347
|
+
* `/plugin` entries over one shared chunk, as `PartialCommitError` is, so the one `instanceof`
|
|
348
|
+
* covers both (the `NOTE:` on {@link reportsPossiblyStoredWrite} applies to it too). A second
|
|
349
|
+
* loaded copy of the plugin would fail the `instanceof` and the lost update would then simply not
|
|
350
|
+
* be retried — the safe side.
|
|
351
|
+
*/
|
|
352
|
+
function isLostUpdate(link) {
|
|
353
|
+
return link instanceof ConcurrentModificationError;
|
|
354
|
+
}
|
|
327
355
|
/**
|
|
328
356
|
* Optimystic refusing to let a node elect ITSELF coordinator because its last connection dropped
|
|
329
357
|
* less than the guard's grace period ago (`Libp2pKeyPeerNetwork.shouldAllowSelfCoordination` →
|
|
@@ -388,9 +416,9 @@ const RETRIABLE_CONTROL_WRITE_MATCHERS = [
|
|
|
388
416
|
* does not complete — an undo statement threw, the post-unwind catalog did not match the pre-apply
|
|
389
417
|
* fingerprint, that catalog could not be re-collected to check, or a step the differ marks
|
|
390
418
|
* irreversible because it discards data (dropping a table or a column, narrowing a column's type —
|
|
391
|
-
*
|
|
392
|
-
* `refuseIncompatibleControlStore` in `control-schema-version.ts`
|
|
393
|
-
*
|
|
419
|
+
* of which only dropping a column reaches a `CadreControl` apply, as the catalog-only migration
|
|
420
|
+
* step `refuseIncompatibleControlStore` in `control-schema-version.ts` lets through; it discards
|
|
421
|
+
* nothing there, since rows keep the field) poisoned the journal before it
|
|
394
422
|
* ran, leaving nothing unwound — Quereus keeps the failing step's own message, APPENDS the reason the
|
|
395
423
|
* schema could not be restored, and carries the original as `cause`. So a transient cause
|
|
396
424
|
* underneath still matches here, and neither veto ({@link reportsPossiblyStoredWrite},
|
|
@@ -443,14 +471,26 @@ export function isRetriableSchemaInitFailure(error) {
|
|
|
443
471
|
return matchesRetriableFailure(error, RETRIABLE_SCHEMA_INIT_MATCHERS);
|
|
444
472
|
}
|
|
445
473
|
/**
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
* still declined because a sibling collection landed.
|
|
474
|
+
* {@link isRetriableControlWriteFailure} widened by exactly one class — a lost update
|
|
475
|
+
* ({@link isLostUpdate}), claimed by type — for the `CadrePeer` writers that re-read the row inside
|
|
476
|
+
* their locked body. Opt-in per call site, via {@link LOST_UPDATE_RETRY_POLICY}; both vetoes still
|
|
477
|
+
* run first, so a lost update carried inside a partial commit, a spent sync budget or a non-final
|
|
478
|
+
* torn write stays declined.
|
|
452
479
|
*/
|
|
453
|
-
function
|
|
480
|
+
export function isRetriableLostUpdateFailure(error) {
|
|
481
|
+
return matchesRetriableFailure(error, RETRIABLE_CONTROL_WRITE_MATCHERS, isLostUpdate);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Shared body of the three classifiers: walk the `cause` chain, let
|
|
485
|
+
* {@link reportsPossiblyStoredWrite} and then {@link reportsIndeterminateCommit} veto it, then claim
|
|
486
|
+
* a final torn write ({@link isFinalTornWrite}) or any link `claimsLink` names, then ask `matchers`.
|
|
487
|
+
* The vetoes run BEFORE any claim for every policy — a chain reporting a possibly-stored write or a
|
|
488
|
+
* commit-phase batch is never retried, however transient some other level looks, and a final torn
|
|
489
|
+
* write or a lost update carried by a partial commit is still declined because a sibling collection
|
|
490
|
+
* landed. `claimsLink` is the one typed claim a policy may add; it sits here beside the torn-write
|
|
491
|
+
* claim so the vetoes stay in one place above both.
|
|
492
|
+
*/
|
|
493
|
+
function matchesRetriableFailure(error, matchers, claimsLink) {
|
|
454
494
|
if (!(error instanceof Error)) {
|
|
455
495
|
return false;
|
|
456
496
|
}
|
|
@@ -462,13 +502,13 @@ function matchesRetriableFailure(error, matchers) {
|
|
|
462
502
|
if (reportsIndeterminateCommit(messages)) {
|
|
463
503
|
return false;
|
|
464
504
|
}
|
|
465
|
-
if (links.some(isFinalTornWrite)) {
|
|
505
|
+
if (links.some(link => isFinalTornWrite(link) || claimsLink?.(link) === true)) {
|
|
466
506
|
return true;
|
|
467
507
|
}
|
|
468
508
|
return messages.some(message => matchers.some(matches => matches(message)));
|
|
469
509
|
}
|
|
470
510
|
/**
|
|
471
|
-
* The
|
|
511
|
+
* The schema-init policy: `ControlDatabase.applyControlSchema`'s distributed DDL, which
|
|
472
512
|
* additionally absorbs optimystic's self-coordination grace refusal and gets more attempts over a
|
|
473
513
|
* longer backoff to do it (see {@link SCHEMA_INIT_ATTEMPTS} and
|
|
474
514
|
* {@link SCHEMA_INIT_RETRY_DELAYS_MS}). Still bounded by the shared
|
|
@@ -479,13 +519,41 @@ function matchesRetriableFailure(error, matchers) {
|
|
|
479
519
|
* and verified against the pre-apply catalog (full argument at the `applyControlSchema` call site
|
|
480
520
|
* in `control-database.ts`). A second opt-in must re-derive that argument for its own write body
|
|
481
521
|
* first; if this policy ever grows a third consumer, rename it for what the callers share rather
|
|
482
|
-
* than widening it by default.
|
|
522
|
+
* than widening it by default. {@link LOST_UPDATE_RETRY_POLICY} is a separate policy for a
|
|
523
|
+
* separate class, not a second consumer of this one.
|
|
483
524
|
*/
|
|
484
525
|
export const SCHEMA_INIT_RETRY_POLICY = {
|
|
485
526
|
attempts: SCHEMA_INIT_ATTEMPTS,
|
|
486
527
|
delaysMs: SCHEMA_INIT_RETRY_DELAYS_MS,
|
|
487
528
|
isRetriable: isRetriableSchemaInitFailure,
|
|
488
529
|
};
|
|
530
|
+
/**
|
|
531
|
+
* The lost-update policy: the default classifier plus a lost update claimed by type
|
|
532
|
+
* ({@link isRetriableLostUpdateFailure}), over the default attempts, backoff and budget. A re-run
|
|
533
|
+
* here is a RE-DECISION, not a re-presentation: the body reads the row again under the lock and
|
|
534
|
+
* signs over what it finds, so the write that lost to a rival is replaced by one made over the
|
|
535
|
+
* rival's result. The budget bounds it as it bounds every write — a losing attempt whose read
|
|
536
|
+
* phase waited out one per-peer read deadline (~7.5 s measured in the degraded-cohort scenario's
|
|
537
|
+
* trio boot) gets exactly one retry, which is the ceiling to expect; one that waited out two
|
|
538
|
+
* (14.7 s, measured once in 18 of that scenario's boots, on the member that cannot reach one
|
|
539
|
+
* sibling) gets none and is abandoned on the budget, and the lost publish is then the reconcile
|
|
540
|
+
* pass's or the heartbeat's to redo, as every abandoned self-publish is.
|
|
541
|
+
*
|
|
542
|
+
* NOTE: the re-run safety this policy assumes is each opted-in body's, not a general property. A
|
|
543
|
+
* body may opt in only when its read of the row, its decision and its signature ALL run inside
|
|
544
|
+
* the locked body, so that the re-run presents a write made over the row as it now stands rather
|
|
545
|
+
* than the first attempt's signed record (which the rival may have stamped past, or which may
|
|
546
|
+
* overwrite what the rival wrote). Three `CadrePeer` writers opt in, through
|
|
547
|
+
* `ControlDatabase.mutateCadrePeer`'s policy parameter or `lockedWithRetry` directly:
|
|
548
|
+
* `updateSelfPeerRecord` (re-reads and re-signs the node's own record), `reauthorizeCadrePeer`
|
|
549
|
+
* (re-reads the stamp and decides again whether the row is still the owner's to re-touch) and
|
|
550
|
+
* the two removals `deleteCadrePeer` / `removeMachine` (stamp read and signature already inside
|
|
551
|
+
* the body, and a self-publish never changes the stamp the `'remove'` digest binds). A new opt-in
|
|
552
|
+
* must re-derive that argument for its own body first.
|
|
553
|
+
*/
|
|
554
|
+
export const LOST_UPDATE_RETRY_POLICY = {
|
|
555
|
+
isRetriable: isRetriableLostUpdateFailure,
|
|
556
|
+
};
|
|
489
557
|
/**
|
|
490
558
|
* Run `attempt` up to {@link CONTROL_WRITE_ATTEMPTS} times (or `options.attempts`), retrying only
|
|
491
559
|
* failures the policy's classifier — {@link isRetriableControlWriteFailure} by default —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC9G,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"control-write-retry.js","sourceRoot":"","sources":["../src/control-write-retry.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,9 +65,9 @@ export declare class PersistentEnrolledMachineStore implements EnrolledMachineSt
|
|
|
65
65
|
* Record the count: visible via {@link count} synchronously, then persisted.
|
|
66
66
|
*
|
|
67
67
|
* Writes are SKIPPED when the slot already holds this number, because the sole
|
|
68
|
-
* caller runs on every committed membership write
|
|
69
|
-
*
|
|
70
|
-
* integer forever. The skip is keyed off {@link persisted} rather than
|
|
68
|
+
* caller runs on every membership refresh — each committed membership write, each
|
|
69
|
+
* replicated membership change, and each reconcile pass down to its backstop — so a
|
|
70
|
+
* party whose membership is stable would otherwise rewrite the same integer forever. The skip is keyed off {@link persisted} rather than
|
|
71
71
|
* {@link current}, so a write that FAILED is retried by the next refresh instead
|
|
72
72
|
* of being suppressed as "unchanged".
|
|
73
73
|
*/
|
|
@@ -123,9 +123,9 @@ export class PersistentEnrolledMachineStore {
|
|
|
123
123
|
* Record the count: visible via {@link count} synchronously, then persisted.
|
|
124
124
|
*
|
|
125
125
|
* Writes are SKIPPED when the slot already holds this number, because the sole
|
|
126
|
-
* caller runs on every committed membership write
|
|
127
|
-
*
|
|
128
|
-
* integer forever. The skip is keyed off {@link persisted} rather than
|
|
126
|
+
* caller runs on every membership refresh — each committed membership write, each
|
|
127
|
+
* replicated membership change, and each reconcile pass down to its backstop — so a
|
|
128
|
+
* party whose membership is stable would otherwise rewrite the same integer forever. The skip is keyed off {@link persisted} rather than
|
|
129
129
|
* {@link current}, so a write that FAILED is retried by the next refresh instead
|
|
130
130
|
* of being suppressed as "unchanged".
|
|
131
131
|
*/
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { FormationRejectionCode } from './strand-formation-rejection.js';
|
|
2
|
+
/** The `FormationInvite` columns a formation session acts on. */
|
|
3
|
+
export interface FormationInviteFacts {
|
|
4
|
+
sAppId: string;
|
|
5
|
+
/** Epoch ms of the stored `ExpiresAt`; null when the invitation never expires. */
|
|
6
|
+
expiresAtMs: number | null;
|
|
7
|
+
/** Null is unlimited. */
|
|
8
|
+
totalUses: number | null;
|
|
9
|
+
/** A bound invitation's host strand; null on the responder-provisions path. */
|
|
10
|
+
strandId: string | null;
|
|
11
|
+
/** The outside approval hook; null when no approval is required. */
|
|
12
|
+
validationUrl: string | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One formation token as read once at the start of a responder session. Every later step of
|
|
16
|
+
* the session takes this value instead of reading the invite again.
|
|
17
|
+
*/
|
|
18
|
+
export interface FormationTokenRead {
|
|
19
|
+
token: string;
|
|
20
|
+
/** Null: no invite row here (it may not have replicated to this machine yet). */
|
|
21
|
+
invite: FormationInviteFacts | null;
|
|
22
|
+
/** Uses recorded so far; counted only for a metered, unexpired invite, else null. */
|
|
23
|
+
usesRecorded: number | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* What the responder's token check yields; an invalid token names which way it failed. The
|
|
27
|
+
* valid arm carries the session's {@link FormationTokenRead}, absent only when the manager has
|
|
28
|
+
* no recorder and so accepts every token with nothing read.
|
|
29
|
+
*/
|
|
30
|
+
export type FormationTokenCheck = {
|
|
31
|
+
valid: true;
|
|
32
|
+
read?: FormationTokenRead;
|
|
33
|
+
} | {
|
|
34
|
+
valid: false;
|
|
35
|
+
code: Extract<FormationRejectionCode, 'token-unknown' | 'token-spent'>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* `expiresAtMs <= nowMs` is expired: the same boundary `hasOutstandingFormationInvite` applies,
|
|
39
|
+
* so an invite the formation handler refuses can never hold the connection gate open.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isInviteExpired(invite: FormationInviteFacts, nowMs: number): boolean;
|
|
42
|
+
/** Used up: a metered invite whose recorded uses reached `totalUses`. An unknown token is not used up. */
|
|
43
|
+
export declare function isTokenReadSpent(read: FormationTokenRead): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* No invite row is `'token-unknown'` (retryable: the row may not have replicated to this
|
|
46
|
+
* machine yet); an expired or used-up invite is `'token-spent'` (final).
|
|
47
|
+
*/
|
|
48
|
+
export declare function classifyTokenRead(read: FormationTokenRead, nowMs: number): FormationTokenCheck;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `expiresAtMs <= nowMs` is expired: the same boundary `hasOutstandingFormationInvite` applies,
|
|
3
|
+
* so an invite the formation handler refuses can never hold the connection gate open.
|
|
4
|
+
*/
|
|
5
|
+
export function isInviteExpired(invite, nowMs) {
|
|
6
|
+
return invite.expiresAtMs !== null && invite.expiresAtMs <= nowMs;
|
|
7
|
+
}
|
|
8
|
+
/** Used up: a metered invite whose recorded uses reached `totalUses`. An unknown token is not used up. */
|
|
9
|
+
export function isTokenReadSpent(read) {
|
|
10
|
+
const totalUses = read.invite?.totalUses ?? null;
|
|
11
|
+
return totalUses !== null && read.usesRecorded !== null && read.usesRecorded >= totalUses;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* No invite row is `'token-unknown'` (retryable: the row may not have replicated to this
|
|
15
|
+
* machine yet); an expired or used-up invite is `'token-spent'` (final).
|
|
16
|
+
*/
|
|
17
|
+
export function classifyTokenRead(read, nowMs) {
|
|
18
|
+
if (read.invite === null) {
|
|
19
|
+
return { valid: false, code: 'token-unknown' };
|
|
20
|
+
}
|
|
21
|
+
if (isInviteExpired(read.invite, nowMs) || isTokenReadSpent(read)) {
|
|
22
|
+
return { valid: false, code: 'token-spent' };
|
|
23
|
+
}
|
|
24
|
+
return { valid: true, read };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=formation-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formation-token.js","sourceRoot":"","sources":["../src/formation-token.ts"],"names":[],"mappings":"AAoCA;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAA4B,EAAE,KAAa;IACzE,OAAO,MAAM,CAAC,WAAW,KAAK,IAAI,IAAI,MAAM,CAAC,WAAW,IAAI,KAAK,CAAC;AACpE,CAAC;AAED,0GAA0G;AAC1G,MAAM,UAAU,gBAAgB,CAAC,IAAwB;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,IAAI,CAAC;IACjD,OAAO,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC;AAC5F,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAwB,EAAE,KAAa;IACvE,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IACjD,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC/B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ export { canonicalJson } from './canonical-json.js';
|
|
|
3
3
|
export { CadreNode, CADRE_INVITATION_DEFAULT_TTL_MS, OWNER_GRANT_DEFAULT_TTL_MS } from './cadre-node.js';
|
|
4
4
|
export { MachineRemovalRefusedError } from './machine-removal.js';
|
|
5
5
|
export { OwnerKeyAddRefusedError, OwnerKeyRemovalRefusedError } from './owner-keys.js';
|
|
6
|
-
export { ControlDatabase, parseNullableStoredDatetimeMs, MissingHostStrandError, InvitationExhaustedError, CadreInviteIssuerUnknownError, OwnerGrantIssuerUnknownError, IssuedRowNotHereYetError, buildAuthorizationMessage, registerPartyIdFunction, formationVouchMessage, formationConsentMessage, cadreInviteAddMessage, cadreInviteRedeemMessage, cadreInviteConsentMessage, ownerGrantAddMessage, ownerGrantRedeemMessage, ownerGrantConsentMessage, projectSeedPeers, REAPABLE_TABLES, type ReapableTable, type ControlDatabaseConfig, type ControlTable, type RevocableTable, type FormationUsageResult, type FormationInviteRow, type MembershipChangeListener, type GuardedDeleteListener, type ControlWriteAbandonedListener, type RevokedRowRef, type ControlSign, type OwnerGrantRedemptionFields } from './control-database.js';
|
|
7
|
-
export { CONTROL_SCHEMA_VERSION, CONTROL_SCHEMA_BASELINE_VERSION } from './control-schema.js';
|
|
8
|
-
export { ControlStoreIncompatibleError } from './control-schema-version.js';
|
|
9
|
-
export { CONTROL_WRITE_ATTEMPTS, CONTROL_WRITE_RETRY_BUDGET_MS, SCHEMA_INIT_ATTEMPTS, SCHEMA_INIT_RETRY_POLICY, isRetriableControlWriteFailure, isRetriableSchemaInitFailure, retryControlWrite, type ControlWriteRetryOptions } from './control-write-retry.js';
|
|
6
|
+
export { ControlDatabase, parseNullableStoredDatetimeMs, MissingHostStrandError, InvitationExhaustedError, CadreInviteIssuerUnknownError, OwnerGrantIssuerUnknownError, IssuedRowNotHereYetError, buildAuthorizationMessage, registerPartyIdFunction, formationVouchMessage, formationConsentMessage, cadreInviteAddMessage, cadreInviteRedeemMessage, cadreInviteConsentMessage, ownerGrantAddMessage, ownerGrantRedeemMessage, ownerGrantConsentMessage, projectSeedPeers, REAPABLE_TABLES, type ReapableTable, type ControlDatabaseConfig, type ControlTable, type RevocableTable, type FormationUsageResult, type FormationInviteRow, type FoundingRows, type FoundingInvite, type MembershipChangeListener, type GuardedDeleteListener, type ControlWriteAbandonedListener, type RevokedRowRef, type ControlSign, type SelfRecordSigner, type CadrePeerRetouchMode, type CadrePeerRetouchOutcome, type OwnerGrantRedemptionFields } from './control-database.js';
|
|
7
|
+
export { CONTROL_SCHEMA_VERSION, CONTROL_SCHEMA_BASELINE_VERSION, CONTROL_SCHEMA_VERSION_TAG } from './control-schema.js';
|
|
8
|
+
export { ControlStoreIncompatibleError, type ControlStoreIncompatibility } from './control-schema-version.js';
|
|
9
|
+
export { CONTROL_WRITE_ATTEMPTS, CONTROL_WRITE_RETRY_BUDGET_MS, LOST_UPDATE_RETRY_POLICY, SCHEMA_INIT_ATTEMPTS, SCHEMA_INIT_RETRY_POLICY, isRetriableControlWriteFailure, isRetriableLostUpdateFailure, isRetriableSchemaInitFailure, retryControlWrite, type ControlWriteRetryOptions } from './control-write-retry.js';
|
|
10
10
|
export { CONTROL_READ_ATTEMPTS, CONTROL_READ_RETRY_DELAYS_MS, CONTROL_READ_RETRY_BUDGET_MS, isRetriableControlReadFailure, retryControlRead, type ControlReadRetryOptions } from './control-read-retry.js';
|
|
11
11
|
export type { ControlRetryAbandonment, ControlRetryAbandonReason, ControlRetryAbandonListener } from './control-retry.js';
|
|
12
12
|
export { controlAuthorizationFields, unboundAuthorizationFields, cadreInviteRowFields, ownerGrantRowFields, type ControlDomain, type BoundControlDomain, type UnboundControlDomain, type ControlAction, type CadreInviteSignedFields, type OwnerGrantSignedFields } from './control-authorization.js';
|
|
@@ -30,23 +30,23 @@ export { StrandDatabase, type StrandDatabaseConfig } from './strand-database.js'
|
|
|
30
30
|
export type { StrandCommitDurability, StrandCommitHeld } from './strand-commit-durability.js';
|
|
31
31
|
export { StrandWatcher, type StrandWatcherCallbacks, type StrandQueryable, type SAppIdLookup, type StrandRowWithApp } from './strand-watcher.js';
|
|
32
32
|
export { StrandInstanceManager, type StartStrandConfig, type ResumeStrandOverrides, getStrandStoragePath, isAwaitingFirstSync, liveStrandStatus } from './strand-instance-manager.js';
|
|
33
|
-
export { StrandAwaitingFirstSyncError, DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS,
|
|
33
|
+
export { StrandAwaitingFirstSyncError, DEFAULT_STRAND_FIRST_SYNC_TIMEOUT_MS, DEFAULT_STRAND_FIRST_SYNC_BACKSTOP_MS, type StrandFirstSyncConfig } from './strand-first-sync-gate.js';
|
|
34
34
|
export { PeerJoinBackfill, DEFAULT_PEER_JOIN_BACKFILL, MAX_BLOCK_MESSAGE_BYTES, PEER_JOIN_BACKFILL_WARN_AFTER_FAILURES, type PeerJoinBackfillConfig, type PeerJoinBackfillDeps, type PeerJoinBackfillResult, type PeerJoinBackfillPushClient } from './peer-join-backfill.js';
|
|
35
35
|
export { strandCohortTopicOption, type StrandReactivityConfig } from './strand-reactivity.js';
|
|
36
|
-
export { StrandRevocationEnforcer, createRevocationConnectionGater, readStrandRevocationRows,
|
|
37
|
-
export { StrandMembershipReconciler, IDLE_PASSES_BEFORE_ESCALATION, INITIAL_JOIN_RETRY_INTERVAL_MS, type StrandMembershipReconcilerDeps, type StrandMembershipReconciliationConfig, type PendingMembershipInviteSource } from './strand-membership-reconciler.js';
|
|
36
|
+
export { StrandRevocationEnforcer, createRevocationConnectionGater, readStrandRevocationRows, DEFAULT_REVOCATION_BACKSTOP_MS, REVOCATION_REFRESH_RETRY_MS, REVOCATION_WIDE_STRAND_REFRESH_MS, type StrandRevocationEnforcementConfig, type StrandRevocationEnforcerDeps, type StrandRevocationRows, type StrandMemberPeerBinding, type StrandRevocationJudge, type StrandRevocationNetwork } from './strand-revocation-enforcer.js';
|
|
37
|
+
export { StrandMembershipReconciler, DEFAULT_MEMBERSHIP_RECONCILE_INTERVAL_MS, IDLE_PASSES_BEFORE_ESCALATION, INITIAL_JOIN_RETRY_INTERVAL_MS, type StrandMembershipReconcilerDeps, type StrandMembershipReconciliationConfig, type PendingMembershipInviteSource } from './strand-membership-reconciler.js';
|
|
38
38
|
export { defaultTimeoutScheduler, type TimeoutScheduler } from './timeout-scheduler.js';
|
|
39
39
|
export { HibernationManager, type HibernationCallbacks } from './hibernation-manager.js';
|
|
40
40
|
export { ArachnodeStub, createArachnodeStub, type RingConfig } from './arachnode-stub.js';
|
|
41
41
|
export { EnrollmentService, type MemberVerifier, type MemberRegistry } from './enrollment.js';
|
|
42
|
-
export { StrandSolicitationService, createDefaultFormationResponseValidator, type DisclosureValidator, type FormationUsageRecorder, type FormationUsageParams, type AuthorizedFormationUsage, type ResolvedHostStrand, type StrandProvisioner, type FormationResponseValidator, type StrandSolicitationServiceOptions } from './strand-solicitation.js';
|
|
42
|
+
export { StrandSolicitationService, createDefaultFormationResponseValidator, type DisclosureValidator, type FormationUsageRecorder, type FormationUsageParams, type AuthorizedFormationUsage, type BoundHostStrand, type ResolvedHostStrand, type StrandProvisioner, type FormationResponseValidator, type StrandSolicitationServiceOptions } from './strand-solicitation.js';
|
|
43
43
|
export { createHttpFormationApprover, signFormationApproval, verifyFormationApproval, FormationApprovalError, type FormationApprovalRequest, type FormationVouchFields, type FormationApproval, type FormationApprover, type FormationApprovalFailure } from './formation-approval.js';
|
|
44
44
|
export { ControlFormationUsageRecorder } from './control-formation-recorder.js';
|
|
45
45
|
export { generateStrandMemberKey, strandMemberKeyPair } from './strand-member-key.js';
|
|
46
46
|
export { signStrandPayload, verifyStrandPayload, signStrandApproval, generateStrandStampId, bootstrapFounderMembership, PreSplitStrandIdentityError, issueInvite, consumeInvite, burnInvite, isStrandMember, cancelInvite, listOutstandingInvites, addMemberByManager, revokeMember, leaveStrand, registerMemberPeer, listMemberPeers, removeMemberPeer, addManager, admitManager, removeManager, sealStrand, isStrandSealed, StrandTransactionBusyError, STRAND_ENGINE, STRAND_ENGINE_VERSION, type FounderBootstrapParams, type IssueInviteParams, type IssuedInvite, type ConsumeInviteParams, type CancelInviteParams, type OutstandingInvite, type AddMemberByManagerParams, type RevokeMemberParams, type LeaveStrandParams, type RegisterMemberPeerParams, type RemoveOwnPeerParams, type RemoveMemberPeerByManagerParams, type RemoveMemberPeerParams, type AddManagerParams, type AdmitManagerParams, type RemoveManagerParams, type SealStrandParams, type StrandWriteOptions } from './strand-membership-writer.js';
|
|
47
47
|
export { canonicalDatetime } from './canonical-datetime.js';
|
|
48
48
|
export { StrandMemberRegistry, StrandMemberVerifier, memberRegistrationPayload, type StrandAdmission } from './strand-member-registry.js';
|
|
49
|
-
export { SeedBootstrapService, SEED_PROTOCOL, mergeSeedPeers, seedDigest, type SeedBootstrapConfig, type SeedEventCallbacks } from './seed-bootstrap.js';
|
|
49
|
+
export { SeedBootstrapService, SEED_PROTOCOL, mergeSeedPeers, seedDialTargets, seedDigest, type SeedBootstrapConfig, type SeedEventCallbacks } from './seed-bootstrap.js';
|
|
50
50
|
export { peerAuthorizationDigest, cadrePeerVoucherDigest, cadrePeerRemoveDigest, deviceTokenAddDigest, deviceTokenRemoveDigest, formationConsentDigest, cadreInviteAddDigest, cadreInviteRedeemDigest, cadreInviteConsentDigest, ownerKeyAddDigest, verifyPeerAuthorization, verifyCadrePeerVoucher, verifyOwnerKeyVoucher, verifyRevocationSigner, verifyFormationConsent, verifyInvitationAdmission, verifyCadreInviteRow, verifyCadreInviteRedemption, ownerGrantAddDigest, ownerGrantRedeemDigest, ownerGrantConsentDigest, verifyOwnerGrantRow, verifyOwnerGrantRedemption, verifyOwnerGrantAdmission, type DeviceTokenAuthorizedRow } from './peer-authorization.js';
|
|
51
51
|
export { deriveOwnerAnchor, type OwnerAnchorInputs, type OwnerAnchorDerivation } from './owner-anchor-sync.js';
|
|
52
52
|
export { StrandWakeService, dialWake, WAKE_PROTOCOL, DEFAULT_WAKE_DIAL_BUDGET_MS, type StrandWakeServiceOptions, type DialWakeOptions } from './strand-wake-protocol.js';
|
|
@@ -57,7 +57,7 @@ export { STRAND_WAKE_TYPE, type StrandWakePayload } from './strand-wake-payload.
|
|
|
57
57
|
export type { PushNotifier, PushMessage, PushSendResult } from './push-notifier.js';
|
|
58
58
|
export { validatePushCredentials, redactPushCredentials, REDACTED } from './push-credentials.js';
|
|
59
59
|
export { PushFanoutService, DEFAULT_PUSH_COOLDOWN_MS, DEFAULT_PUSH_DEBOUNCE_MS, type PushFanoutOptions, type FanoutMember } from './push-fanout.js';
|
|
60
|
-
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE, type ControlCohortSelection, type ControlCohortReconcileResult } from './control-cohort.js';
|
|
60
|
+
export { selectControlCohortDials, DEFAULT_CONTROL_COHORT_RECONCILE_MS, DEFAULT_CONTROL_COHORT_TARGET_DEGREE, CONTROL_COHORT_REDIAL_MS, type ControlCohortSelection, type ControlCohortReconcileResult } from './control-cohort.js';
|
|
61
61
|
export { dialAddr, withTrailingPeerId, dialPeerAddrs, SelfRelayOnlyError, PeerUnreachableError, tryAddrsInTurn, directBeforeRelayed, DEFAULT_CONTROL_COHORT_DIAL_TIMEOUT_MS, DEFAULT_CONTROL_COHORT_PER_ADDRESS_DIAL_TIMEOUT_MS, CONTROL_COHORT_DIAL_ADDRESS_ATTEMPTS, DEFAULT_PEER_DIAL_BUDGET, type PeerDialBudget, type AddrDialer } from './peer-dial.js';
|
|
62
62
|
export { DECLARED_LINK_ROUND_TRIP_MS, CIRCUIT_DIAL_ROUND_TRIPS, RELAY_DIAL_ROUND_TRIPS, RELAYED_DIAL_ROUND_TRIPS, RELAY_RESERVATION_ROUND_TRIPS, CIRCUIT_REQUEST_ROUND_TRIPS, RELAYED_REQUEST_ROUND_TRIPS, PUSH_TRANSFER_ALLOWANCE_MS, ADMISSION_DECISION_TIMEOUT_MS, resolveLinkRoundTripMs, relayedDialBudgetMs, relayReservationBudgetMs, circuitRequestBudgetMs, relayedRequestBudgetMs, peerJoinPushBudget, type PeerJoinPushBudget, DIAL_ADMISSION_DECISIONS, optimysticDialLimits, type OptimysticDialLimits } from './link-budget.js';
|
|
63
63
|
export { anchoredTrustPolicy, pinnedKeyTrustPolicy, tofuTrustPolicy, claimSecretTrustPolicy, type SeedTrustPolicy, type SeedTrustContext, type SeedTrustDecision, type ClaimSecretTrustPolicyOptions } from './seed-trust-policy.js';
|
|
@@ -67,14 +67,15 @@ export { exportStrandBundle, adoptStrandBundle, readStrandHoldings, unheldBundle
|
|
|
67
67
|
export { encodeCadreJoinRequest, decodeCadreJoinRequest, requireCadreJoinReply, CADRE_JOIN_REQUEST_PREFIX, CADRE_INVITATION_PREFIX, OWNER_KEY_EXPORT_STEM, OWNER_GRANT_PREFIX, CADRE_JOIN_REQUEST_MAX_APP_NAME, type CadreJoinReply, type CadreJoinRequest } from './cadre-join-request.js';
|
|
68
68
|
export * from './provider/index.js';
|
|
69
69
|
export { signSchema, verifySchema, assertSchemaSignature, SchemaVerificationError } from './schema-verification.js';
|
|
70
|
-
export { FormationListener, dialFormation, dialFormationByMachine, isValidResponderCreatesResult, isWellFormedMembershipInvite, sanitizeStrandAddrs, FORMATION_PROTOCOL, type FormationParty, type FormationContactMessage, type FormationResultMessage, type FormationProvisionResult, type FormationStrandInfo, type FormationDbConnectionInfo, type FormationListenerOptions, type FormationDialOptions, type FormationDialResult, type FormationRejection, type
|
|
70
|
+
export { FormationListener, dialFormation, dialFormationByMachine, isValidResponderCreatesResult, isWellFormedMembershipInvite, sanitizeStrandAddrs, FORMATION_PROTOCOL, type FormationParty, type FormationContactMessage, type FormationResultMessage, type FormationProvisionResult, type FormationStrandInfo, type FormationDbConnectionInfo, type FormationListenerOptions, type FormationDialOptions, type FormationDialResult, type FormationRejection, type ResponderProvisionOutcome } from './strand-formation-protocol.js';
|
|
71
|
+
export { classifyTokenRead, isTokenReadSpent, type FormationInviteFacts, type FormationTokenRead, type FormationTokenCheck } from './formation-token.js';
|
|
71
72
|
export { FormationRejectedError, FormationUnreachableError, FormationPostApprovalError, FORMATION_REJECTION_RETRYABLE, isFormationRejectionCode, type FormationRejectionCode } from './strand-formation-rejection.js';
|
|
72
73
|
export { formationDeadlines, type FormationDeadlines } from './strand-formation-deadlines.js';
|
|
73
|
-
export { CadreInviteHandler, redeemAtMembers, redeemInPasses, signRedeemRequest, verifyRedeemReply, encodeCadreInvitation, decodeCadreInvitation, isWellFormedCadreInviteRow, sanitizeAddrs, CadreInviteRejectedError, CadreInviteUnreachableError, CadreInviteReplyInvalidError, CADRE_INVITE_PROTOCOL, CADRE_INVITE_REJECTION_RETRYABLE, isCadreInviteRejectionCode, type CadreInvitation, type CadreInviteRedeemRequest, type CadreInviteRedeemReply, type CadreInviteAccepted, type CadreInviteRejectionCode, type CadreInviteAddressOutcome, type CadreInviteHandlerOptions, type CadreInviteStore, type RedeemAtMembersOptions, type RedeemInPassesOptions, type RedeemSigner, type CadreInviteRedemption } from './cadre-invite-protocol.js';
|
|
74
|
+
export { CadreInviteHandler, redeemAtMembers, redeemInPasses, signRedeemRequest, verifyRedeemReply, encodeCadreInvitation, decodeCadreInvitation, isWellFormedCadreInviteRow, sanitizeAddrs, CadreInviteRejectedError, CadreInviteUnreachableError, CadreInviteReplyInvalidError, CADRE_INVITE_PROTOCOL, CADRE_INVITE_REJECTION_RETRYABLE, isCadreInviteRejectionCode, type CadreInvitation, type CadreInviteRedeemRequest, type CadreInviteRedeemReply, type CadreInviteAccepted, type CadreInviteRejectionCode, type CadreInviteAddressOutcome, type CadreInviteHandlerOptions, type CadreInviteStore, type RedeemAtMembersOptions, type RedeemInPassesOptions, type RedeemSigner, type RedeemSelfRecord, type CadreInviteRedemption } from './cadre-invite-protocol.js';
|
|
74
75
|
export { OwnerGrantHandler, redeemOwnerGrantAtMembers, redeemOwnerGrantInPasses, signOwnerGrantRequest, verifyOwnerGrantReply, encodeOwnerGrant, decodeOwnerGrant, isWellFormedOwnerGrantRow, OwnerGrantRejectedError, OwnerGrantUnreachableError, OwnerGrantReplyInvalidError, OWNER_GRANT_PROTOCOL, OWNER_GRANT_REJECTION_RETRYABLE, isOwnerGrantRejectionCode, type OwnerGrantBundle, type OwnerGrantRedeemRequest, type OwnerGrantRedeemReply, type OwnerGrantAccepted, type OwnerGrantRejectionCode, type OwnerGrantHandlerOptions, type OwnerGrantStore, type RedeemOwnerGrantAtMembersOptions, type RedeemOwnerGrantInPassesOptions, type OwnerGrantRedemption } from './owner-grant-protocol.js';
|
|
75
76
|
export { MemberRedemptionHandler, dialRedemption, dialRedemptionInPasses, MAX_REDEMPTION_FRAME_BYTES, type MemberRedemptionHandlerOptions, type MemberRedemptionOptions, type MemberRedemptionPassOptions, type MemberRedemption, type RedemptionAddressOutcome, type RedemptionRejection, type RedemptionRefusalFrame } from './member-redemption.js';
|
|
76
77
|
export { selectCadreInvitationMembers, cadreInvitationReach, CADRE_INVITATION_MAX_ADDRS, CADRE_INVITATION_ADDRS_PER_SIBLING } from './invitation-bootstrap.js';
|
|
77
|
-
export {
|
|
78
|
+
export { PENDING_JOIN_BACKSTOP_MS, PENDING_JOIN_MAX_BACKOFF_MS, MAX_PENDING_JOIN_MS } from './pending-join-runner.js';
|
|
78
79
|
export { StrandFormationManager, createStrandFormationManager, MEMBERSHIP_INVITE_TTL_MS, MEMBERSHIP_INVITE_UNAVAILABLE_REASON, HOST_STRAND_MUST_BE_RECREATED_REASON, type CadrePeerAddrsSource, type MembershipInviteIssuer, type StrandFormationManagerConfig, type StrandFormationManagerOptions } from './strand-formation-manager.js';
|
|
79
80
|
export { controlProtocolClasses, type ControlProtocolClass } from './control-protocol-guard.js';
|
|
80
81
|
export { createMembershipConnectionGater, PROVISIONAL_ADMISSION_DEADLINE_MS, PROVISIONAL_ADMISSION_CLOSE_TIMEOUT_MS, MAX_UNAUTHORIZED_RELAY_RESERVATIONS, UnauthorizedReservationBudget, type InboundAdmissionPolicy, type InboundConnectionVerdict } from './membership-connection-gater.js';
|