@serfab/cadre-core 1.16.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 +4 -3
- package/dist/bootstrap-peer-store-file.js +1 -1
- package/dist/bootstrap-peer-store.d.ts +1 -1
- package/dist/bootstrap-peer-store.js +4 -4
- package/dist/cadre-invite-protocol.d.ts +81 -142
- package/dist/cadre-invite-protocol.js +168 -458
- package/dist/cadre-invite-protocol.js.map +1 -1
- package/dist/cadre-join-request.d.ts +15 -2
- package/dist/cadre-join-request.js +22 -3
- package/dist/cadre-join-request.js.map +1 -1
- package/dist/cadre-node.d.ts +1089 -475
- package/dist/cadre-node.js +2170 -1037
- package/dist/cadre-node.js.map +1 -1
- package/dist/control-authorization.d.ts +36 -14
- package/dist/control-authorization.js +20 -3
- package/dist/control-authorization.js.map +1 -1
- package/dist/control-cohort.d.ts +88 -32
- package/dist/control-cohort.js +91 -33
- package/dist/control-cohort.js.map +1 -1
- package/dist/control-database.d.ts +856 -318
- package/dist/control-database.js +1422 -701
- 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 +11 -4
- package/dist/control-protocol-guard.js +20 -5
- package/dist/control-protocol-guard.js.map +1 -1
- package/dist/control-schema-version.d.ts +97 -0
- package/dist/control-schema-version.js +225 -0
- package/dist/control-schema-version.js.map +1 -0
- package/dist/control-schema.d.ts +45 -5
- package/dist/control-schema.js +262 -78
- package/dist/control-schema.js.map +1 -1
- package/dist/control-write-retry.d.ts +45 -10
- package/dist/control-write-retry.js +92 -22
- package/dist/control-write-retry.js.map +1 -1
- package/dist/delegate-admission.d.ts +13 -0
- package/dist/delegate-admission.js +27 -0
- package/dist/delegate-admission.js.map +1 -1
- package/dist/ed25519-key.d.ts +10 -7
- package/dist/ed25519-key.js +23 -20
- package/dist/ed25519-key.js.map +1 -1
- package/dist/edge-node/config.d.ts +122 -0
- package/dist/edge-node/config.js +199 -0
- package/dist/edge-node/config.js.map +1 -0
- package/dist/edge-node/dissolve.d.ts +95 -0
- package/dist/edge-node/dissolve.js +184 -0
- package/dist/edge-node/dissolve.js.map +1 -0
- package/dist/edge-node/edge-join.d.ts +44 -0
- package/dist/edge-node/edge-join.js +227 -0
- package/dist/edge-node/edge-join.js.map +1 -0
- package/dist/edge-node/edge-node.d.ts +295 -0
- package/dist/edge-node/edge-node.js +704 -0
- package/dist/edge-node/edge-node.js.map +1 -0
- package/dist/edge-node/index.d.ts +18 -0
- package/dist/edge-node/index.js +18 -0
- package/dist/edge-node/index.js.map +1 -0
- package/dist/edge-node/join-credential.d.ts +11 -0
- package/dist/edge-node/join-credential.js +11 -0
- package/dist/edge-node/join-credential.js.map +1 -0
- package/dist/edge-node/lazy-raw-storage.d.ts +40 -0
- package/dist/edge-node/lazy-raw-storage.js +134 -0
- package/dist/edge-node/lazy-raw-storage.js.map +1 -0
- package/dist/edge-node/node-local.d.ts +60 -0
- package/dist/edge-node/node-local.js +58 -0
- package/dist/edge-node/node-local.js.map +1 -0
- package/dist/edge-node/options.d.ts +83 -0
- package/dist/edge-node/options.js +110 -0
- package/dist/edge-node/options.js.map +1 -0
- package/dist/edge-node/owner-grant.d.ts +41 -0
- package/dist/edge-node/owner-grant.js +38 -0
- package/dist/edge-node/owner-grant.js.map +1 -0
- package/dist/edge-node/platform.d.ts +140 -0
- package/dist/edge-node/platform.js +12 -0
- package/dist/edge-node/platform.js.map +1 -0
- package/dist/edge-node/strand-move.d.ts +115 -0
- package/dist/edge-node/strand-move.js +223 -0
- package/dist/edge-node/strand-move.js.map +1 -0
- package/dist/edge-node/strands.d.ts +28 -0
- package/dist/edge-node/strands.js +60 -0
- package/dist/edge-node/strands.js.map +1 -0
- 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 +27 -17
- package/dist/index.js +39 -17
- package/dist/index.js.map +1 -1
- package/dist/joined-strand-store.d.ts +29 -12
- package/dist/joined-strand-store.js +66 -27
- package/dist/joined-strand-store.js.map +1 -1
- package/dist/key-store.d.ts +9 -4
- package/dist/key-store.js +9 -4
- package/dist/key-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/machine-removal.d.ts +19 -39
- package/dist/machine-removal.js +24 -98
- package/dist/machine-removal.js.map +1 -1
- package/dist/member-redemption.d.ts +256 -0
- package/dist/member-redemption.js +490 -0
- package/dist/member-redemption.js.map +1 -0
- 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-anchor-sync.d.ts +4 -4
- package/dist/owner-anchor-sync.js +16 -15
- package/dist/owner-anchor-sync.js.map +1 -1
- package/dist/owner-grant-protocol.d.ts +251 -0
- package/dist/owner-grant-protocol.js +344 -0
- package/dist/owner-grant-protocol.js.map +1 -0
- package/dist/owner-key-export.d.ts +70 -0
- package/dist/owner-key-export.js +279 -0
- package/dist/owner-key-export.js.map +1 -0
- package/dist/owner-key-flows.d.ts +55 -0
- package/dist/owner-key-flows.js +60 -0
- package/dist/owner-key-flows.js.map +1 -0
- package/dist/owner-key-store.d.ts +31 -0
- package/dist/owner-key-store.js +81 -0
- package/dist/owner-key-store.js.map +1 -0
- package/dist/owner-keys.d.ts +78 -0
- package/dist/owner-keys.js +133 -0
- package/dist/owner-keys.js.map +1 -0
- package/dist/owner-signer.d.ts +54 -0
- package/dist/owner-signer.js +51 -0
- package/dist/owner-signer.js.map +1 -0
- 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-authorization.d.ts +83 -18
- package/dist/peer-authorization.js +123 -53
- package/dist/peer-authorization.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/provider/rent-node.js +1 -1
- package/dist/provider/rent-node.js.map +1 -1
- package/dist/seed-bootstrap.d.ts +162 -133
- package/dist/seed-bootstrap.js +300 -283
- package/dist/seed-bootstrap.js.map +1 -1
- package/dist/seed-trust-policy.js +4 -4
- package/dist/strand-addr-protocol.d.ts +4 -1
- package/dist/strand-addr-protocol.js +8 -2
- package/dist/strand-addr-protocol.js.map +1 -1
- package/dist/strand-cohort.d.ts +3 -0
- package/dist/strand-cohort.js.map +1 -1
- package/dist/strand-database.d.ts +24 -2
- package/dist/strand-database.js +29 -6
- package/dist/strand-database.js.map +1 -1
- package/dist/strand-first-sync-gate.d.ts +176 -88
- package/dist/strand-first-sync-gate.js +288 -121
- 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 +27 -18
- 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 +45 -22
- package/dist/strand-membership-writer.js +226 -131
- package/dist/strand-membership-writer.js.map +1 -1
- package/dist/strand-move.d.ts +6 -5
- package/dist/strand-move.js +36 -32
- package/dist/strand-move.js.map +1 -1
- package/dist/strand-peer-redial.js +2 -3
- package/dist/strand-peer-redial.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 +374 -150
- package/dist/types.js +4 -4
- package/dist/types.js.map +1 -1
- package/package.json +17 -8
- package/src/bootstrap-peer-store-file.ts +44 -44
- package/src/bootstrap-peer-store.ts +214 -214
- package/src/cadre-invite-protocol.ts +740 -1052
- package/src/cadre-join-request.ts +24 -3
- package/src/cadre-node.ts +2402 -1079
- package/src/control-authorization.ts +47 -14
- package/src/control-cohort.ts +204 -128
- package/src/control-database.ts +1749 -820
- package/src/control-formation-recorder.ts +359 -353
- package/src/control-protocol-guard.ts +23 -6
- package/src/control-schema-version.ts +301 -0
- package/src/control-schema.ts +273 -78
- package/src/control-write-retry.ts +641 -567
- package/src/delegate-admission.ts +351 -314
- package/src/ed25519-key.ts +174 -171
- package/src/edge-node/config.ts +277 -0
- package/src/edge-node/dissolve.ts +251 -0
- package/src/edge-node/edge-join.ts +319 -0
- package/src/edge-node/edge-node.ts +1045 -0
- package/src/edge-node/index.ts +59 -0
- package/src/edge-node/join-credential.ts +16 -0
- package/src/edge-node/lazy-raw-storage.ts +178 -0
- package/src/edge-node/node-local.ts +84 -0
- package/src/edge-node/options.ts +179 -0
- package/src/edge-node/owner-grant.ts +63 -0
- package/src/edge-node/platform.ts +151 -0
- package/src/edge-node/strand-move.ts +270 -0
- package/src/edge-node/strands.ts +72 -0
- package/src/enrolled-machine-store.ts +3 -3
- package/src/formation-token.ts +63 -0
- package/src/index.ts +899 -789
- package/src/joined-strand-store.ts +73 -28
- package/src/key-store.ts +10 -4
- package/src/link-budget.ts +9 -7
- package/src/machine-removal.ts +26 -111
- package/src/member-redemption.ts +649 -0
- package/src/membership-view.ts +144 -0
- package/src/owner-anchor-sync.ts +19 -18
- package/src/owner-grant-protocol.ts +547 -0
- package/src/owner-key-export.ts +348 -0
- package/src/owner-key-flows.ts +109 -0
- package/src/owner-key-store.ts +85 -0
- package/src/owner-keys.ts +178 -0
- package/src/owner-signer.ts +94 -0
- package/src/peer-addr-book.ts +4 -3
- package/src/peer-authorization.ts +558 -488
- package/src/peer-join-backfill.ts +971 -761
- package/src/pending-join-runner.ts +76 -53
- package/src/provider/rent-node.ts +1 -1
- package/src/seed-bootstrap.ts +343 -349
- package/src/seed-trust-policy.ts +4 -4
- package/src/strand-addr-protocol.ts +547 -538
- package/src/strand-cohort.ts +4 -0
- package/src/strand-database.ts +352 -319
- package/src/strand-first-sync-gate.ts +334 -133
- 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 -1974
- package/src/strand-move.ts +50 -38
- package/src/strand-peer-redial.ts +2 -3
- 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 +391 -152
|
@@ -219,8 +219,8 @@ async function execStrandTransaction(db, statements, options) {
|
|
|
219
219
|
*/
|
|
220
220
|
function revocationStatement(tableName, stampId, retiree) {
|
|
221
221
|
return {
|
|
222
|
-
sql: `insert into Strand.Revocation (TableName, StampId)
|
|
223
|
-
with context MemberKey = :revocationSignerKey, Signature = :revocationSignature
|
|
222
|
+
sql: `insert into Strand.Revocation (TableName, StampId)
|
|
223
|
+
with context MemberKey = :revocationSignerKey, Signature = :revocationSignature
|
|
224
224
|
values (:revocationTable, :revocationStampId);`,
|
|
225
225
|
params: {
|
|
226
226
|
revocationSignerKey: retiree.publicKeyB64,
|
|
@@ -276,12 +276,6 @@ async function strandTableCount(db, table) {
|
|
|
276
276
|
* `Revocation` schema comment already flags, tracked by `debt-strand-tombstone-reap`
|
|
277
277
|
* — this wants a stored "founding closed" marker rather than a scan per call.
|
|
278
278
|
*
|
|
279
|
-
* NOTE: on a strand that has never revoked anyone, `Strand.Revocation` has never been
|
|
280
|
-
* written, so this node does not hold its block, and the storage layer consults the
|
|
281
|
-
* block's cohort on every read of a block it does not hold — this scan and every
|
|
282
|
-
* `NotRevoked` insert check pay that per call. Not measured, and cheap while strand
|
|
283
|
-
* membership writes are rare; if they become frequent, file a singleton marker row in
|
|
284
|
-
* the strand schema the way the control schema does (`ControlDatabase.openRevocationLedger`).
|
|
285
279
|
*/
|
|
286
280
|
async function strandHasManagerRevocation(db) {
|
|
287
281
|
for await (const row of db.eval('select TableName from Strand.Revocation')) {
|
|
@@ -292,7 +286,37 @@ async function strandHasManagerRevocation(db) {
|
|
|
292
286
|
return false;
|
|
293
287
|
}
|
|
294
288
|
/**
|
|
295
|
-
*
|
|
289
|
+
* Commit an empty collection for every table the strand declares except `writtenTables`, so a
|
|
290
|
+
* read of a table nobody has written is answered from local storage instead of asking the
|
|
291
|
+
* block's cohort to prove the collection absent, and still answers with the other members
|
|
292
|
+
* offline. Peer-join backfill hands these collections to every joiner. The founding
|
|
293
|
+
* transaction's own tables are left out because its inserts create their collections anyway.
|
|
294
|
+
*
|
|
295
|
+
* Only while the Header is absent, and before the founding transaction writes it: a machine
|
|
296
|
+
* cannot write to a strand before it holds the Header (`strand-first-sync-gate.ts`), so no other
|
|
297
|
+
* machine can yet have created any of these collections and this cannot fork one. On a founder
|
|
298
|
+
* restart the Header is present and this does not run; running it there could commit an empty
|
|
299
|
+
* second history beside a table a joiner wrote while the founder was away. A crash between this
|
|
300
|
+
* and the founding commit repeats it on the next run, which commits only the collections still
|
|
301
|
+
* missing.
|
|
302
|
+
*
|
|
303
|
+
* NOTE: one `sync()` per collection, in sequence. Measured 2026-10-17 on a lone node over the
|
|
304
|
+
* network transactor (`connectToStrand`, then the step alone, 3 runs each): a nine-table app
|
|
305
|
+
* schema (20 collections with the strand's own) took 32–82 ms in memory and 465–486 ms on
|
|
306
|
+
* `FileRawStorage`; the reference chat schema (13 collections) 19–30 ms and 298–350 ms. About
|
|
307
|
+
* 23 ms per collection on disk, once per strand, before `foundStrand` returns. Leaving out the
|
|
308
|
+
* founding transaction's tables brings the chat schema to 6 collections on a closed strand whose
|
|
309
|
+
* founder binds its peer, and 12 on an open one. If founding latency starts to matter (slower
|
|
310
|
+
* phone storage, much larger schemas), commit them as one batch through a coordinator, the way
|
|
311
|
+
* the transaction bridge's `commitBatchLegacy` does.
|
|
312
|
+
*/
|
|
313
|
+
async function createDeclaredCollections(params, writtenTables) {
|
|
314
|
+
const t0 = performance.now();
|
|
315
|
+
const committed = await params.createEmptyCollections(writtenTables);
|
|
316
|
+
log('Committed %d empty collections for strand %s in %dms', committed, params.strandId, Math.round(performance.now() - t0));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* The singleton `Strand.Header` insert.
|
|
296
320
|
*
|
|
297
321
|
* Every `Header` column is NOT NULL (Quereus defaults unqualified columns to NOT
|
|
298
322
|
* NULL; the table declares no `null` columns), so all eight are supplied non-null.
|
|
@@ -300,88 +324,127 @@ async function strandHasManagerRevocation(db) {
|
|
|
300
324
|
* rather than inserting null. `Header` carries only `InsertOnly` + a singleton PK,
|
|
301
325
|
* so the insert needs no `with context`.
|
|
302
326
|
*/
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
327
|
+
function headerRow(params) {
|
|
328
|
+
return {
|
|
329
|
+
table: 'Strand.Header',
|
|
330
|
+
statements: {
|
|
331
|
+
sql: `insert into Strand.Header
|
|
332
|
+
(Id, Type, sAppId, sAppVersion, sAppSchema, sAppSignature, Engine, EngineVersion)
|
|
333
|
+
values (:headerId, :headerType, :headerSAppId, :headerSAppVersion, :headerSAppSchema,
|
|
334
|
+
:headerSAppSignature, :headerEngine, :headerEngineVersion);`,
|
|
335
|
+
params: {
|
|
336
|
+
headerId: params.strandId,
|
|
337
|
+
headerType: params.type,
|
|
338
|
+
headerSAppId: params.sApp.id,
|
|
339
|
+
headerSAppVersion: params.sApp.version,
|
|
340
|
+
headerSAppSchema: params.sApp.schema,
|
|
341
|
+
headerSAppSignature: params.sApp.signature ?? '',
|
|
342
|
+
headerEngine: STRAND_ENGINE,
|
|
343
|
+
headerEngineVersion: STRAND_ENGINE_VERSION,
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
};
|
|
321
347
|
}
|
|
322
348
|
/**
|
|
323
|
-
*
|
|
349
|
+
* The founding `Strand.Member` insert.
|
|
324
350
|
*
|
|
325
351
|
* The empty PRE-transaction member set (`count(1) from committed.Member = 0`)
|
|
326
352
|
* satisfies the bootstrap branch of `Member.Authorized`, so no signature is
|
|
327
353
|
* needed — the context fields are explicit nulls. The branch also caps the
|
|
328
354
|
* POST-image at one member, so it waives authorization for exactly this single
|
|
329
355
|
* seat, never for a batch. The row still mints a fresh StampId — the column is
|
|
330
|
-
* NOT NULL on every path; bootstrap only waives the SIGNATURE.
|
|
331
|
-
* count makes this idempotent: a re-run (the founder re-`addStrand`/
|
|
332
|
-
* `resumeStrand`) finds the member present and skips.
|
|
356
|
+
* NOT NULL on every path; bootstrap only waives the SIGNATURE.
|
|
333
357
|
*/
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
358
|
+
function founderMemberRow(memberKey) {
|
|
359
|
+
return {
|
|
360
|
+
table: 'Strand.Member',
|
|
361
|
+
statements: {
|
|
362
|
+
sql: `insert into Strand.Member (Key, StampId)
|
|
363
|
+
with context ManagerKey = null, ManagerSignature = null, MemberSignature = null
|
|
364
|
+
values (:founderMemberKey, :founderMemberStampId);`,
|
|
365
|
+
params: { founderMemberKey: memberKey, founderMemberStampId: generateStrandStampId() },
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* The founding `Strand.Manager` insert, at `Generation = 0` — the root of the manager
|
|
371
|
+
* lineage; the bootstrap branch of `Manager.Authorized` requires exactly that value, and
|
|
372
|
+
* every later manager is seated at a strictly greater generation (see {@link addManager}).
|
|
373
|
+
* No signature is needed (a fresh StampId is still minted — the column is NOT NULL).
|
|
374
|
+
*
|
|
375
|
+
* The bootstrap branch, `Manager.MemberExists` and `Manager.OnlyClosed` all have subqueries,
|
|
376
|
+
* so they defer to commit and read the live `Member` and `Header` tables: a founding
|
|
377
|
+
* `Manager` whose `Member` and `Header` are neither committed already nor in its own
|
|
378
|
+
* transaction is rejected.
|
|
379
|
+
*/
|
|
380
|
+
function founderManagerRow(memberKey) {
|
|
381
|
+
return {
|
|
382
|
+
table: 'Strand.Manager',
|
|
383
|
+
statements: {
|
|
384
|
+
sql: `insert into Strand.Manager (MemberKey, Generation, StampId)
|
|
385
|
+
with context ManagerKey = null, Signature = null
|
|
386
|
+
values (:founderManagerKey, 0, :founderManagerStampId);`,
|
|
387
|
+
params: { founderManagerKey: memberKey, founderManagerStampId: generateStrandStampId() },
|
|
388
|
+
},
|
|
389
|
+
};
|
|
343
390
|
}
|
|
344
391
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* no
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* Idempotent via the same count guard.
|
|
353
|
-
*
|
|
354
|
-
* ORDERING IS LOAD-BEARING, not merely convenient. The bootstrap branch is gated to
|
|
355
|
-
* the founding state and now reads `exists (select 1 from Member M where M.Key =
|
|
356
|
-
* new.MemberKey)` alongside `count(Manager) <= 1` and `count(Member) <= 1`, so the
|
|
357
|
-
* founding `Member` row MUST already exist when this commits — a Manager-first
|
|
358
|
-
* seeding path is rejected. It must also run AFTER the Header insert:
|
|
359
|
-
* `Manager.OnlyClosed` is a deferred (subquery) check evaluated at commit. The
|
|
360
|
-
* sequential auto-commit Header→Member→Manager order in
|
|
361
|
-
* {@link bootstrapFounderMembership} satisfies both.
|
|
362
|
-
*
|
|
363
|
-
* SEALED strands are skipped, not re-founded: a strand whose sole manager has
|
|
364
|
-
* {@link sealStrand}ed also has zero `Manager` rows, but its founding branch is
|
|
365
|
-
* closed for good (the schema's bootstrap branch requires no `Manager`-table
|
|
366
|
-
* `Revocation` row to exist). Attempting the founding insert here would be
|
|
367
|
-
* schema-rejected and turn every founder restart of a sealed strand into a
|
|
368
|
-
* loud failure — so this mirrors the schema's own gate and returns quietly.
|
|
369
|
-
* A crash BETWEEN the founding Member and Manager inserts leaves no Revocation
|
|
370
|
-
* rows at all, so that restart still completes the founding.
|
|
392
|
+
* Whether the founding `Strand.Manager` still has to be seated: no manager exists and the
|
|
393
|
+
* strand is not SEALED. A strand whose sole manager has {@link sealStrand}ed also has zero
|
|
394
|
+
* `Manager` rows, but its founding branch is closed for good (the schema's bootstrap branch
|
|
395
|
+
* requires no `Manager`-table `Revocation` row to exist). Seating it there would be
|
|
396
|
+
* schema-rejected and turn every founder restart of a sealed strand into a loud failure — so
|
|
397
|
+
* this mirrors the schema's own gate. A founding that never committed its Manager leaves no
|
|
398
|
+
* Revocation rows at all, so that restart still completes the founding.
|
|
371
399
|
*/
|
|
372
|
-
async function
|
|
400
|
+
async function founderManagerMissing(db, strandId) {
|
|
373
401
|
if (await strandTableCount(db, 'Manager') > 0) {
|
|
374
402
|
log('Manager already present for strand %s; skipping founder Manager', strandId);
|
|
375
|
-
return;
|
|
403
|
+
return false;
|
|
376
404
|
}
|
|
377
405
|
if (await strandHasManagerRevocation(db)) {
|
|
378
406
|
log('Strand %s has retired a manager seat (sealed); skipping founder Manager', strandId);
|
|
379
|
-
return;
|
|
407
|
+
return false;
|
|
380
408
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* This machine's `Strand.MemberPeer` binding, unless there is no peer id to bind or the
|
|
413
|
+
* binding is already present (a re-run after a torn founding commit).
|
|
414
|
+
*/
|
|
415
|
+
async function founderBindingIfAbsent(db, founderKeyPair, peerId) {
|
|
416
|
+
if (peerId === undefined) {
|
|
417
|
+
return [];
|
|
418
|
+
}
|
|
419
|
+
if (await memberPeerStampId(db, founderKeyPair.publicKeyB64, peerId) !== undefined) {
|
|
420
|
+
log('MemberPeer (%s, %s) already present; skipping founder binding', founderKeyPair.publicKeyB64, peerId);
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
return [{ table: 'Strand.MemberPeer', statements: memberPeerInsertStatement(founderKeyPair, peerId) }];
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* The closed strand's founding rows that are still missing, in Member → Manager → MemberPeer
|
|
427
|
+
* order. Each is behind an insert-if-absent guard, so a re-run after a crash or a torn commit
|
|
428
|
+
* writes only what is missing.
|
|
429
|
+
*
|
|
430
|
+
* The binding joins only a run that seats the founding `Member`. With a member row already
|
|
431
|
+
* present the founder may since have left the strand or been removed, and
|
|
432
|
+
* `MemberPeer.MemberExists` would then refuse the whole founding transaction; the membership
|
|
433
|
+
* reconciler, which binds only once it sees this party's member row, writes it instead.
|
|
434
|
+
*/
|
|
435
|
+
async function missingClosedFoundingRows(db, founderKeyPair, params) {
|
|
436
|
+
const memberKey = founderKeyPair.publicKeyB64;
|
|
437
|
+
const seatsMember = await strandTableCount(db, 'Member') === 0;
|
|
438
|
+
if (!seatsMember) {
|
|
439
|
+
log('Member already present for strand %s; skipping founder Member', params.strandId);
|
|
440
|
+
}
|
|
441
|
+
const seatsManager = await founderManagerMissing(db, params.strandId);
|
|
442
|
+
const binding = seatsMember ? await founderBindingIfAbsent(db, founderKeyPair, params.founderPeerId) : [];
|
|
443
|
+
return [
|
|
444
|
+
...(seatsMember ? [founderMemberRow(memberKey)] : []),
|
|
445
|
+
...(seatsManager ? [founderManagerRow(memberKey)] : []),
|
|
446
|
+
...binding,
|
|
447
|
+
];
|
|
385
448
|
}
|
|
386
449
|
/**
|
|
387
450
|
* Refuse a closed strand whose membership still holds the key derived from the shared
|
|
@@ -407,17 +470,23 @@ export async function assertNotPreSplitStrand(db, strandId, sharedMemberPublicKe
|
|
|
407
470
|
*
|
|
408
471
|
* Runs once at bring-up on the strand's FOUNDER (the party that provisioned and
|
|
409
472
|
* published the strand). A joiner never calls this — it receives these rows via
|
|
410
|
-
* Optimystic sync.
|
|
411
|
-
*
|
|
473
|
+
* Optimystic sync. It reads which founding rows are missing, then writes all of them in
|
|
474
|
+
* ONE strand transaction. Every row is insert-if-absent, so a restart / founder
|
|
475
|
+
* re-`addStrand` writes nothing, and a re-run after a failed or torn founding commit
|
|
476
|
+
* writes only what is missing.
|
|
477
|
+
*
|
|
478
|
+
* On the run that finds no `Header`, it first commits an empty collection for every
|
|
479
|
+
* table the `Strand` and `App` schemas declare except the ones the founding transaction
|
|
480
|
+
* writes, so no read of a declared table ever needs another member to prove it empty
|
|
481
|
+
* ({@link createDeclaredCollections}).
|
|
412
482
|
*
|
|
413
483
|
* Behavior by strand type:
|
|
414
|
-
* - **Open (`'o'`)**:
|
|
415
|
-
*
|
|
416
|
-
* - **Closed (`'c'`)**:
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
* evaluate at commit.
|
|
484
|
+
* - **Open (`'o'`)**: `Header` only. `Member`/`Manager`/`Invite` are `OnlyClosed` and
|
|
485
|
+
* would trip that constraint — they are skipped entirely.
|
|
486
|
+
* - **Closed (`'c'`)**: `Header(Type='c')`, the founding `Member` and `Manager` (both
|
|
487
|
+
* `founderKeyPair.publicKeyB64`) and, when `founderPeerId` is supplied, this machine's
|
|
488
|
+
* `MemberPeer` binding. Every check that reads another founding row has a subquery, so
|
|
489
|
+
* it defers to commit and sees the whole transaction.
|
|
421
490
|
*
|
|
422
491
|
* A closed strand with no `founderKeyPair` throws: a closed strand with no founding
|
|
423
492
|
* Manager could never admit anyone, so failing loudly here (which propagates out
|
|
@@ -426,11 +495,14 @@ export async function assertNotPreSplitStrand(db, strandId, sharedMemberPublicKe
|
|
|
426
495
|
* A closed strand whose membership holds `sharedMemberPublicKey` throws
|
|
427
496
|
* {@link PreSplitStrandIdentityError} before writing anything: the insert-if-absent
|
|
428
497
|
* guards would otherwise skip over its pre-split founding rows and leave the shared
|
|
429
|
-
* key seated.
|
|
498
|
+
* key seated. Checked only when the `Header` is already present: a strand founded before
|
|
499
|
+
* the key split committed its Header first, alone, so a strand with no Header has none
|
|
500
|
+
* of those rows.
|
|
430
501
|
*
|
|
431
502
|
* @param db - The strand's Quereus database (schema already applied).
|
|
432
|
-
* @param params - Strand id/type, the sApp config for the Header,
|
|
433
|
-
*
|
|
503
|
+
* @param params - Strand id/type, the sApp config for the Header, the composition's
|
|
504
|
+
* empty-collection step, and (closed only) the derived founder keypair, the
|
|
505
|
+
* shared-derived public key to refuse and this machine's peer id to bind.
|
|
434
506
|
* @throws If `type === 'c'` and no `founderKeyPair` is supplied.
|
|
435
507
|
* @throws {PreSplitStrandIdentityError} If `type === 'c'` and a `Strand.Member` or
|
|
436
508
|
* `Strand.Manager` row is `sharedMemberPublicKey`.
|
|
@@ -445,19 +517,35 @@ export async function bootstrapFounderMembership(db, params) {
|
|
|
445
517
|
throw new Error(`Cannot bootstrap closed strand ${strandId}: no founder key pair derived from this party's ` +
|
|
446
518
|
'StrandPartyKey. A closed strand needs a founding Member + Manager or it can never admit members.');
|
|
447
519
|
}
|
|
448
|
-
|
|
520
|
+
const headerPresent = await strandTableCount(db, 'Header') > 0;
|
|
521
|
+
if (headerPresent && type === 'c' && sharedMemberPublicKey !== undefined) {
|
|
449
522
|
await assertNotPreSplitStrand(db, strandId, sharedMemberPublicKey);
|
|
450
523
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
524
|
+
const rows = [
|
|
525
|
+
...(headerPresent ? [] : [headerRow(params)]),
|
|
526
|
+
...(type === 'c' ? await missingClosedFoundingRows(db, founderKeyPair, params) : []),
|
|
527
|
+
];
|
|
528
|
+
if (!headerPresent) {
|
|
529
|
+
await createDeclaredCollections(params, rows.map((row) => row.table));
|
|
530
|
+
}
|
|
531
|
+
if (rows.length === 0) {
|
|
532
|
+
log('Strand %s is already founded; nothing to write', strandId);
|
|
455
533
|
return;
|
|
456
534
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
535
|
+
// NOTE: a torn founding commit (some of the batch's collections saved, others not) can leave
|
|
536
|
+
// the Header committed beside a founding table with no collection, which committing every
|
|
537
|
+
// table's empty collection first used to rule out. A sibling machine of this party could then
|
|
538
|
+
// create that collection itself (its reconciler binding its own peer into MemberPeer). The
|
|
539
|
+
// re-run's guards, and this machine's reconciler, read each table before writing it, and a
|
|
540
|
+
// networked read asks the cohort, so the healing write appends to the sibling's collection
|
|
541
|
+
// unless the sibling is unreachable at that moment. A torn founding that saves this
|
|
542
|
+
// machine's MemberPeer without its Member also leaves an orphaned binding, which every
|
|
543
|
+
// machine's revocation enforcer (this one's and any joiner's) reads as a removed founder
|
|
544
|
+
// until a later run of this bootstrap seats the Member. If torn founding commits are ever
|
|
545
|
+
// observed, commit the founding tables a sibling writes (MemberPeer) as empty collections
|
|
546
|
+
// before this batch again.
|
|
547
|
+
await execStrandTransaction(db, combineStatements(...rows.map((row) => row.statements)));
|
|
548
|
+
log('Founder bootstrap for strand %s wrote %s', strandId, rows.map((row) => row.table).join(', '));
|
|
461
549
|
}
|
|
462
550
|
/**
|
|
463
551
|
* Issue a single-use invitation to join a closed strand.
|
|
@@ -489,8 +577,8 @@ export async function issueInvite(db, params) {
|
|
|
489
577
|
const payload = `${inviteKey}|${expirationSegment}`;
|
|
490
578
|
const managerSignature = signStrandPayload(payload, managerKeyPair.privateKeyB64);
|
|
491
579
|
const inviteSignature = signStrandPayload(payload, invitePrivateKey);
|
|
492
|
-
await db.exec(`insert into Strand.Invite (Key, Expiration)
|
|
493
|
-
with context ManagerKey = ?, ManagerSignature = ?, InviteSignature = ?
|
|
580
|
+
await db.exec(`insert into Strand.Invite (Key, Expiration)
|
|
581
|
+
with context ManagerKey = ?, ManagerSignature = ?, InviteSignature = ?
|
|
494
582
|
values (?, ?)`, [managerKeyPair.publicKeyB64, managerSignature, inviteSignature, inviteKey, expirationColumn]);
|
|
495
583
|
log('Issued invite %s (expires=%s)', inviteKey, expirationColumn ?? 'never');
|
|
496
584
|
return { inviteKey, invitePrivateKey };
|
|
@@ -547,8 +635,8 @@ export async function consumeInvite(db, params, options) {
|
|
|
547
635
|
// Member first — admitted by the deferred invite branch (the matching ConsumedInvite
|
|
548
636
|
// after it), so no manager signature is supplied.
|
|
549
637
|
const member = {
|
|
550
|
-
sql: `insert into Strand.Member (Key, StampId)
|
|
551
|
-
with context ManagerKey = null, ManagerSignature = null, MemberSignature = null
|
|
638
|
+
sql: `insert into Strand.Member (Key, StampId)
|
|
639
|
+
with context ManagerKey = null, ManagerSignature = null, MemberSignature = null
|
|
552
640
|
values (:memberKey, :memberStampId);`,
|
|
553
641
|
params: { memberKey, memberStampId: generateStrandStampId() },
|
|
554
642
|
};
|
|
@@ -569,8 +657,8 @@ export async function consumeInvite(db, params, options) {
|
|
|
569
657
|
async function consumedInviteStatement(db, params) {
|
|
570
658
|
const { inviteKey, invitePrivateKey, memberKey, nowMs } = params;
|
|
571
659
|
return {
|
|
572
|
-
sql: `insert into Strand.ConsumedInvite (InviteKey, MemberKey)
|
|
573
|
-
with context InviteSignature = :consumedSignature, Now = :consumedNow
|
|
660
|
+
sql: `insert into Strand.ConsumedInvite (InviteKey, MemberKey)
|
|
661
|
+
with context InviteSignature = :consumedSignature, Now = :consumedNow
|
|
574
662
|
values (:consumedInviteKey, :consumedMemberKey);`,
|
|
575
663
|
params: {
|
|
576
664
|
consumedSignature: signStrandPayload(`${inviteKey}|${memberKey}`, invitePrivateKey),
|
|
@@ -676,8 +764,8 @@ export async function cancelInvite(db, params) {
|
|
|
676
764
|
return;
|
|
677
765
|
}
|
|
678
766
|
const signature = signStrandApproval(['Strand.CancelledInvite', 'cancel', inviteKey], managerKeyPair.privateKeyB64);
|
|
679
|
-
await db.exec(`insert into Strand.CancelledInvite (InviteKey)
|
|
680
|
-
with context ManagerKey = ?, ManagerSignature = ?
|
|
767
|
+
await db.exec(`insert into Strand.CancelledInvite (InviteKey)
|
|
768
|
+
with context ManagerKey = ?, ManagerSignature = ?
|
|
681
769
|
values (?)`, [managerKeyPair.publicKeyB64, signature, inviteKey]);
|
|
682
770
|
log('Cancelled invite %s by manager %s', inviteKey, managerKeyPair.publicKeyB64);
|
|
683
771
|
}
|
|
@@ -790,8 +878,8 @@ function memberAddByManagerStatement(params) {
|
|
|
790
878
|
const { managerKeyPair, memberKey } = params;
|
|
791
879
|
const stampId = generateStrandStampId();
|
|
792
880
|
return {
|
|
793
|
-
sql: `insert into Strand.Member (Key, StampId)
|
|
794
|
-
with context ManagerKey = :memberAdmitterKey, ManagerSignature = :memberAdmitterSignature, MemberSignature = null
|
|
881
|
+
sql: `insert into Strand.Member (Key, StampId)
|
|
882
|
+
with context ManagerKey = :memberAdmitterKey, ManagerSignature = :memberAdmitterSignature, MemberSignature = null
|
|
795
883
|
values (:memberKey, :memberStampId);`,
|
|
796
884
|
params: {
|
|
797
885
|
memberAdmitterKey: managerKeyPair.publicKeyB64,
|
|
@@ -837,12 +925,11 @@ function memberAddByManagerStatement(params) {
|
|
|
837
925
|
* (`Member.MinOneMember`, a local-count floor with the cross-node caveat its
|
|
838
926
|
* schema NOTE states).
|
|
839
927
|
*
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
* that call the cut lands up to one poll interval (default 30 s) later.
|
|
928
|
+
* Inside a cadre runtime the removed party's machines are then refused at the
|
|
929
|
+
* network layer by the strand's revoked-peer gate (`strand-revocation-enforcer.ts`),
|
|
930
|
+
* which re-reads membership when this write commits on the runtime's own
|
|
931
|
+
* `Database`. A caller that wants to await the cut follows the write with
|
|
932
|
+
* `CadreNode.refreshRevocationEnforcement(strandId)`, which resolves after it.
|
|
846
933
|
*
|
|
847
934
|
* @param db - The closed strand's database.
|
|
848
935
|
* @param params - The revoking manager keypair and the target member key.
|
|
@@ -860,8 +947,8 @@ export async function revokeMember(db, params, options) {
|
|
|
860
947
|
return;
|
|
861
948
|
}
|
|
862
949
|
const removal = {
|
|
863
|
-
sql: `delete from Strand.Member
|
|
864
|
-
with context ManagerKey = :memberRemoverKey, ManagerSignature = :memberRemoverSignature, MemberSignature = null
|
|
950
|
+
sql: `delete from Strand.Member
|
|
951
|
+
with context ManagerKey = :memberRemoverKey, ManagerSignature = :memberRemoverSignature, MemberSignature = null
|
|
865
952
|
where Key = :memberKey;`,
|
|
866
953
|
params: {
|
|
867
954
|
memberRemoverKey: managerKeyPair.publicKeyB64,
|
|
@@ -886,10 +973,10 @@ export async function revokeMember(db, params, options) {
|
|
|
886
973
|
* The same floors as {@link revokeMember} apply: a manager must resign first
|
|
887
974
|
* (`NotAManager`) and the last member cannot leave (`MinOneMember`).
|
|
888
975
|
*
|
|
889
|
-
* Like {@link revokeMember},
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
976
|
+
* Like {@link revokeMember}, inside a cadre runtime the write wakes the strand's
|
|
977
|
+
* revoked-peer gate, which emits `strand:revoked` when it finds this node's own
|
|
978
|
+
* peer id revoked; `CadreNode.refreshRevocationEnforcement(strandId)` awaits that
|
|
979
|
+
* refresh.
|
|
893
980
|
*
|
|
894
981
|
* @param db - The closed strand's database.
|
|
895
982
|
* @param params - The departing member's own keypair.
|
|
@@ -906,8 +993,8 @@ export async function leaveStrand(db, params, options) {
|
|
|
906
993
|
return;
|
|
907
994
|
}
|
|
908
995
|
const departure = {
|
|
909
|
-
sql: `delete from Strand.Member
|
|
910
|
-
with context ManagerKey = null, ManagerSignature = null, MemberSignature = :memberSignature
|
|
996
|
+
sql: `delete from Strand.Member
|
|
997
|
+
with context ManagerKey = null, ManagerSignature = null, MemberSignature = :memberSignature
|
|
911
998
|
where Key = :memberKey;`,
|
|
912
999
|
params: {
|
|
913
1000
|
memberSignature: signStrandApproval(['Strand.Member', 'leave', memberKey, stampId], memberKeyPair.privateKeyB64),
|
|
@@ -960,10 +1047,19 @@ export async function registerMemberPeer(db, params, options) {
|
|
|
960
1047
|
log('MemberPeer (%s, %s) already present; skipping', memberKey, peerId);
|
|
961
1048
|
return;
|
|
962
1049
|
}
|
|
1050
|
+
await execStrandTransaction(db, memberPeerInsertStatement(memberKeyPair, peerId), options);
|
|
1051
|
+
log('Registered MemberPeer (%s, %s)', memberKey, peerId);
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* The self-signed `Strand.MemberPeer` insert binding `peerId` to the member, under a fresh
|
|
1055
|
+
* stamp bound into the add-tagged digest (see {@link registerMemberPeer}).
|
|
1056
|
+
*/
|
|
1057
|
+
function memberPeerInsertStatement(memberKeyPair, peerId) {
|
|
1058
|
+
const memberKey = memberKeyPair.publicKeyB64;
|
|
963
1059
|
const stampId = generateStrandStampId();
|
|
964
|
-
|
|
965
|
-
sql: `insert into Strand.MemberPeer (MemberKey, PeerId, StampId)
|
|
966
|
-
with context Signature = :peerSignature, ManagerKey = null, ManagerSignature = null
|
|
1060
|
+
return {
|
|
1061
|
+
sql: `insert into Strand.MemberPeer (MemberKey, PeerId, StampId)
|
|
1062
|
+
with context Signature = :peerSignature, ManagerKey = null, ManagerSignature = null
|
|
967
1063
|
values (:peerMemberKey, :peerId, :peerStampId);`,
|
|
968
1064
|
params: {
|
|
969
1065
|
peerSignature: signStrandApproval(['Strand.MemberPeer', 'add', memberKey, peerId, stampId], memberKeyPair.privateKeyB64),
|
|
@@ -971,8 +1067,7 @@ export async function registerMemberPeer(db, params, options) {
|
|
|
971
1067
|
peerId,
|
|
972
1068
|
peerStampId: stampId,
|
|
973
1069
|
},
|
|
974
|
-
}
|
|
975
|
-
log('Registered MemberPeer (%s, %s)', memberKey, peerId);
|
|
1070
|
+
};
|
|
976
1071
|
}
|
|
977
1072
|
/**
|
|
978
1073
|
* Yield every `(PeerId, StampId)` bound to `memberKey`, re-comparing the member key
|
|
@@ -1114,8 +1209,8 @@ function ownMemberPeerRemovalStatements(params, stampId) {
|
|
|
1114
1209
|
const { memberKeyPair, peerId } = params;
|
|
1115
1210
|
const memberKey = memberKeyPair.publicKeyB64;
|
|
1116
1211
|
const removal = {
|
|
1117
|
-
sql: `delete from Strand.MemberPeer
|
|
1118
|
-
with context Signature = :peerSignature, ManagerKey = null, ManagerSignature = null
|
|
1212
|
+
sql: `delete from Strand.MemberPeer
|
|
1213
|
+
with context Signature = :peerSignature, ManagerKey = null, ManagerSignature = null
|
|
1119
1214
|
where MemberKey = :peerMemberKey and PeerId = :peerId;`,
|
|
1120
1215
|
params: {
|
|
1121
1216
|
peerSignature: signStrandApproval(['Strand.MemberPeer', 'remove', memberKey, peerId, stampId], memberKeyPair.privateKeyB64),
|
|
@@ -1139,8 +1234,8 @@ function ownMemberPeerRemovalStatements(params, stampId) {
|
|
|
1139
1234
|
function memberPeerRemovalByManagerStatements(params, stampId) {
|
|
1140
1235
|
const { managerKeyPair, memberKey, peerId } = params;
|
|
1141
1236
|
const removal = {
|
|
1142
|
-
sql: `delete from Strand.MemberPeer
|
|
1143
|
-
with context Signature = null, ManagerKey = :peerManagerKey, ManagerSignature = :peerManagerSignature
|
|
1237
|
+
sql: `delete from Strand.MemberPeer
|
|
1238
|
+
with context Signature = null, ManagerKey = :peerManagerKey, ManagerSignature = :peerManagerSignature
|
|
1144
1239
|
where MemberKey = :peerMemberKey and PeerId = :peerId;`,
|
|
1145
1240
|
params: {
|
|
1146
1241
|
peerManagerKey: managerKeyPair.publicKeyB64,
|
|
@@ -1226,8 +1321,8 @@ async function managerAddStatement(db, params) {
|
|
|
1226
1321
|
const generation = authorizer == null ? 1 : authorizer.generation + 1;
|
|
1227
1322
|
const stampId = generateStrandStampId();
|
|
1228
1323
|
return {
|
|
1229
|
-
sql: `insert into Strand.Manager (MemberKey, Generation, StampId)
|
|
1230
|
-
with context ManagerKey = :managerAuthorizerKey, Signature = :managerSignature
|
|
1324
|
+
sql: `insert into Strand.Manager (MemberKey, Generation, StampId)
|
|
1325
|
+
with context ManagerKey = :managerAuthorizerKey, Signature = :managerSignature
|
|
1231
1326
|
values (:managerMemberKey, :managerGeneration, :managerStampId);`,
|
|
1232
1327
|
params: {
|
|
1233
1328
|
managerAuthorizerKey: byManagerKeyPair.publicKeyB64,
|
|
@@ -1371,8 +1466,8 @@ export async function removeManager(db, params, options) {
|
|
|
1371
1466
|
*/
|
|
1372
1467
|
function managerRemovalStatements(signer, signature, targetManagerKey, targetStampId) {
|
|
1373
1468
|
const removal = {
|
|
1374
|
-
sql: `delete from Strand.Manager
|
|
1375
|
-
with context ManagerKey = :managerRemoverKey, Signature = :managerRemoverSignature
|
|
1469
|
+
sql: `delete from Strand.Manager
|
|
1470
|
+
with context ManagerKey = :managerRemoverKey, Signature = :managerRemoverSignature
|
|
1376
1471
|
where MemberKey = :managerMemberKey;`,
|
|
1377
1472
|
params: {
|
|
1378
1473
|
managerRemoverKey: signer.publicKeyB64,
|