@interop/wallet-core 0.9.0 → 0.11.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.
Files changed (45) hide show
  1. package/README.md +8 -3
  2. package/dist/keyring/index.d.ts +1 -1
  3. package/dist/keyring/index.d.ts.map +1 -1
  4. package/dist/keyring/index.js +1 -1
  5. package/dist/keyring/index.js.map +1 -1
  6. package/dist/keyring/unlockSpace.d.ts +27 -0
  7. package/dist/keyring/unlockSpace.d.ts.map +1 -1
  8. package/dist/keyring/unlockSpace.js +31 -0
  9. package/dist/keyring/unlockSpace.js.map +1 -1
  10. package/dist/keys/index.d.ts +9 -1
  11. package/dist/keys/index.d.ts.map +1 -1
  12. package/dist/keys/index.js +8 -1
  13. package/dist/keys/index.js.map +1 -1
  14. package/dist/keys/pukCascade.d.ts +157 -0
  15. package/dist/keys/pukCascade.d.ts.map +1 -0
  16. package/dist/keys/pukCascade.js +235 -0
  17. package/dist/keys/pukCascade.js.map +1 -0
  18. package/dist/keys/pukRoster.d.ts +26 -0
  19. package/dist/keys/pukRoster.d.ts.map +1 -1
  20. package/dist/keys/pukRoster.js +30 -1
  21. package/dist/keys/pukRoster.js.map +1 -1
  22. package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
  23. package/dist/recovery/recoveryWebvh.js +1 -20
  24. package/dist/recovery/recoveryWebvh.js.map +1 -1
  25. package/dist/space/activity.d.ts +30 -0
  26. package/dist/space/activity.d.ts.map +1 -1
  27. package/dist/space/activity.js +33 -0
  28. package/dist/space/activity.js.map +1 -1
  29. package/dist/space/index.d.ts +1 -1
  30. package/dist/space/index.d.ts.map +1 -1
  31. package/dist/space/index.js +1 -1
  32. package/dist/space/index.js.map +1 -1
  33. package/dist/webvh/didWebvh.d.ts +14 -0
  34. package/dist/webvh/didWebvh.d.ts.map +1 -1
  35. package/dist/webvh/didWebvh.js +20 -0
  36. package/dist/webvh/didWebvh.js.map +1 -1
  37. package/dist/webvh/index.d.ts +7 -4
  38. package/dist/webvh/index.d.ts.map +1 -1
  39. package/dist/webvh/index.js +6 -4
  40. package/dist/webvh/index.js.map +1 -1
  41. package/dist/webvh/revokeClient.d.ts +64 -0
  42. package/dist/webvh/revokeClient.d.ts.map +1 -0
  43. package/dist/webvh/revokeClient.js +241 -0
  44. package/dist/webvh/revokeClient.js.map +1 -0
  45. package/package.json +3 -3
package/README.md CHANGED
@@ -63,13 +63,18 @@ The subpaths:
63
63
 
64
64
  - **`@interop/wallet-core/webvh`** -- the account's did:webvh identity: the
65
65
  hosted DID log, its per-client update-key rotation, the client enrollment
66
- entries, and ZCap signing under the did:webvh verification-method id.
66
+ entries, the one-entry client-revocation edit (verification methods, update
67
+ key, and standing commitments out in a single entry, the staged commitment
68
+ recovered by log attribution), and ZCap signing under the did:webvh
69
+ verification-method id.
67
70
 
68
71
  - **`@interop/wallet-core/keys`** -- the per-user key (PUK) and its
69
72
  `key-map/puk.json` wrap-set roster: minting, the roster's init/read/rotate
70
73
  primitives with their client-side guards (`epochsMac`, the latest-seen epoch
71
- pin, the document-backed recipient resolver), and the roster's
72
- compare-and-swap descriptor store.
74
+ pin, the document-backed recipient resolver), the roster's compare-and-swap
75
+ descriptor store, and the PUK rotation cascade's per-collection op (re-epoch a
76
+ collection onto the roster's current PUK, staleness detected from durable
77
+ state alone, history escrowed -- also the completion sweep's building block).
73
78
 
74
79
  - **`@interop/wallet-core/descriptors`** -- collection encryption-descriptor
75
80
  acquisition (fetch / cache / offline fallback) and the unknown-epoch refresh
