@interop/wallet-core 0.106.0 → 0.107.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +1 -1
  2. package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
  3. package/dist/clientAnnex/forgetLast.js +0 -1
  4. package/dist/clientAnnex/forgetLast.js.map +1 -1
  5. package/dist/clientAnnex/gc.d.ts +55 -24
  6. package/dist/clientAnnex/gc.d.ts.map +1 -1
  7. package/dist/clientAnnex/gc.js +111 -31
  8. package/dist/clientAnnex/gc.js.map +1 -1
  9. package/dist/clientAnnex/generationRung.d.ts +5 -21
  10. package/dist/clientAnnex/generationRung.d.ts.map +1 -1
  11. package/dist/clientAnnex/generationRung.js +30 -41
  12. package/dist/clientAnnex/generationRung.js.map +1 -1
  13. package/dist/clientAnnex/grantRevocation.d.ts +11 -7
  14. package/dist/clientAnnex/grantRevocation.d.ts.map +1 -1
  15. package/dist/clientAnnex/grantRevocation.js +1 -1
  16. package/dist/clientAnnex/grantRevocation.js.map +1 -1
  17. package/dist/clientAnnex/heal.d.ts +14 -4
  18. package/dist/clientAnnex/heal.d.ts.map +1 -1
  19. package/dist/clientAnnex/heal.js +32 -12
  20. package/dist/clientAnnex/heal.js.map +1 -1
  21. package/dist/clientAnnex/index.d.ts +6 -5
  22. package/dist/clientAnnex/index.d.ts.map +1 -1
  23. package/dist/clientAnnex/index.js +6 -5
  24. package/dist/clientAnnex/index.js.map +1 -1
  25. package/dist/clientAnnex/log.d.ts +106 -59
  26. package/dist/clientAnnex/log.d.ts.map +1 -1
  27. package/dist/clientAnnex/log.js +156 -111
  28. package/dist/clientAnnex/log.js.map +1 -1
  29. package/dist/clientAnnex/recoveryLadderAnchored.d.ts +5 -0
  30. package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
  31. package/dist/clientAnnex/recoveryLadderAnchored.js +5 -0
  32. package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
  33. package/dist/clients/grantState.d.ts +11 -9
  34. package/dist/clients/grantState.d.ts.map +1 -1
  35. package/dist/clients/grantState.js +19 -16
  36. package/dist/clients/grantState.js.map +1 -1
  37. package/dist/clients/index.d.ts +9 -9
  38. package/dist/clients/index.js +9 -9
  39. package/dist/clients/listing.d.ts +12 -14
  40. package/dist/clients/listing.d.ts.map +1 -1
  41. package/dist/clients/listing.js +17 -23
  42. package/dist/clients/listing.js.map +1 -1
  43. package/dist/connections/grantProof.d.ts +47 -14
  44. package/dist/connections/grantProof.d.ts.map +1 -1
  45. package/dist/connections/grantProof.js +88 -57
  46. package/dist/connections/grantProof.js.map +1 -1
  47. package/dist/connections/grants.d.ts +13 -1
  48. package/dist/connections/grants.d.ts.map +1 -1
  49. package/dist/connections/grants.js +15 -26
  50. package/dist/connections/grants.js.map +1 -1
  51. package/dist/connections/index.d.ts +4 -3
  52. package/dist/connections/index.d.ts.map +1 -1
  53. package/dist/connections/index.js +3 -2
  54. package/dist/connections/index.js.map +1 -1
  55. package/dist/testing/accountBuilder.d.ts.map +1 -1
  56. package/dist/testing/accountBuilder.js +0 -1
  57. package/dist/testing/accountBuilder.js.map +1 -1
  58. package/dist/testing/signerFixture.d.ts +3 -3
  59. package/dist/testing/signerFixture.d.ts.map +1 -1
  60. package/dist/testing/signerFixture.js +7 -5
  61. package/dist/testing/signerFixture.js.map +1 -1
  62. package/dist/unlock/retire.d.ts +5 -2
  63. package/dist/unlock/retire.d.ts.map +1 -1
  64. package/dist/unlock/retire.js.map +1 -1
  65. package/dist/webvh/clientAnnexDid.d.ts +4 -5
  66. package/dist/webvh/clientAnnexDid.d.ts.map +1 -1
  67. package/dist/webvh/clientAnnexDid.js +4 -5
  68. package/dist/webvh/clientAnnexDid.js.map +1 -1
  69. package/dist/webvh/index.d.ts +13 -6
  70. package/dist/webvh/index.d.ts.map +1 -1
  71. package/dist/webvh/index.js +12 -5
  72. package/dist/webvh/index.js.map +1 -1
  73. package/dist/webvh/ladderDerivation.d.ts +1 -2
  74. package/dist/webvh/ladderDerivation.d.ts.map +1 -1
  75. package/dist/webvh/ladderDerivation.js +5 -5
  76. package/dist/webvh/ladderDerivation.js.map +1 -1
  77. package/dist/webvh/listClients.d.ts +124 -15
  78. package/dist/webvh/listClients.d.ts.map +1 -1
  79. package/dist/webvh/listClients.js +148 -43
  80. package/dist/webvh/listClients.js.map +1 -1
  81. package/dist/webvh/standingZcap.d.ts +4 -1
  82. package/dist/webvh/standingZcap.d.ts.map +1 -1
  83. package/dist/webvh/standingZcap.js +13 -14
  84. package/dist/webvh/standingZcap.js.map +1 -1
  85. package/package.json +12 -12