@@ -25,6 +25,6 @@ export { deriveUnlockIdentity, KEYRING_KDF, UNLOCK_HANDLE, UNLOCK_KEY_NAME, unlo
25
25
  export type { UnlockIdentity, UnlockKdf } from './kdf.js';
26
26
  export { KEYRING_RECORD_VERSION, parseRecordPointer, unwrapKeyringRecord, wrapKeyringRecord } from './record.js';
27
27
  export type { AccountPointer, KeyringRecordContents } from './record.js';
28
- export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, UNLOCK_SPACE_NAME } from './unlockSpace.js';
28
+ export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, putUnlockKeyringWithCapability, UNLOCK_SPACE_NAME } from './unlockSpace.js';
29
29
  export { fetchKeyringRecord } from './fetch.js';
30
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,8BAA8B,EAC9B,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
@@ -23,6 +23,6 @@
23
23
  */
24
24
  export { deriveUnlockIdentity, KEYRING_KDF, UNLOCK_HANDLE, UNLOCK_KEY_NAME, unlockSpaceIdFor } from './kdf.js';
25
25
  export { KEYRING_RECORD_VERSION, parseRecordPointer, unwrapKeyringRecord, wrapKeyringRecord } from './record.js';
26
- export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, UNLOCK_SPACE_NAME } from './unlockSpace.js';
26
+ export { deleteUnlockSpace, deleteUnlockSpaceWithCapability, ensureUnlockSpace, getUnlockKeyring, putUnlockKeyring, putUnlockKeyringWithCapability, UNLOCK_SPACE_NAME } from './unlockSpace.js';
27
27
  export { fetchKeyringRecord } from './fetch.js';
28
28
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAGjB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keyring/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAGjB,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EACL,iBAAiB,EACjB,+BAA+B,EAC/B,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,8BAA8B,EAC9B,iBAAiB,EAClB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA"}
@@ -59,6 +59,33 @@ export declare function putUnlockKeyring({ storageServerUrl, zcapClient, spaceId
59
59
  spaceId: string;
60
60
  record: object;
61
61
  }): Promise<void>;