@@ -14,12 +14,14 @@
14
14
  *
15
15
  * The annex's conventions differ from the account log's on purpose:
16
16
  *
17
- * - Update authority is each standing credential's static annex rung 0
18
- * (chain length one, no rung advancement, no attribution scan). Genesis
19
- * states the minting credential's rung-0 key in `updateKeys` and commits
20
- * every standing credential's rung-0 hash in `nextKeyHashes` -- the minting
21
- * key's own carry-over hash included, or no later entry could re-state it.
22
- * - Prerotation stays on (the rung-0 hashes are the commitment chain),
17
+ * - Update authority is each standing credential's static annex rung
18
+ * (`clientAnnexRung`): one key per credential, the same on every
19
+ * generation, with no rung advancement and no attribution scan. Genesis
20
+ * states the minting credential's rung key in `updateKeys` and commits its
21
+ * own carry-over hash in `nextKeyHashes`, or no later entry could re-state
22
+ * it. A genesis that supersedes a readable generation also restates that
23
+ * generation's standing set there ({@link standingRungHashesOf}).
24
+ * - Prerotation stays on (the rung hashes are the commitment chain),
23
25
  * witnesses stay off, and portability is off: an annex is
24
26
  * generation-scoped and host-bound, and replacement is a GC swap, never a
25
27
  * portability move.
@@ -40,13 +42,9 @@
40
42
  * `gen-` prefix match over the auxiliary Space's collection listing, with no
41
43
  * registry of generations anywhere.
42
44
  *
43
- * Generation identity is random, never a counter: a reused generation id would
44
- * re-derive the same rung-0 update key for a new generation, and no counter
45
- * carrier survives GC deleting the old collection. The generation id is also
46
- * the generation-identifying half of the annex rung HKDF labels
47
- * (`<generationId>/rung/<k>` under the unlock ladder's one salt), so there is
48
- * exactly one spelling of a generation's identity -- the one the annex
49
- * DID string already embeds.
45
+ * Generation identity is random rather than a counter: no counter carrier
46
+ * survives GC deleting the old collection. The generation id is the
47
+ * generation collection's name, and the annex DID string embeds it.
50
48
  */
51
49
  import { createDID, deriveNextKeyHash, updateDID } from '@interop/did-method-webvh';
52
50
  import { rootCapabilityId, spacePath, toUrl } from '@interop/was-client/paths';
@@ -403,17 +401,14 @@ async function publishClientAnnexGenesis({ was, wasServerUrl, spaceId, generatio
403
401
  };
404
402
  }
405
403
  /**
406
- * Mints a fresh annex generation signed by a standing CREDENTIAL's
407
- * annex rung 0 -- the mint a ladder-seed holder runs (a credential-in-hand
408
- * login, or a test harness standing in for one). The generation id must exist
409
- * before the update authority can: the rung-0 key derives from the ladder
410
- * seed AND the generation id (`clientAnnexRung`), so this helper mints the
411
- * generation id
412
- * first, derives the rung, and states its own carry-over hash in
413
- * `nextKeyHashes` -- {@link mintClientAnnexGeneration}'s caller-supplied-key
414
- * shape cannot express that ordering. Everything else matches it: the typed
415
- * Space ensure, the collection create, the create-if-absent genesis publish,
416
- * and the pointer deliberately left to the caller.
404
+ * Mints a fresh annex generation signed by a standing CREDENTIAL's static
405
+ * annex rung -- the mint a ladder-seed holder runs (a credential-in-hand
406
+ * login, or a test harness standing in for one). It derives the rung from the
407
+ * ladder seed, states the rung key in `updateKeys`, and commits its own
408
+ * carry-over hash in `nextKeyHashes` beside any restated standing hashes.
409
+ * Everything else matches {@link mintClientAnnexGeneration}: the typed Space
410
+ * ensure, the collection create, the create-if-absent genesis publish, and
411
+ * the pointer deliberately left to the caller.
417
412
  *
418
413
  * @param options {object}
419
414
  * @param options.was {WasClient} the storage client, signing as an enrolled
@@ -426,12 +421,14 @@ async function publishClientAnnexGenesis({ was, wasServerUrl, spaceId, generatio
426
421
  * seed, from its unlock record
427
422
  * @param options.pinStore {ResourceLogPinStore} this client's chain-head
428
423
  * pins; the store derives each log's slot
429
- * @param [options.otherLadderSeeds] {Uint8Array[]} the OTHER standing
430
- * credentials' ladder seeds, when the caller holds them. Each one's rung-0
431
- * hash for the fresh generation id is committed in the genesis
432
- * `nextKeyHashes` beside the minting credential's own carry-over hash.
433
- * Seeds rather than hashes, since a rung is bound to the generation id
434
- * minted here. A repeated seed is stated once
424
+ * @param [options.standingRungHashes] {string[]} the standing
425
+ * credentials' annex rung hashes, restated from the superseded generation's
426
+ * log ({@link standingRungHashesOf}) by a swap or a heal that supersedes a
427
+ * readable generation. Each is committed in the genesis `nextKeyHashes`
428
+ * beside the minting credential's own carry-over hash, deduplicated, so
429
+ * every credential that could write the old generation can write this
430
+ * one. A first generation (genesis, establishment, the transient-recovery
431
+ * continuation) passes none
435
432
  * @param [options.capability] {IZcap} an invocation capability the mint
436
433
  * rides -- the transient-recovery continuation minting its fresh generation
437
434
  * through the credential's sibling delegation (the auxiliary Space). The
@@ -450,21 +447,20 @@ async function publishClientAnnexGenesis({ was, wasServerUrl, spaceId, generatio
450
447
  * controller afterwards need not re-read it. Present exactly when the
451
448
  * ensure ran, so absent under a supplied `capability`.
452
449
  */
453
- export async function mintCredentialClientAnnexGeneration({ was, wasServerUrl, spaceId, controller, ladderSeed, pinStore, otherLadderSeeds = [], capability }) {
450
+ export async function mintCredentialClientAnnexGeneration({ was, wasServerUrl, spaceId, controller, ladderSeed, pinStore, standingRungHashes = [], capability }) {
454
451
  const spaceDescription = capability === undefined
455
452
  ? await ensureClientAnnexSpace({ was, spaceId, controller })
456
453
  : undefined;
457
454
  const generationId = mintGenerationId();
458
- const rungs = await Promise.all([ladderSeed, ...otherLadderSeeds].map(seed => clientAnnexRung({ ladderSeed: seed, generationId })));
459
- const rung = rungs[0];
460
- const nextKeyHashes = await Promise.all(rungs.map(each => deriveNextKeyHash(each.keyMultibase)));
455
+ const rung = await clientAnnexRung({ ladderSeed });
456
+ const ownHash = await deriveNextKeyHash(rung.keyMultibase);
461
457
  const published = await publishClientAnnexGenesis({
462
458
  was,
463
459
  wasServerUrl,
464
460
  spaceId,
465
461
  generationId,
466
462
  updateKeyPublicKeyMultibase: rung.keyMultibase,
467
- nextKeyHashes: [...new Set(nextKeyHashes)],
463
+ nextKeyHashes: [...new Set([ownHash, ...standingRungHashes])],
468
464
  signer: await updateKeySigner({ seed: rung.seed }),
469
465
  pinStore,
470
466
  ...(capability !== undefined ? { capability } : {})
@@ -1152,15 +1148,15 @@ function withGenerationDelegationEntry({ doc, clientAnnexDid, delegation }) {
1152
1148
  }
1153
1149
  /**
1154
1150
  * Thrown when the published annex log commits neither the writing
1155
- * credential's rung-0 key nor its hash -- the mid-generation lockout: a
1156
- * credential bound after the generation's genesis cannot write the annex
1157
- * until an existing writer commits its rung-0 hash
1158
- * ({@link commitClientAnnexRung}, the one exit short of minting a fresh
1159
- * generation). A GC swap's genesis commits only the seeds its caller holds,
1160
- * and a wallet session holds its login credential's seed alone, so a swap
1161
- * locks out every other credential rather than freeing one. Typed so
1162
- * callers can map it to the fresh-generation path where one is licensed
1163
- * (the transient-recovery continuation) or to honest copy where none is.
1151
+ * credential's annex rung key nor its hash. A generation swap restates the
1152
+ * superseded generation's standing set, so a swap locks no committed
1153
+ * credential out. What is left is the mid-generation bind: a credential
1154
+ * bound after the generation's genesis cannot write the annex until an
1155
+ * existing writer commits its hash ({@link commitClientAnnexRung}), or until
1156
+ * it mints a fresh generation itself (the transient visit's heal, which
1157
+ * restates the superseded generation's set beside its own hash). Typed so
1158
+ * callers can map it to the fresh-generation path where one is licensed or
1159
+ * to honest copy where none is.
1164
1160
  */
1165
1161
  export class ClientAnnexRungUncommittedError extends Error {
1166
1162
  constructor(message) {
@@ -1169,20 +1165,86 @@ export class ClientAnnexRungUncommittedError extends Error {
1169
1165
  }
1170
1166
  }
1171
1167
  /**
1172
- * Derives a generation's rung-0 key for a ladder and admits it as the writer
1173
- * of the entry about to be built: it must stand revealed in the log's
1174
- * `updateKeys`, or its hash must stand committed in `nextKeyHashes`.
1168
+ * The annex's writer-admission rule as a predicate: whether a credential's
1169
+ * static annex rung stands revealed in `updateKeys`, or its hash stands
1170
+ * committed in `nextKeyHashes`. Annex entries verify against the log's own
1171
+ * hash-commitment chain, so a rung this answers false for can never be made
1172
+ * to verify mid-log. A caller that must decide before any write (the
1173
+ * transient visit's heal, choosing between renewal and a fresh mint) asks
1174
+ * this over a head it already read.
1175
+ *
1176
+ * @param options {object}
1177
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed
1178
+ * @param options.updateKeys {string[]} the log's current update keys
1179
+ * @param options.nextKeyHashes {string[]} the log's current commitments
1180
+ * @returns {Promise<boolean>}
1181
+ */
1182
+ export async function logCommitsRung({ ladderSeed, updateKeys, nextKeyHashes }) {
1183
+ return rungAdmitted({
1184
+ rung: await clientAnnexRung({ ladderSeed }),
1185
+ updateKeys,
1186
+ nextKeyHashes
1187
+ });
1188
+ }
1189
+ /**
1190
+ * A credential's annex rung hash, in the multihash form `nextKeyHashes`
1191
+ * carries: what a genesis commits for it and what a swap leaves out when it
1192
+ * retires it.
1193
+ *
1194
+ * @param options {object}
1195
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed
1196
+ * @returns {Promise<string>}
1197
+ */
1198
+ export async function clientAnnexRungHash({ ladderSeed }) {
1199
+ const rung = await clientAnnexRung({ ladderSeed });
1200
+ return deriveNextKeyHash(rung.keyMultibase);
1201
+ }
1202
+ /**
1203
+ * {@link logCommitsRung} over a rung already derived, so a caller that goes
1204
+ * on to sign with the rung derives it once.
1205
+ *
1206
+ * @param options {object}
1207
+ * @param options.rung {{ keyMultibase: string }} the derived annex rung
1208
+ * @param options.updateKeys {string[]}
1209
+ * @param options.nextKeyHashes {string[]}
1210
+ * @returns {Promise<boolean>}
1211
+ */
1212
+ async function rungAdmitted({ rung, updateKeys, nextKeyHashes }) {
1213
+ return (updateKeys.includes(rung.keyMultibase) ||
1214
+ nextKeyHashes.includes(await deriveNextKeyHash(rung.keyMultibase)));
1215
+ }
1216
+ /**
1217
+ * The standing credentials' annex commitment set, read off a generation
1218
+ * log's current parameters: every `nextKeyHashes` entry, plus the hash of
1219
+ * every revealed `updateKeys` entry, deduplicated. Since each credential's
1220
+ * annex rung is the same on every generation, this is exactly what a fresh
1221
+ * genesis restates to keep every credential that could write the
1222
+ * superseded generation able to write the new one. A strike entry already
1223
+ * dropped a retired credential's key and hash from these parameters, so
1224
+ * nothing it struck is restated.
1225
+ *
1226
+ * @param options {object}
1227
+ * @param options.updateKeys {string[]} the superseded log's current update
1228
+ * keys
1229
+ * @param options.nextKeyHashes {string[]} the superseded log's current
1230
+ * commitments
1231
+ * @returns {Promise<string[]>}
1232
+ */
1233
+ export async function standingRungHashesOf({ updateKeys, nextKeyHashes }) {
1234
+ const revealed = await Promise.all(updateKeys.map(key => deriveNextKeyHash(key)));
1235
+ return [...new Set([...nextKeyHashes, ...revealed])];
1236
+ }
1237
+ /**
1238
+ * Derives a credential's annex rung and admits it as the writer of the entry
1239
+ * about to be built, the throwing form of {@link logCommitsRung}.
1175
1240
  *
1176
1241
  * The one implementation of the annex's writer-admission rule, which every
1177
- * entry builder in this module applies before it mints anything. Annex
1178
- * entries verify against the log's own hash-commitment chain, so a key that
1179
- * is neither revealed nor committed can never be made to verify mid-log --
1180
- * the caller supplies only the refusal message, since what a locked-out
1181
- * credential should do next differs per ceremony.
1242
+ * entry builder in this module applies before it mints anything. The caller
1243
+ * supplies only the refusal message, since what a locked-out credential
1244
+ * should do next differs per ceremony.
1182
1245
  *
1183
1246
  * @param options {object}
1184
1247
  * @param options.ladderSeed {Uint8Array} the acting credential's ladder seed
1185
- * @param options.generationId {string}
1186
1248
  * @param options.updateKeys {string[]} the keys the entry will be verified
1187
1249
  * against (the retired members already excluded, where a ceremony excludes
1188
1250
  * them)
@@ -1190,23 +1252,22 @@ export class ClientAnnexRungUncommittedError extends Error {
1190
1252
  * @param options.message {string} the refusal's message
1191
1253
  * @returns {Promise<{ seed: Uint8Array; keyMultibase: string }>}
1192
1254
  */
1193
- async function admitActingRung({ ladderSeed, generationId, updateKeys, nextKeyHashes, message }) {
1194
- const rung = await clientAnnexRung({ ladderSeed, generationId });
1195
- const rungHash = await deriveNextKeyHash(rung.keyMultibase);
1196
- if (!updateKeys.includes(rung.keyMultibase) &&
1197
- !nextKeyHashes.includes(rungHash)) {
1255
+ async function admitActingRung({ ladderSeed, updateKeys, nextKeyHashes, message }) {
1256
+ const rung = await clientAnnexRung({ ladderSeed });
1257
+ if (!(await rungAdmitted({ rung, updateKeys, nextKeyHashes }))) {
1198
1258
  throw new ClientAnnexRungUncommittedError(message);
1199
1259
  }
1200
1260
  return rung;
1201
1261
  }
1202
1262
  /**
1203
- * The read-only form of the writer-admission rule: whether a credential's
1204
- * rung for a generation stands revealed in the published log's `updateKeys`
1205
- * or committed in its `nextKeyHashes`, read under the store's own chain-head
1206
- * pin. A ceremony that must commit ANOTHER credential's rung with this one
1207
- * (the backup export's required commit) asks this before its first durable
1208
- * write, so an acting rung the generation does not admit refuses over
1209
- * nothing rather than after a roster wrap and a record are written. An
1263
+ * The read-only form of the writer-admission rule over a store: whether a
1264
+ * credential's annex rung stands revealed in the published log's
1265
+ * `updateKeys` or committed in its `nextKeyHashes`, read under the store's
1266
+ * own chain-head pin. A ceremony that must commit ANOTHER credential's rung
1267
+ * with this one (the backup export's required commit) asks this before its
1268
+ * first durable write, so an acting rung the generation does not admit
1269
+ * refuses over nothing rather than after a roster wrap and a record are
1270
+ * written. An
1210
1271
  * absent generation log admits no writer.
1211
1272
  *
1212
1273
  * @param options {object}
@@ -1214,13 +1275,11 @@ async function admitActingRung({ ladderSeed, generationId, updateKeys, nextKeyHa
1214
1275
  * log store
1215
1276
  * @param options.ladderSeed {Uint8Array} the acting credential's ladder
1216
1277
  * seed
1217
- * @param options.generationId {string}
1218
1278
  * @param [options.expectedDid] {string} the annex DID the log must
1219
1279
  * resolve to, from the account document's pointer
1220
1280
  * @returns {Promise<boolean>}
1221
1281
  */
1222
- export async function clientAnnexRungAdmitted({ store, ladderSeed, generationId, expectedDid }) {
1223
- assertGenerationId(generationId);
1282
+ export async function clientAnnexRungAdmitted({ store, ladderSeed, expectedDid }) {
1224
1283
  const published = await readClientAnnexLogOrAbsent({
1225
1284
  store,
1226
1285
  ...(expectedDid !== undefined ? { expectedDid } : {})
@@ -1228,9 +1287,11 @@ export async function clientAnnexRungAdmitted({ store, ladderSeed, generationId,
1228
1287
  if (!published) {
1229
1288
  return false;
1230
1289
  }
1231
- const rung = await clientAnnexRung({ ladderSeed, generationId });
1232
- return (published.updateKeys.includes(rung.keyMultibase) ||
1233
- published.nextKeyHashes.includes(await deriveNextKeyHash(rung.keyMultibase)));
1290
+ return logCommitsRung({
1291
+ ladderSeed,
1292
+ updateKeys: published.updateKeys,
1293
+ nextKeyHashes: published.nextKeyHashes
1294
+ });
1234
1295
  }
1235
1296
  /**
1236
1297
  * Reads and resolves the published annex log through the narrow seam, or
@@ -1283,9 +1344,8 @@ export async function readClientAnnexLogOrAbsent({ store, expectedDid }) {
1283
1344
  /**
1284
1345
  * TRANSIENT ENROLLMENT: publishes one per-visit verification method into a
1285
1346
  * annex generation's log -- one atomic entry, signed by the writing
1286
- * credential's static rung 0 (derived from the ladder seed and the generation
1287
- * id;
1288
- * see `clientAnnexRung`). The entry:
1347
+ * credential's static annex rung (derived from the ladder seed alone; see
1348
+ * `clientAnnexRung`). The entry:
1289
1349
  *
1290
1350
  * - reveals the writer's rung-0 key into `updateKeys` at its first annex
1291
1351
  * write (later writes re-state it unchanged);
@@ -1320,7 +1380,6 @@ export async function readClientAnnexLogOrAbsent({ store, expectedDid }) {
1320
1380
  * controller-tier)
1321
1381
  * @param options.ladderSeed {Uint8Array} the credential's ladder seed, from
1322
1382
  * its unlock record
1323
- * @param options.generationId {string} the generation collection's name
1324
1383
  * @param options.transientKeyMultibase {string} the visit's in-memory
1325
1384
  * Ed25519 signing key, public multibase
1326
1385
  * @param [options.services] {ServiceEndpoint[]} the annex document's
@@ -1363,8 +1422,7 @@ export async function enrollClientAnnexTransientClient({ published: threadedHead
1363
1422
  * @param options {object} see {@link enrollClientAnnexTransientClient}
1364
1423
  * @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog }>}
1365
1424
  */
1366
- async function enrollClientAnnexTransientClientOnce({ store, ladderSeed, generationId, transientKeyMultibase, services, mintGenerationDelegation: mintDelegation, expectedDid, published: alreadyRead }) {
1367
- assertGenerationId(generationId);
1425
+ async function enrollClientAnnexTransientClientOnce({ store, ladderSeed, transientKeyMultibase, services, mintGenerationDelegation: mintDelegation, expectedDid, published: alreadyRead }) {
1368
1426
  const published = alreadyRead !== undefined
1369
1427
  ? assertPublishedLogDid({
1370
1428
  published: alreadyRead,
@@ -1385,7 +1443,6 @@ async function enrollClientAnnexTransientClientOnce({ store, ladderSeed, generat
1385
1443
  }
1386
1444
  const rung = await admitActingRung({
1387
1445
  ladderSeed,
1388
- generationId,
1389
1446
  updateKeys: published.updateKeys,
1390
1447
  nextKeyHashes: published.nextKeyHashes,
1391
1448
  message: "client annex: the log commits neither this credential's rung-0 key nor " +
@@ -1683,7 +1740,6 @@ export async function enrollTransientClient({ readAccountDocument, storeForGener
1683
1740
  const enrolled = await enrollClientAnnexTransientClient({
1684
1741
  store: storeForGenerationId(generationId),
1685
1742
  ladderSeed,
1686
- generationId,
1687
1743
  transientKeyMultibase,
1688
1744
  expectedDid: clientAnnexDid,
1689
1745
  ...(head !== undefined ? { published: head } : {}),
@@ -1739,6 +1795,10 @@ export async function enrollTransientClient({ readAccountDocument, storeForGener
1739
1795
  * pins; the store derives each log's slot
1740
1796
  * @param [options.capability] {IZcap} the sibling delegation the annex
1741
1797
  * writes ride, for a caller holding a standing invocation authority
1798
+ * @param [options.standingRungHashes] {string[]} the superseded
1799
+ * generation's standing set, restated in the fresh genesis (see
1800
+ * {@link mintCredentialClientAnnexGeneration}); absent on a first
1801
+ * generation and wherever no superseded log was readable
1742
1802
  * @param [options.beforePointerEntry] {Function}
1743
1803
  * `({ minted }) => Promise<void>` -- runs after the install and before the
1744
1804
  * pointer entry, with the mint's published head (its `spaceDescription`
@@ -1747,7 +1807,7 @@ export async function enrollTransientClient({ readAccountDocument, storeForGener
1747
1807
  * @returns {Promise<{ clientAnnexDid: string, generationDelegation: IZcap,
1748
1808
  * pointed: T }>}
1749
1809
  */
1750
- export async function mintPointedClientAnnexGeneration({ was, wasServerUrl, spaceId, controller, ladderSeed, mintGenerationDelegation, point, pinStore, capability, beforePointerEntry, now }) {
1810
+ export async function mintPointedClientAnnexGeneration({ was, wasServerUrl, spaceId, controller, ladderSeed, mintGenerationDelegation, point, pinStore, capability, standingRungHashes, beforePointerEntry, now }) {
1751
1811
  const minted = await mintCredentialClientAnnexGeneration({
1752
1812
  was,
1753
1813
  wasServerUrl,
@@ -1755,7 +1815,8 @@ export async function mintPointedClientAnnexGeneration({ was, wasServerUrl, spac
1755
1815
  controller,
1756
1816
  ladderSeed,
1757
1817
  pinStore,
1758
- ...(capability !== undefined ? { capability } : {})
1818
+ ...(capability !== undefined ? { capability } : {}),
1819
+ ...(standingRungHashes !== undefined ? { standingRungHashes } : {})
1759
1820
  });
1760
1821
  const ensured = await ensureGenerationDelegationCurrent({
1761
1822
  store: clientAnnexLogStore({
@@ -1766,7 +1827,6 @@ export async function mintPointedClientAnnexGeneration({ was, wasServerUrl, spac
1766
1827
  ...(capability !== undefined ? { capability } : {})
1767
1828
  }),
1768
1829
  ladderSeed,
1769
- generationId: minted.generationId,
1770
1830
  mintGenerationDelegation,
1771
1831
  expectedDid: minted.did,
1772
1832
  ...(minted.etag !== undefined ? { published: minted } : {}),
@@ -1823,7 +1883,6 @@ export async function mintPointedClientAnnexGeneration({ was, wasServerUrl, spac
1823
1883
  * controller-tier)
1824
1884
  * @param options.ladderSeed {Uint8Array} the credential's ladder seed, from
1825
1885
  * its unlock record
1826
- * @param options.generationId {string} the generation collection's name
1827
1886
  * @param options.mintGenerationDelegation {Function}
1828
1887
  * `({ clientAnnexDid }) => Promise<IZcap>` -- mints the replacement
1829
1888
  * delegation (ladder-signed in a transient session)
@@ -1874,8 +1933,7 @@ export async function ensureGenerationDelegationCurrent({ published: threadedHea
1874
1933
  * @returns {Promise<{ delegation: IZcap, renewed: boolean,
1875
1934
  * published?: PublishedWebvhLog }>}
1876
1935
  */
1877
- async function ensureGenerationDelegationCurrentOnce({ store, ladderSeed, generationId, mintGenerationDelegation: mintDelegation, expectedDid, accountDoc, retiringKeyMultibases = [], now, published: alreadyRead }) {
1878
- assertGenerationId(generationId);
1936
+ async function ensureGenerationDelegationCurrentOnce({ store, ladderSeed, mintGenerationDelegation: mintDelegation, expectedDid, accountDoc, retiringKeyMultibases = [], now, published: alreadyRead }) {
1879
1937
  const published = alreadyRead !== undefined
1880
1938
  ? assertPublishedLogDid({
1881
1939
  published: alreadyRead,
@@ -1900,7 +1958,6 @@ async function ensureGenerationDelegationCurrentOnce({ store, ladderSeed, genera
1900
1958
  // who cannot publish the entry that would carry it.
1901
1959
  const rung = await admitActingRung({
1902
1960
  ladderSeed,
1903
- generationId,
1904
1961
  updateKeys: published.updateKeys,
1905
1962
  nextKeyHashes: published.nextKeyHashes,
1906
1963
  message: "client annex: the log commits neither this credential's rung-0 key nor " +
@@ -1947,18 +2004,18 @@ async function ensureGenerationDelegationCurrentOnce({ store, ladderSeed, genera
1947
2004
  * retired members are excluded -- so the retired credential can never sign
1948
2005
  * its own strike) is refused with {@link ClientAnnexRungUncommittedError},
1949
2006
  * which the caller maps to the generation-swap fallback: a fresh generation
1950
- * minted from a surviving credential's seed retires the rung with the whole
1951
- * generation.
2007
+ * minted from a surviving credential's seed restates the old generation's
2008
+ * standing set EXCLUDING the retired rung's hash, so the retired rung does
2009
+ * not reach the fresh generation (`swapClientAnnexGeneration` with
2010
+ * `retiredLadderSeeds`).
1952
2011
  *
1953
2012
  * @param options {object}
1954
2013
  * @param options.store {ClientAnnexWriteStore} the pointed generation's log
1955
2014
  * store (controller-tier, or delegated through a sibling delegation)
1956
2015
  * @param options.retiredLadderSeed {Uint8Array} the RETIRED credential's
1957
- * ladder seed (its rung is derived per generation, so the seed is the only
1958
- * way to name what to strike)
2016
+ * ladder seed, from which its static annex rung is derived
1959
2017
  * @param options.actingLadderSeed {Uint8Array} a surviving credential's
1960
2018
  * ladder seed, whose committed rung 0 signs the strike entry
1961
- * @param options.generationId {string} the generation collection's name
1962
2019
  * @param [options.expectedDid] {string} the annex DID the log must
1963
2020
  * resolve to, from the account document's pointer. The read and the publish
1964
2021
  * run under the store's own chain-head pin
@@ -1975,16 +2032,12 @@ export async function retireClientAnnexRung(options) {
1975
2032
  * @param options {object} see {@link retireClientAnnexRung}
1976
2033
  * @returns {Promise<{ struck: boolean }>}
1977
2034
  */
1978
- async function retireClientAnnexRungOnce({ store, retiredLadderSeed, actingLadderSeed, generationId, expectedDid }) {
1979
- assertGenerationId(generationId);
2035
+ async function retireClientAnnexRungOnce({ store, retiredLadderSeed, actingLadderSeed, expectedDid }) {
1980
2036
  const published = await readClientAnnexLogOrThrow({
1981
2037
  store,
1982
2038
  ...(expectedDid !== undefined ? { expectedDid } : {})
1983
2039
  });
1984
- const retired = await clientAnnexRung({
1985
- ladderSeed: retiredLadderSeed,
1986
- generationId
1987
- });
2040
+ const retired = await clientAnnexRung({ ladderSeed: retiredLadderSeed });
1988
2041
  const retiredHash = await deriveNextKeyHash(retired.keyMultibase);
1989
2042
  const remainingKeys = published.updateKeys.filter(key => key !== retired.keyMultibase);
1990
2043
  const remainingHashes = published.nextKeyHashes.filter(hash => hash !== retiredHash);
@@ -1998,7 +2051,6 @@ async function retireClientAnnexRungOnce({ store, retiredLadderSeed, actingLadde
1998
2051
  // excluded, so the retired credential can never sign its own strike.
1999
2052
  const acting = await admitActingRung({
2000
2053
  ladderSeed: actingLadderSeed,
2001
- generationId,
2002
2054
  updateKeys: remainingKeys,
2003
2055
  nextKeyHashes: remainingHashes,
2004
2056
  message: "client annex: the log commits neither the acting credential's rung-0 " +
@@ -2027,11 +2079,11 @@ async function retireClientAnnexRungOnce({ store, retiredLadderSeed, actingLadde
2027
2079
  * hash to a generation's `nextKeyHashes` -- one atomic hash-restating entry
2028
2080
  * signed by an already-committed credential's rung 0. The bind ceremonies'
2029
2081
  * annex reach (passkey add, passphrase change): a bind runs from a logged-in
2030
- * session whose own login credential's rung 0 is committed, so committing the
2082
+ * session whose own login credential's rung is committed, so committing the
2031
2083
  * new credential's hash here is what keeps it out of the mid-generation
2032
2084
  * lockout ({@link ClientAnnexRungUncommittedError} at its first transient
2033
- * login, otherwise standing; a GC swap another credential drives does not
2034
- * end it).
2085
+ * login, otherwise standing). Once committed, the hash rides every later
2086
+ * swap's restated set.
2035
2087
  *
2036
2088
  * A log already committing the bound rung's hash (or carrying its revealed
2037
2089
  * key) is a no-op (`committed: false`) -- the resumable shape. An acting rung
@@ -2044,11 +2096,9 @@ async function retireClientAnnexRungOnce({ store, retiredLadderSeed, actingLadde
2044
2096
  * @param options.store {ClientAnnexWriteStore} the pointed generation's log
2045
2097
  * store (controller-tier, or delegated through a sibling delegation)
2046
2098
  * @param options.boundLadderSeed {Uint8Array} the freshly bound
2047
- * credential's ladder seed (its rung is derived per generation, so the seed
2048
- * is the only way to name what to commit)
2099
+ * credential's ladder seed, from which its static annex rung is derived
2049
2100
  * @param options.actingLadderSeed {Uint8Array} the logged-in session's
2050
2101
  * login credential's ladder seed, whose committed rung 0 signs the entry
2051
- * @param options.generationId {string} the generation collection's name
2052
2102
  * @param [options.expectedDid] {string} the annex DID the log must
2053
2103
  * resolve to, from the account document's pointer. The read and the publish
2054
2104
  * run under the store's own chain-head pin
@@ -2065,16 +2115,12 @@ export async function commitClientAnnexRung(options) {
2065
2115
  * @param options {object} see {@link commitClientAnnexRung}
2066
2116
  * @returns {Promise<{ committed: boolean }>}
2067
2117
  */
2068
- async function commitClientAnnexRungOnce({ store, boundLadderSeed, actingLadderSeed, generationId, expectedDid }) {
2069
- assertGenerationId(generationId);
2118
+ async function commitClientAnnexRungOnce({ store, boundLadderSeed, actingLadderSeed, expectedDid }) {
2070
2119
  const published = await readClientAnnexLogOrThrow({
2071
2120
  store,
2072
2121
  ...(expectedDid !== undefined ? { expectedDid } : {})
2073
2122
  });
2074
- const bound = await clientAnnexRung({
2075
- ladderSeed: boundLadderSeed,
2076
- generationId
2077
- });
2123
+ const bound = await clientAnnexRung({ ladderSeed: boundLadderSeed });
2078
2124
  const boundHash = await deriveNextKeyHash(bound.keyMultibase);
2079
2125
  if (published.updateKeys.includes(bound.keyMultibase) ||
2080
2126
  published.nextKeyHashes.includes(boundHash)) {
@@ -2084,7 +2130,6 @@ async function commitClientAnnexRungOnce({ store, boundLadderSeed, actingLadderS
2084
2130
  }
2085
2131
  const acting = await admitActingRung({
2086
2132
  ladderSeed: actingLadderSeed,
2087
- generationId,
2088
2133
  updateKeys: published.updateKeys,
2089
2134
  nextKeyHashes: published.nextKeyHashes,
2090
2135
  message: "client annex: the log commits neither the acting credential's rung-0 " +