62
+ /**
63
+ * Writes (upserts) the keyring record with an explicitly attached management
64
+ * capability, rather than by root invocation. The `zcapClient` here is an
65
+ * enrolled client's (not the unlock identity's); the attached `capability` --
66
+ * the management zcap the unlock identity delegated at bind time, provided it
67
+ * allows PUT -- authorizes the write against the unlock Space. This is what
68
+ * lets the revocation cascade re-PUT a recovery code's unlock record (a fresh
69
+ * `did.jsonl` delegation inside a re-wrapped record) without holding the
70
+ * code: the record's JWE recipient is the code's unlock KAK, whose PUBLIC
71
+ * half the issuing client recorded, so re-encryption needs no secret.
72
+ *
73
+ * @param options {object}
74
+ * @param options.storageServerUrl {string}
75
+ * @param options.zcapClient {ZcapClient} an enrolled client's zcap client
76
+ * @param options.spaceId {string} the unlock Space id
77
+ * @param options.record {object} the keyring record
78
+ * @param options.capability {IZcap} the delegated management zcap (must
79
+ * allow PUT)
80
+ * @returns {Promise<void>}
81
+ */
82
+ export declare function putUnlockKeyringWithCapability({ storageServerUrl, zcapClient, spaceId, record, capability }: {
83
+ storageServerUrl: string;
84
+ zcapClient: ZcapClient;
85
+ spaceId: string;
86
+ record: object;
87
+ capability: IZcap;
88
+ }): Promise<void>;
62
89
  /**
63
90
  * Deletes the whole unlock Space (what retires an old passphrase on a
64
91
  * passphrase change). `space.delete()` is idempotent, so an already-absent
@@ -1 +1 @@
1
- {"version":3,"file":"unlockSpace.d.ts","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uBAAuB,CAAA;AAoIrD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACV,IAAwB,EACzB,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQ1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EACP,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,+BAA+B,CAAC,EACpD,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACX,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,KAAK,CAAA;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB"}
1
+ {"version":3,"file":"unlockSpace.d.ts","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGhD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uBAAuB,CAAA;AAoIrD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACV,IAAwB,EACzB,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAQ1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EACP,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,8BAA8B,CAAC,EACnD,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EACN,UAAU,EACX,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,KAAK,CAAA;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,gBAAgB,EAChB,UAAU,EACV,OAAO,EACR,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,+BAA+B,CAAC,EACpD,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,UAAU,EACX,EAAE;IACD,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,KAAK,CAAA;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAchB"}
@@ -175,6 +175,37 @@ export async function putUnlockKeyring({ storageServerUrl, zcapClient, spaceId,
175
175
  record
176
176
  });
177
177
  }
178
+ /**
179
+ * Writes (upserts) the keyring record with an explicitly attached management
180
+ * capability, rather than by root invocation. The `zcapClient` here is an
181
+ * enrolled client's (not the unlock identity's); the attached `capability` --
182
+ * the management zcap the unlock identity delegated at bind time, provided it
183
+ * allows PUT -- authorizes the write against the unlock Space. This is what
184
+ * lets the revocation cascade re-PUT a recovery code's unlock record (a fresh
185
+ * `did.jsonl` delegation inside a re-wrapped record) without holding the
186
+ * code: the record's JWE recipient is the code's unlock KAK, whose PUBLIC
187
+ * half the issuing client recorded, so re-encryption needs no secret.
188
+ *
189
+ * @param options {object}
190
+ * @param options.storageServerUrl {string}
191
+ * @param options.zcapClient {ZcapClient} an enrolled client's zcap client
192
+ * @param options.spaceId {string} the unlock Space id
193
+ * @param options.record {object} the keyring record
194
+ * @param options.capability {IZcap} the delegated management zcap (must
195
+ * allow PUT)
196
+ * @returns {Promise<void>}
197
+ */
198
+ export async function putUnlockKeyringWithCapability({ storageServerUrl, zcapClient, spaceId, record, capability }) {
199
+ const was = unlockSpaceClient({ storageServerUrl, zcapClient });
200
+ const body = new TextEncoder().encode(JSON.stringify(record));
201
+ await was.request({
202
+ capability,
203
+ path: `/space/${spaceId}/${KEYRING_COLLECTION.id}/${KEYRING_RESOURCE}`,
204
+ method: 'PUT',
205
+ headers: { 'content-type': 'application/json' },
206
+ body
207
+ });
208
+ }
178
209
  /**
179
210
  * Deletes the whole unlock Space (what retires an old passphrase on a
180
211
  * passphrase change). `space.delete()` is idempotent, so an already-absent
@@ -1 +1 @@
1
- {"version":3,"file":"unlockSpace.js","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"unlockSpace.js","sourceRoot":"","sources":["../../src/keyring/unlockSpace.ts"],"names":[],"mappings":"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"}
@@ -16,10 +16,18 @@
16
16
  * document).
17
17
  * - `pukRosterDescriptorStore` -- that descriptor store, built from a bare
18
18
  * signing client for the login-time direct read.
19
+ * - `rotatePukRoster` / `unwrapPukGenerations` / `rotateCollectionEpochsToPuk`
20
+ * / `cascadeCollectionsToPuk` / `pukAsRecipient` -- the PUK rotation
21
+ * cascade: the roster rotation off a revoked recipient, the per-collection
22
+ * re-epoch that brings an encrypted collection onto the roster's current
23
+ * PUK, and the parallel best-effort fan-out over the collections the wallet
24
+ * names (also the completion sweep's driver).
19
25
  */
20
26
  export { mintPuk, pukVaultKeys } from './puk.js';
21
27
  export type { Puk } from './puk.js';
22
- export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster } from './pukRoster.js';
28
+ export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster, rotatePukRoster } from './pukRoster.js';
29
+ export { cascadeCollectionsToPuk, pukAsRecipient, rotateCollectionEpochsToPuk, unwrapPukGenerations } from './pukCascade.js';
30
+ export type { CollectionPukRotationOutcome, PukCascadeResult } from './pukCascade.js';
23
31
  export type { PukRosterReadResult, RosterRecipientDocument } from './pukRoster.js';
24
32
  export { pukRosterDescriptorStore } from './rosterStore.js';
25
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAChD,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAChD,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAEnC,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACb,eAAe,EAChB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,2BAA2B,EAC3B,oBAAoB,EACrB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,4BAA4B,EAC5B,gBAAgB,EACjB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -16,8 +16,15 @@
16
16
  * document).
17
17
  * - `pukRosterDescriptorStore` -- that descriptor store, built from a bare
18
18
  * signing client for the login-time direct read.
19
+ * - `rotatePukRoster` / `unwrapPukGenerations` / `rotateCollectionEpochsToPuk`
20
+ * / `cascadeCollectionsToPuk` / `pukAsRecipient` -- the PUK rotation
21
+ * cascade: the roster rotation off a revoked recipient, the per-collection
22
+ * re-epoch that brings an encrypted collection onto the roster's current
23
+ * PUK, and the parallel best-effort fan-out over the collections the wallet
24
+ * names (also the completion sweep's driver).
19
25
  */
20
26
  export { mintPuk, pukVaultKeys } from './puk.js';
21
- export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster } from './pukRoster.js';
27
+ export { addPukRosterRecipient, ensurePukRoster, PukRosterContinuityError, PukRosterIntegrityError, PukRosterUnwrapError, pukRosterRecipientResolver, readPukRoster, rotatePukRoster } from './pukRoster.js';
28
+ export { cascadeCollectionsToPuk, pukAsRecipient, rotateCollectionEpochsToPuk, unwrapPukGenerations } from './pukCascade.js';
22
29
  export { pukRosterDescriptorStore } from './rosterStore.js';
23
30
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGhD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACd,MAAM,gBAAgB,CAAA;AAMvB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/keys/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGhD,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,aAAa,EACb,eAAe,EAChB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,2BAA2B,EAC3B,oBAAoB,EACrB,MAAM,iBAAiB,CAAA;AAUxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -0,0 +1,157 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The per-collection half of the PUK rotation cascade: once the roster's
6
+ * current epoch has moved to a fresh PUK (a client revoked, a recovery code
7
+ * spent or revoked), every encrypted collection must take a new epoch naming
8
+ * the fresh PUK and retire the old one -- otherwise writes keep landing under
9
+ * an epoch key the revoked party still holds.
10
+ *
11
+ * The staleness rule is the one the revocation spike verified: **a collection
12
+ * is stale exactly when its current epoch names a PUK KAK other than the
13
+ * roster's current** -- detectable from durable data alone, no checkpoint
14
+ * resource anywhere, which is what makes a crashed cascade resumable by a
15
+ * naive full re-run (and what the login-time completion sweep re-checks).
16
+ * Which KAKs are "PUK generations" is read from the roster itself: its epochs
17
+ * ARE the PUK generations, each escrow-wrapped to every enrolled client, so
18
+ * any enrolled client can recover any generation's key
19
+ * ({@link unwrapPukGenerations}) -- needed both to recognize a stale epoch
20
+ * and to escrow the fresh PUK into a stranded collection's history.
21
+ *
22
+ * One residue, accepted: a collection with NO epochs gets the newest prior
23
+ * generation installed as its first epoch (pre-epoch envelopes are sealed to
24
+ * the era's PUK KAK, and the PUK IS the epoch construction, so they ARE
25
+ * epoch-of-that-generation envelopes) -- envelopes older than that
26
+ * generation, on a collection every prior cascade missed, stay readable only
27
+ * to sessions that held the older key.
28
+ */
29
+ import type { IKeyAgreementKey } from '@interop/data-integrity-core';
30
+ import type { CollectionEncryption } from '@interop/was-client';
31
+ import { type EncryptionDescriptorStore, type RecipientPublicKey } from '@interop/was-client/edv';
32
+ import { type Puk } from './puk.js';
33
+ /**
34
+ * A PUK presented as an epoch-roster recipient: the kid is the
35
+ * self-describing `<did:key>#<fingerprint>` form every collection epoch names
36
+ * the user under, and the public key is the did:key's own multibase.
37
+ *
38
+ * @param options {object}
39
+ * @param options.puk {Puk}
40
+ * @returns {RecipientPublicKey}
41
+ */
42
+ export declare function pukAsRecipient({ puk }: {
43
+ puk: Puk;
44
+ }): RecipientPublicKey;
45
+ /**
46
+ * Recovers every PUK generation from the roster descriptor: each roster epoch
47
+ * is one generation (its id the generation's did:key, its wrapped secret the
48
+ * generation's raw key), escrow-wrapped to every enrolled client -- so this
49
+ * client's key-agreement key unwraps them all, in roster (chronological)
50
+ * order. A generation whose wrap is missing or fails to unwrap is skipped
51
+ * rather than fatal (the cascade then simply cannot recognize or escrow that
52
+ * generation; the current epoch always unwraps or the roster read itself
53
+ * would have refused).
54
+ *
55
+ * @param options {object}
56
+ * @param options.descriptor {CollectionEncryption} the roster descriptor
57
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
58
+ * (identity) key-agreement key
59
+ * @returns {Promise<Puk[]>} the generations, oldest first
60
+ */
61
+ export declare function unwrapPukGenerations({ descriptor, clientKeyAgreementKey }: {
62
+ descriptor: CollectionEncryption;
63
+ clientKeyAgreementKey: IKeyAgreementKey;
64
+ }): Promise<Puk[]>;
65
+ /**
66
+ * What one collection's cascade step did: `noop` (already on the current
67
+ * PUK), `installed` (a pre-epoch collection on a first-generation account
68
+ * gained its first epoch; nothing to retire), `escrowed` (the current PUK's
69
+ * wrap was completed into history with no stale epoch to rotate), or
70
+ * `rotated` (a fresh epoch sealed to the current PUK, the stale generations
71
+ * retired -- the pre-epoch install falls through to this).
72
+ */
73
+ export type CollectionPukRotationOutcome = 'noop' | 'installed' | 'escrowed' | 'rotated';
74
+ /**
75
+ * Brings ONE encrypted collection's epoch roster onto the current PUK -- the
76
+ * per-collection op of the revocation cascade and of the completion sweep:
77
+ *
78
+ * - **No epochs yet**: install the newest PRIOR generation as the first epoch
79
+ * (see the module doc), wrapped to that generation and the current PUK,
80
+ * then fall through to the rotation. A first-generation account (nothing
81
+ * prior) installs the current PUK alone and is done.
82
+ * - **Stale current epoch** (names a non-current generation): one
83
+ * `replaceRecipient` write -- the current PUK escrowed into every epoch,
84
+ * a fresh epoch minted without the stale generations. Two requests per
85
+ * collection; app recipients and other readers ride through untouched (the
86
+ * default did:key resolver re-wraps them).
87
+ * - **Current already** and fully escrowed: no write at all, so a naive
88
+ * re-run after a mid-cascade crash converges with zero redundant epochs.
89
+ *
90
+ * The pull axis is deliberately a no-op here: a PUK rotation follows a
91
+ * document edit (client revocation, code retirement) that already killed the
92
+ * revoked party's server-side access everywhere under the current-key-set
93
+ * rule -- there is no per-collection revoke.
94
+ *
95
+ * @param options {object}
96
+ * @param options.store {EncryptionDescriptorStore} the collection's
97
+ * descriptor store
98
+ * @param options.puk {Puk} the roster's CURRENT PUK
99
+ * @param options.generations {Puk[]} every roster generation this client
100
+ * could unwrap ({@link unwrapPukGenerations}), oldest first
101
+ * @returns {Promise<CollectionPukRotationOutcome>}
102
+ */
103
+ export declare function rotateCollectionEpochsToPuk({ store, puk, generations }: {
104
+ store: EncryptionDescriptorStore;
105
+ puk: Puk;
106
+ generations: Puk[];
107
+ }): Promise<CollectionPukRotationOutcome>;
108
+ /**
109
+ * What the collection fan-out did, per collection id: the outcomes for every
110
+ * collection that needed (or took) work, and the per-collection failures the
111
+ * caller surfaces -- the cascade never aborts on one stuck collection.
112
+ */
113
+ export interface PukCascadeResult {
114
+ outcomes: Record<string, CollectionPukRotationOutcome>;
115
+ failed: Array<{
116
+ collectionId: string;
117
+ error: unknown;
118
+ }>;
119
+ }
120
+ /**
121
+ * The collection fan-out of the PUK rotation cascade: re-epochs every named
122
+ * collection onto the roster's current PUK, in parallel, unwrapping the PUK
123
+ * generations from the roster once. The wallet supplies what only it knows --
124
+ * which collections exist (`collectionIds`) and how to reach each one's
125
+ * descriptor (`storeFor`); the per-collection staleness rule and re-epoch live
126
+ * in {@link rotateCollectionEpochsToPuk}.
127
+ *
128
+ * A collection that fails is reported in `failed` and the rest proceed; the
129
+ * caller decides what a failure means (the login-time completion sweep is the
130
+ * standing backstop, and the staleness rule makes a naive full re-run
131
+ * converge with zero redundant epochs).
132
+ *
133
+ * @param options {object}
134
+ * @param options.collectionIds {string[]} the encrypted collections to
135
+ * cover, deduplicated by the caller
136
+ * @param options.storeFor {Function} `(collectionId) =>
137
+ * EncryptionDescriptorStore` -- the collection's descriptor store
138
+ * @param [options.isEncrypted] {Function} `(collectionId) =>
139
+ * Promise<boolean>` -- optional pre-filter, checked inside each collection's
140
+ * own task so a throwing check lands in that collection's `failed` entry
141
+ * (e.g. a standard collection an account never provisioned server-side)
142
+ * @param options.rosterDescriptor {CollectionEncryption} the freshly read
143
+ * `key-map/puk.json` roster (the source of the PUK generations)
144
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
145
+ * (identity) key-agreement key, unwrapping the generations
146
+ * @param options.puk {Puk} the roster's current PUK
147
+ * @returns {Promise<PukCascadeResult>}
148
+ */
149
+ export declare function cascadeCollectionsToPuk({ collectionIds, storeFor, isEncrypted, rosterDescriptor, clientKeyAgreementKey, puk }: {
150
+ collectionIds: string[];
151
+ storeFor: (collectionId: string) => EncryptionDescriptorStore;
152
+ isEncrypted?: (collectionId: string) => Promise<boolean>;
153
+ rosterDescriptor: CollectionEncryption;
154
+ clientKeyAgreementKey: IKeyAgreementKey;
155
+ puk: Puk;
156
+ }): Promise<PukCascadeResult>;
157
+ //# sourceMappingURL=pukCascade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pukCascade.d.ts","sourceRoot":"","sources":["../../src/keys/pukCascade.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAML,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAgB,KAAK,GAAG,EAAE,MAAM,UAAU,CAAA;AAEjD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,kBAAkB,CAKxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,UAAU,EACV,qBAAqB,EACtB,EAAE;IACD,UAAU,EAAE,oBAAoB,CAAA;IAChC,qBAAqB,EAAE,gBAAgB,CAAA;CACxC,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAkBjB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,4BAA4B,GACtC,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,KAAK,EACL,GAAG,EACH,WAAW,EACZ,EAAE;IACD,KAAK,EAAE,yBAAyB,CAAA;IAChC,GAAG,EAAE,GAAG,CAAA;IACR,WAAW,EAAE,GAAG,EAAE,CAAA;CACnB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CA2HxC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAA;IACtD,MAAM,EAAE,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CACxD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,aAAa,EACb,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACrB,GAAG,EACJ,EAAE;IACD,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,yBAAyB,CAAA;IAC7D,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACxD,gBAAgB,EAAE,oBAAoB,CAAA;IACtC,qBAAqB,EAAE,gBAAgB,CAAA;IACvC,GAAG,EAAE,GAAG,CAAA;CACT,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwB5B"}
@@ -0,0 +1,235 @@
1
+ import { addRecipient, epochKeyIdFor, initRecipients, replaceRecipient, unwrapEpochSecret } from '@interop/was-client/edv';
2
+ import { ValidationError } from '@interop/was-client';
3
+ import { pukVaultKeys } from './puk.js';
4
+ /**
5
+ * A PUK presented as an epoch-roster recipient: the kid is the
6
+ * self-describing `<did:key>#<fingerprint>` form every collection epoch names
7
+ * the user under, and the public key is the did:key's own multibase.
8
+ *
9
+ * @param options {object}
10
+ * @param options.puk {Puk}
11
+ * @returns {RecipientPublicKey}
12
+ */
13
+ export function pukAsRecipient({ puk }) {
14
+ return {
15
+ id: epochKeyIdFor(puk.id),
16
+ publicKeyMultibase: puk.id.split(':')[2]
17
+ };
18
+ }
19
+ /**
20
+ * Recovers every PUK generation from the roster descriptor: each roster epoch
21
+ * is one generation (its id the generation's did:key, its wrapped secret the
22
+ * generation's raw key), escrow-wrapped to every enrolled client -- so this
23
+ * client's key-agreement key unwraps them all, in roster (chronological)
24
+ * order. A generation whose wrap is missing or fails to unwrap is skipped
25
+ * rather than fatal (the cascade then simply cannot recognize or escrow that
26
+ * generation; the current epoch always unwraps or the roster read itself
27
+ * would have refused).
28
+ *
29
+ * @param options {object}
30
+ * @param options.descriptor {CollectionEncryption} the roster descriptor
31
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
32
+ * (identity) key-agreement key
33
+ * @returns {Promise<Puk[]>} the generations, oldest first
34
+ */
35
+ export async function unwrapPukGenerations({ descriptor, clientKeyAgreementKey }) {
36
+ const generations = [];
37
+ for (const epoch of descriptor.epochs ?? []) {
38
+ const entry = epoch.recipients.find(recipient => recipient.header.kid === clientKeyAgreementKey.id);
39
+ if (!entry) {
40
+ continue;
41
+ }
42
+ const secret = await unwrapEpochSecret({
43
+ entry,
44
+ keyAgreementKey: clientKeyAgreementKey
45
+ });
46
+ if (secret) {
47
+ generations.push({ id: epoch.id, secret });
48
+ }
49
+ }
50
+ return generations;
51
+ }
52
+ /**
53
+ * Brings ONE encrypted collection's epoch roster onto the current PUK -- the
54
+ * per-collection op of the revocation cascade and of the completion sweep:
55
+ *
56
+ * - **No epochs yet**: install the newest PRIOR generation as the first epoch
57
+ * (see the module doc), wrapped to that generation and the current PUK,
58
+ * then fall through to the rotation. A first-generation account (nothing
59
+ * prior) installs the current PUK alone and is done.
60
+ * - **Stale current epoch** (names a non-current generation): one
61
+ * `replaceRecipient` write -- the current PUK escrowed into every epoch,
62
+ * a fresh epoch minted without the stale generations. Two requests per
63
+ * collection; app recipients and other readers ride through untouched (the
64
+ * default did:key resolver re-wraps them).
65
+ * - **Current already** and fully escrowed: no write at all, so a naive
66
+ * re-run after a mid-cascade crash converges with zero redundant epochs.
67
+ *
68
+ * The pull axis is deliberately a no-op here: a PUK rotation follows a
69
+ * document edit (client revocation, code retirement) that already killed the
70
+ * revoked party's server-side access everywhere under the current-key-set
71
+ * rule -- there is no per-collection revoke.
72
+ *
73
+ * @param options {object}
74
+ * @param options.store {EncryptionDescriptorStore} the collection's
75
+ * descriptor store
76
+ * @param options.puk {Puk} the roster's CURRENT PUK
77
+ * @param options.generations {Puk[]} every roster generation this client
78
+ * could unwrap ({@link unwrapPukGenerations}), oldest first
79
+ * @returns {Promise<CollectionPukRotationOutcome>}
80
+ */
81
+ export async function rotateCollectionEpochsToPuk({ store, puk, generations }) {
82
+ const current = await store.read();
83
+ if (current === null) {
84
+ return 'noop';
85
+ }
86
+ let descriptor = current.descriptor;
87
+ const staleGenerations = generations.filter(generation => generation.id !== puk.id);
88
+ if (!descriptor.epochs?.length || !descriptor.currentEpoch) {
89
+ // Pre-epoch: the collection's envelopes are sealed to the era's PUK KAK,
90
+ // which -- the PUK being the epoch construction -- makes them epoch-of-
91
+ // that-generation envelopes. Install that generation as the first epoch.
92
+ const previous = staleGenerations[staleGenerations.length - 1];
93
+ if (!previous) {
94
+ await initRecipients({
95
+ store,
96
+ recipients: [pukAsRecipient({ puk })],
97
+ epoch: { epochId: puk.id, secret: puk.secret }
98
+ });
99
+ return 'installed';
100
+ }
101
+ try {
102
+ descriptor = await initRecipients({
103
+ store,
104
+ recipients: [
105
+ pukAsRecipient({ puk: previous }),
106
+ pukAsRecipient({ puk })
107
+ ],
108
+ epoch: { epochId: previous.id, secret: previous.secret }
109
+ });
110
+ }
111
+ catch (err) {
112
+ // A concurrent cascade won the first-epoch race; re-read and continue
113
+ // into the rotation below against whatever it installed.
114
+ if (!(err instanceof ValidationError)) {
115
+ throw err;
116
+ }
117
+ const reread = await store.read();
118
+ if (reread === null) {
119
+ throw err;
120
+ }
121
+ descriptor = reread.descriptor;
122
+ }
123
+ }
124
+ const currentEpoch = descriptor.epochs.find(epoch => epoch.id === descriptor.currentEpoch) ??
125
+ descriptor.epochs[descriptor.epochs.length - 1];
126
+ const currentKids = new Set(currentEpoch.recipients.map(entry => entry.header.kid));
127
+ const staleKids = staleGenerations
128
+ .map(generation => epochKeyIdFor(generation.id))
129
+ .filter(kid => currentKids.has(kid));
130
+ const pukKid = epochKeyIdFor(puk.id);
131
+ if (staleKids.length === 0) {
132
+ const escrowComplete = (descriptor.epochs ?? []).every(epoch => epoch.recipients.some(entry => entry.header.kid === pukKid));
133
+ if (currentKids.has(pukKid) && escrowComplete) {
134
+ return 'noop';
135
+ }
136
+ }
137
+ if (staleKids.length > 0) {
138
+ // The escrow owner: the newest stale generation still named by the
139
+ // current epoch, which the cascade invariant escrowed into every prior
140
+ // epoch -- so it unwraps the whole history for the fresh PUK's escrow.
141
+ const ownerGeneration = [...staleGenerations]
142
+ .reverse()
143
+ .find(generation => currentKids.has(epochKeyIdFor(generation.id)));
144
+ const owner = pukVaultKeys({ puk: ownerGeneration });
145
+ await replaceRecipient({
146
+ store,
147
+ retire: staleKids,
148
+ recipient: pukAsRecipient({ puk }),
149
+ owner: { keyAgreementKey: owner.keyAgreementKey },
150
+ pull: async () => { }
151
+ });
152
+ return 'rotated';
153
+ }
154
+ if (!currentKids.has(pukKid)) {
155
+ // No stale generation to retire, but the current PUK is not a recipient
156
+ // at all: this collection's roster is not PUK-owned in a shape this
157
+ // cascade can heal -- surface it rather than silently minting an epoch
158
+ // whose history the account cannot read.
159
+ throw new Error('The collection current epoch names no PUK generation this client ' +
160
+ 'can recognize; its roster cannot be rotated to the current PUK.');
161
+ }
162
+ // Escrow completion only: the current epoch is already on the current PUK,
163
+ // but some historical epoch is missing its wrap. The owner must unwrap
164
+ // exactly those epochs -- the newest generation named by every incomplete
165
+ // epoch.
166
+ const incomplete = (descriptor.epochs ?? []).filter(epoch => !epoch.recipients.some(entry => entry.header.kid === pukKid));
167
+ const escrowOwner = [...generations]
168
+ .reverse()
169
+ .find(generation => incomplete.every(epoch => epoch.recipients.some(entry => entry.header.kid === epochKeyIdFor(generation.id))));
170
+ if (!escrowOwner) {
171
+ throw new Error("The current PUK cannot be escrowed into this collection's history: " +
172
+ 'no held PUK generation is a recipient of every incomplete epoch.');
173
+ }
174
+ const owner = pukVaultKeys({ puk: escrowOwner });
175
+ await addRecipient({
176
+ store,
177
+ recipient: pukAsRecipient({ puk }),
178
+ owner: { keyAgreementKey: owner.keyAgreementKey }
179
+ });
180
+ return 'escrowed';
181
+ }
182
+ /**
183
+ * The collection fan-out of the PUK rotation cascade: re-epochs every named
184
+ * collection onto the roster's current PUK, in parallel, unwrapping the PUK
185
+ * generations from the roster once. The wallet supplies what only it knows --
186
+ * which collections exist (`collectionIds`) and how to reach each one's
187
+ * descriptor (`storeFor`); the per-collection staleness rule and re-epoch live
188
+ * in {@link rotateCollectionEpochsToPuk}.
189
+ *
190
+ * A collection that fails is reported in `failed` and the rest proceed; the
191
+ * caller decides what a failure means (the login-time completion sweep is the
192
+ * standing backstop, and the staleness rule makes a naive full re-run
193
+ * converge with zero redundant epochs).
194
+ *
195
+ * @param options {object}
196
+ * @param options.collectionIds {string[]} the encrypted collections to
197
+ * cover, deduplicated by the caller
198
+ * @param options.storeFor {Function} `(collectionId) =>
199
+ * EncryptionDescriptorStore` -- the collection's descriptor store
200
+ * @param [options.isEncrypted] {Function} `(collectionId) =>
201
+ * Promise<boolean>` -- optional pre-filter, checked inside each collection's
202
+ * own task so a throwing check lands in that collection's `failed` entry
203
+ * (e.g. a standard collection an account never provisioned server-side)
204
+ * @param options.rosterDescriptor {CollectionEncryption} the freshly read
205
+ * `key-map/puk.json` roster (the source of the PUK generations)
206
+ * @param options.clientKeyAgreementKey {IKeyAgreementKey} this client's own
207
+ * (identity) key-agreement key, unwrapping the generations
208
+ * @param options.puk {Puk} the roster's current PUK
209
+ * @returns {Promise<PukCascadeResult>}
210
+ */
211
+ export async function cascadeCollectionsToPuk({ collectionIds, storeFor, isEncrypted, rosterDescriptor, clientKeyAgreementKey, puk }) {
212
+ const generations = await unwrapPukGenerations({
213
+ descriptor: rosterDescriptor,
214
+ clientKeyAgreementKey
215
+ });
216
+ const outcomes = {};
217
+ const failed = [];
218
+ await Promise.all(collectionIds.map(async (collectionId) => {
219
+ try {
220
+ if (isEncrypted && !(await isEncrypted(collectionId))) {
221
+ return;
222
+ }
223
+ outcomes[collectionId] = await rotateCollectionEpochsToPuk({
224
+ store: storeFor(collectionId),
225
+ puk,
226
+ generations
227
+ });
228
+ }
229
+ catch (err) {
230
+ failed.push({ collectionId, error: err });
231
+ }
232
+ }));
233
+ return { outcomes, failed };
234
+ }
235
+ //# sourceMappingURL=pukCascade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pukCascade.js","sourceRoot":"","sources":["../../src/keys/pukCascade.ts"],"names":[],"mappings":"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"}