@interop/wallet-core 0.49.0 → 0.51.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 (163) hide show
  1. package/README.md +5 -2
  2. package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +127 -0
  3. package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -0
  4. package/dist/clientAnnex/credentialAnchoredGenesis.js +195 -0
  5. package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -0
  6. package/dist/clientAnnex/forget.d.ts +138 -0
  7. package/dist/clientAnnex/forget.d.ts.map +1 -0
  8. package/dist/clientAnnex/forget.js +133 -0
  9. package/dist/clientAnnex/forget.js.map +1 -0
  10. package/dist/clientAnnex/forgetLast.d.ts +291 -0
  11. package/dist/clientAnnex/forgetLast.d.ts.map +1 -0
  12. package/dist/clientAnnex/forgetLast.js +408 -0
  13. package/dist/clientAnnex/forgetLast.js.map +1 -0
  14. package/dist/{webvh/companionGc.d.ts → clientAnnex/gc.d.ts} +50 -16
  15. package/dist/clientAnnex/gc.d.ts.map +1 -0
  16. package/dist/{webvh/companionGc.js → clientAnnex/gc.js} +103 -71
  17. package/dist/clientAnnex/gc.js.map +1 -0
  18. package/dist/clientAnnex/index.d.ts +60 -0
  19. package/dist/clientAnnex/index.d.ts.map +1 -0
  20. package/dist/clientAnnex/index.js +60 -0
  21. package/dist/clientAnnex/index.js.map +1 -0
  22. package/dist/{unlock → clientAnnex}/ladder.d.ts +89 -15
  23. package/dist/clientAnnex/ladder.d.ts.map +1 -0
  24. package/dist/clientAnnex/ladder.js +474 -0
  25. package/dist/clientAnnex/ladder.js.map +1 -0
  26. package/dist/clientAnnex/ladderAnchored.d.ts +276 -0
  27. package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -0
  28. package/dist/clientAnnex/ladderAnchored.js +631 -0
  29. package/dist/clientAnnex/ladderAnchored.js.map +1 -0
  30. package/dist/{webvh/companion.d.ts → clientAnnex/log.d.ts} +333 -119
  31. package/dist/clientAnnex/log.d.ts.map +1 -0
  32. package/dist/{webvh/companion.js → clientAnnex/log.js} +583 -199
  33. package/dist/clientAnnex/log.js.map +1 -0
  34. package/dist/clientAnnex/recoveryLadderAnchored.d.ts +103 -0
  35. package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -0
  36. package/dist/clientAnnex/recoveryLadderAnchored.js +263 -0
  37. package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -0
  38. package/dist/{unlock → clientAnnex}/selfEnroll.d.ts +1 -1
  39. package/dist/clientAnnex/selfEnroll.d.ts.map +1 -0
  40. package/dist/{unlock → clientAnnex}/selfEnroll.js +1 -1
  41. package/dist/clientAnnex/selfEnroll.js.map +1 -0
  42. package/dist/clientAnnex/zcap.d.ts +49 -0
  43. package/dist/clientAnnex/zcap.d.ts.map +1 -0
  44. package/dist/clientAnnex/zcap.js +101 -0
  45. package/dist/clientAnnex/zcap.js.map +1 -0
  46. package/dist/clients/index.d.ts +9 -6
  47. package/dist/clients/index.d.ts.map +1 -1
  48. package/dist/clients/index.js +8 -5
  49. package/dist/clients/index.js.map +1 -1
  50. package/dist/clients/listing.d.ts +32 -0
  51. package/dist/clients/listing.d.ts.map +1 -1
  52. package/dist/clients/listing.js +47 -1
  53. package/dist/clients/listing.js.map +1 -1
  54. package/dist/clients/revocation.d.ts +33 -1
  55. package/dist/clients/revocation.d.ts.map +1 -1
  56. package/dist/clients/revocation.js +16 -4
  57. package/dist/clients/revocation.js.map +1 -1
  58. package/dist/enrollment/index.d.ts +6 -4
  59. package/dist/enrollment/index.d.ts.map +1 -1
  60. package/dist/enrollment/index.js +6 -4
  61. package/dist/enrollment/index.js.map +1 -1
  62. package/dist/enrollment/onboardingInvite.d.ts +5 -88
  63. package/dist/enrollment/onboardingInvite.d.ts.map +1 -1
  64. package/dist/enrollment/onboardingInvite.js +5 -168
  65. package/dist/enrollment/onboardingInvite.js.map +1 -1
  66. package/dist/genesis/accountGenesis.d.ts +12 -0
  67. package/dist/genesis/accountGenesis.d.ts.map +1 -1
  68. package/dist/genesis/accountGenesis.js.map +1 -1
  69. package/dist/genesis/index.d.ts +5 -0
  70. package/dist/genesis/index.d.ts.map +1 -1
  71. package/dist/genesis/index.js +5 -0
  72. package/dist/genesis/index.js.map +1 -1
  73. package/dist/keys/index.d.ts +1 -1
  74. package/dist/keys/index.d.ts.map +1 -1
  75. package/dist/keys/index.js +1 -1
  76. package/dist/keys/index.js.map +1 -1
  77. package/dist/keys/spaceEpochs.d.ts +7 -2
  78. package/dist/keys/spaceEpochs.d.ts.map +1 -1
  79. package/dist/keys/spaceEpochs.js +8 -2
  80. package/dist/keys/spaceEpochs.js.map +1 -1
  81. package/dist/keys/userKeyRoster.d.ts +39 -0
  82. package/dist/keys/userKeyRoster.d.ts.map +1 -1
  83. package/dist/keys/userKeyRoster.js +43 -1
  84. package/dist/keys/userKeyRoster.js.map +1 -1
  85. package/dist/recovery/index.d.ts +5 -3
  86. package/dist/recovery/index.d.ts.map +1 -1
  87. package/dist/recovery/index.js +4 -2
  88. package/dist/recovery/index.js.map +1 -1
  89. package/dist/recovery/recoveryDelegation.d.ts +35 -12
  90. package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
  91. package/dist/recovery/recoveryDelegation.js +84 -86
  92. package/dist/recovery/recoveryDelegation.js.map +1 -1
  93. package/dist/recovery/recoveryWebvh.d.ts +32 -1
  94. package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
  95. package/dist/recovery/recoveryWebvh.js +2 -2
  96. package/dist/recovery/recoveryWebvh.js.map +1 -1
  97. package/dist/request/capabilityRequest.d.ts +33 -0
  98. package/dist/request/capabilityRequest.d.ts.map +1 -0
  99. package/dist/request/capabilityRequest.js +35 -0
  100. package/dist/request/capabilityRequest.js.map +1 -0
  101. package/dist/request/ephemeralExchange.d.ts +118 -0
  102. package/dist/request/ephemeralExchange.d.ts.map +1 -0
  103. package/dist/request/ephemeralExchange.js +224 -0
  104. package/dist/request/ephemeralExchange.js.map +1 -0
  105. package/dist/request/index.d.ts +6 -0
  106. package/dist/request/index.d.ts.map +1 -1
  107. package/dist/request/index.js +6 -0
  108. package/dist/request/index.js.map +1 -1
  109. package/dist/space/activity.d.ts +2 -2
  110. package/dist/space/activity.js +3 -3
  111. package/dist/space/activity.js.map +1 -1
  112. package/dist/unlock/index.d.ts +11 -23
  113. package/dist/unlock/index.d.ts.map +1 -1
  114. package/dist/unlock/index.js +10 -21
  115. package/dist/unlock/index.js.map +1 -1
  116. package/dist/unlock/retire.d.ts +47 -3
  117. package/dist/unlock/retire.d.ts.map +1 -1
  118. package/dist/unlock/retire.js +21 -5
  119. package/dist/unlock/retire.js.map +1 -1
  120. package/dist/unlock/standingWebvh.d.ts +37 -82
  121. package/dist/unlock/standingWebvh.d.ts.map +1 -1
  122. package/dist/unlock/standingWebvh.js +64 -247
  123. package/dist/unlock/standingWebvh.js.map +1 -1
  124. package/dist/unlock/unlockRecord.d.ts +13 -6
  125. package/dist/unlock/unlockRecord.d.ts.map +1 -1
  126. package/dist/unlock/unlockRecord.js +14 -8
  127. package/dist/unlock/unlockRecord.js.map +1 -1
  128. package/dist/webvh/delegatedLogStore.d.ts +5 -5
  129. package/dist/webvh/delegatedLogStore.js +1 -1
  130. package/dist/webvh/didWebvh.d.ts +19 -9
  131. package/dist/webvh/didWebvh.d.ts.map +1 -1
  132. package/dist/webvh/didWebvh.js +16 -16
  133. package/dist/webvh/didWebvh.js.map +1 -1
  134. package/dist/webvh/index.d.ts +9 -25
  135. package/dist/webvh/index.d.ts.map +1 -1
  136. package/dist/webvh/index.js +9 -23
  137. package/dist/webvh/index.js.map +1 -1
  138. package/dist/webvh/revokeClient.d.ts +77 -5
  139. package/dist/webvh/revokeClient.d.ts.map +1 -1
  140. package/dist/webvh/revokeClient.js +154 -61
  141. package/dist/webvh/revokeClient.js.map +1 -1
  142. package/dist/webvh/standingZcap.d.ts +11 -1
  143. package/dist/webvh/standingZcap.d.ts.map +1 -1
  144. package/dist/webvh/standingZcap.js +13 -14
  145. package/dist/webvh/standingZcap.js.map +1 -1
  146. package/dist/webvh/wasIdStore.d.ts +13 -7
  147. package/dist/webvh/wasIdStore.d.ts.map +1 -1
  148. package/dist/webvh/wasIdStore.js +8 -4
  149. package/dist/webvh/wasIdStore.js.map +1 -1
  150. package/dist/webvh/zcap.d.ts +0 -24
  151. package/dist/webvh/zcap.d.ts.map +1 -1
  152. package/dist/webvh/zcap.js +0 -42
  153. package/dist/webvh/zcap.js.map +1 -1
  154. package/package.json +41 -35
  155. package/dist/unlock/ladder.d.ts.map +0 -1
  156. package/dist/unlock/ladder.js +0 -258
  157. package/dist/unlock/ladder.js.map +0 -1
  158. package/dist/unlock/selfEnroll.d.ts.map +0 -1
  159. package/dist/unlock/selfEnroll.js.map +0 -1
  160. package/dist/webvh/companion.d.ts.map +0 -1
  161. package/dist/webvh/companion.js.map +0 -1
  162. package/dist/webvh/companionGc.d.ts.map +0 -1
  163. package/dist/webvh/companionGc.js.map +0 -1
package/README.md CHANGED
@@ -57,8 +57,11 @@ The subpaths:
57
57
  injected), the App Connect app-key credential module (query validation,
58
58
  matching, minting, store-time refusal, legacy re-issue), the
59
59
  `WalletOnboardingQuery` transport vocabulary (compose and classification), the
60
- VC-API exchange client, and VCALM `interaction:` URL handling. The VPR type
61
- vocabulary lives in
60
+ VC-API exchange client, VCALM `interaction:` URL handling, the requester's
61
+ half of a server's ephemeral exchange (`createEphemeralExchange` /
62
+ `pollEphemeralExchange`, the poll bounded by a caller signal or its own
63
+ deadline), and `composeCapabilityRequest`, the zcap-only VPR a requester
64
+ stores on such an exchange. The VPR type vocabulary lives in
62
65
  [`@interop/data-integrity-core`](https://npm.im/@interop/data-integrity-core)
63
66
  and is re-exported here.
64
67
 
@@ -0,0 +1,127 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The account-genesis ceremony's CREDENTIAL-ANCHORED variant: such a
6
+ * signup mints no durable client, so the ceremony is anchored on the unlock
7
+ * credential's ladder alone. The stage order mirrors `ensureAccountGenesis`
8
+ * with the durable-client members swapped for their ladder analogs:
9
+ *
10
+ * 1. Space provisioning under the ladder VM's bare did:key -- the bootstrap
11
+ * controller (wallet-core decision 0004, freewallet decision 0002's
12
+ * resolution of the orphan-Space tear): re-derivable from the unlock
13
+ * record's ladder seed, so a tab death here strands nothing a later
14
+ * login cannot finish or unwind.
15
+ * 2. The ladder-anchored did:webvh genesis
16
+ * (`ensureLadderAnchoredDidWebvh`): the entry signed by ladder rung 0, `updateKeys` = [rung 0], `nextKeyHashes`
17
+ * = [hash(rung 0), hash(rung 1)], the ladder VM and the credential's
18
+ * `keyAgreement` posture folded in, `portable` unchanged. There is no KMS
19
+ * stage: the keystore is DEFERRED to the first durable enrollment (a
20
+ * ladder-anchored account has no consumer for the convenience VM, and a
21
+ * keystore under an evaporating identity would orphan).
22
+ * 3. The user-key roster genesis, wrapped to the CREDENTIAL's standing
23
+ * key-agreement key -- the only recipient a ladder-anchored account has
24
+ * -- with the entry proof signed by the ladder VM (the ceremony-tail
25
+ * license's first-entry shape). The account is credential-recoverable
26
+ * from the moment this lands.
27
+ * 4. Epoch[0] on every encrypted roster collection -- gated twice, unlike
28
+ * the durable flow. The roster stage must have landed, AND the roster's
29
+ * current epoch must BE the `userKey` this run was handed: the user key
30
+ * here exists only in this tab's memory, so installing collection epochs
31
+ * under a key the roster does not deliver would strand the collections
32
+ * on a key that dies with the tab. The second gate is what a re-run over
33
+ * an earlier run's roster hits: `read()` adopts a roster keyed to that
34
+ * run's user key, and this run's candidate key is a throwaway nobody
35
+ * holds -- installing epoch[0] under it on a collection the earlier run
36
+ * never reached would key that collection to nothing, permanently, since
37
+ * the install is create-if-absent and every later ensure adopts it. So
38
+ * the stage is skipped whole and reported on `epochsSkipped`; the caller
39
+ * that recovers the roster's real key is the one installer. With both
40
+ * gates the tear heal is always clean: no roster means no epochs, and a
41
+ * fresh user key re-runs both.
42
+ * 5. Space-controller promotion, last -- every earlier stage ran under the
43
+ * bootstrap did:key the Space's stored controller authorizes.
44
+ *
45
+ * Idempotent end to end on the durable flow's convention; the did:webvh
46
+ * stage adopts a published log iff the ladder attributes it (a naive re-run
47
+ * would mint a different SCID, so adoption IS the torn-signup convergence).
48
+ */
49
+ import { type RecipientPublicKey } from '@interop/was-client/edv';
50
+ import type { WasClient } from '@interop/was-client';
51
+ import type { EncryptionDescriptorStore } from '@interop/was-client/edv';
52
+ import type { WebvhIdStore } from '../webvh/didWebvh.js';
53
+ import type { UnlockKeyAgreementPublication } from '../unlock/standingWebvh.js';
54
+ import { type UserKey } from '../keys/index.js';
55
+ import type { ResourceLogPinStore } from '../resourceLog/index.js';
56
+ import { type AccountGenesisResult } from '../genesis/accountGenesis.js';
57
+ /**
58
+ * The key set a credential-anchored signup mints locally before anything
59
+ * touches the network: the data Space id and the account's user key -- nothing else.
60
+ * No client seed and no client update-key seeds exist (that is the point);
61
+ * the ladder seed is minted by the unlock layer beside the record that
62
+ * carries it, and every other key derives from it.
63
+ *
64
+ * @returns {Promise<{ spaceId: string, userKey: Required<UserKey> }>}
65
+ */
66
+ export declare function mintCredentialAnchoredAccountKeySet(): Promise<{
67
+ spaceId: string;
68
+ userKey: Required<UserKey>;
69
+ }>;
70
+ /**
71
+ * Runs the credential-anchored account-genesis ceremony (see the module doc
72
+ * for the stage order and its whys). The caller has already durably written the
73
+ * unlock record carrying the ladder seed -- the transposed
74
+ * persist-before-publish rule: rung 0 must never publish before the seed
75
+ * that derives it is recoverable.
76
+ *
77
+ * @param options {object}
78
+ * @param options.was {WasClient} signing as the ladder VM's bare did:key
79
+ * (the bootstrap controller; build it over `ladderVmAgent`)
80
+ * @param options.wasServerUrl {string}
81
+ * @param options.spaceId {string}
82
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed,
83
+ * already sealed into the durably written unlock record
84
+ * @param options.keyAgreement {UnlockKeyAgreementPublication} the
85
+ * credential's key-agreement publication (commitment or verbatim), folded
86
+ * into the genesis document
87
+ * @param options.standingRecipient {RecipientPublicKey} the credential's
88
+ * standing key-agreement key as a roster recipient (`id` its roster kid)
89
+ * @param options.userKey {UserKey} the account's user key, epoch[0] of the
90
+ * roster and recipient zero of every encrypted collection
91
+ * @param options.idStore {WebvhIdStore} the account's `id` collection
92
+ * store, signing as the same bootstrap did:key
93
+ * @param options.rosterStoreFor {Function} `({ did }) =>
94
+ * EncryptionDescriptorStore` -- the user-key roster's store once the DID is
95
+ * known, with a LADDER-signed `ResourceLogSigner` (the first-entry shape)
96
+ * @param [options.expectedDid] {string} the account DID, when the caller
97
+ * holds a pointer that already names one (a heal re-run); a fresh signup
98
+ * and a fresh-terminal heal legitimately hold none
99
+ * @param [options.accountLogPinStore] {ResourceLogPinStore} the chain-head
100
+ * pins the genesis read and create ride (a transient signup passes the
101
+ * visit's in-memory store)
102
+ * @param [options.onDidPublished] {Function} `({ did }) => Promise<void>`
103
+ * @param [options.promoteController] {boolean} default `true`; an app whose
104
+ * account pointer must durably name the DID first (freewallet's record
105
+ * re-bind) passes `false` and promotes after that write
106
+ * @returns {Promise<AccountGenesisResult>}
107
+ */
108
+ export declare function ensureCredentialAnchoredAccountGenesis({ was, wasServerUrl, spaceId, ladderSeed, keyAgreement, standingRecipient, userKey, idStore, rosterStoreFor, expectedDid, accountLogPinStore, onDidPublished, promoteController }: {
109
+ was: WasClient;
110
+ wasServerUrl: string;
111
+ spaceId: string;
112
+ ladderSeed: Uint8Array;
113
+ keyAgreement: UnlockKeyAgreementPublication;
114
+ standingRecipient: RecipientPublicKey;
115
+ userKey: UserKey;
116
+ idStore: WebvhIdStore;
117
+ rosterStoreFor: (options: {
118
+ did: string;
119
+ }) => EncryptionDescriptorStore;
120
+ expectedDid?: string;
121
+ accountLogPinStore?: ResourceLogPinStore;
122
+ onDidPublished?: (published: {
123
+ did: string;
124
+ }) => Promise<void>;
125
+ promoteController?: boolean;
126
+ }): Promise<AccountGenesisResult>;
127
+ //# sourceMappingURL=credentialAnchoredGenesis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentialAnchoredGenesis.d.ts","sourceRoot":"","sources":["../../src/clientAnnex/credentialAnchoredGenesis.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC1E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAIxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAA;AAC/E,OAAO,EAGL,KAAK,OAAO,EAEb,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,8BAA8B,CAAA;AAErC;;;;;;;;GAQG;AACH,wBAAsB,mCAAmC,IAAI,OAAO,CAAC;IACnE,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAC3B,CAAC,CAED;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,sCAAsC,CAAC,EAC3D,GAAG,EACH,YAAY,EACZ,OAAO,EACP,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,OAAO,EACP,OAAO,EACP,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,iBAAwB,EACzB,EAAE;IACD,GAAG,EAAE,SAAS,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,UAAU,CAAA;IACtB,YAAY,EAAE,6BAA6B,CAAA;IAC3C,iBAAiB,EAAE,kBAAkB,CAAA;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,YAAY,CAAA;IACrB,cAAc,EAAE,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,yBAAyB,CAAA;IACvE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,mBAAmB,CAAA;IACxC,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA0FhC"}
@@ -0,0 +1,195 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The account-genesis ceremony's CREDENTIAL-ANCHORED variant: such a
6
+ * signup mints no durable client, so the ceremony is anchored on the unlock
7
+ * credential's ladder alone. The stage order mirrors `ensureAccountGenesis`
8
+ * with the durable-client members swapped for their ladder analogs:
9
+ *
10
+ * 1. Space provisioning under the ladder VM's bare did:key -- the bootstrap
11
+ * controller (wallet-core decision 0004, freewallet decision 0002's
12
+ * resolution of the orphan-Space tear): re-derivable from the unlock
13
+ * record's ladder seed, so a tab death here strands nothing a later
14
+ * login cannot finish or unwind.
15
+ * 2. The ladder-anchored did:webvh genesis
16
+ * (`ensureLadderAnchoredDidWebvh`): the entry signed by ladder rung 0, `updateKeys` = [rung 0], `nextKeyHashes`
17
+ * = [hash(rung 0), hash(rung 1)], the ladder VM and the credential's
18
+ * `keyAgreement` posture folded in, `portable` unchanged. There is no KMS
19
+ * stage: the keystore is DEFERRED to the first durable enrollment (a
20
+ * ladder-anchored account has no consumer for the convenience VM, and a
21
+ * keystore under an evaporating identity would orphan).
22
+ * 3. The user-key roster genesis, wrapped to the CREDENTIAL's standing
23
+ * key-agreement key -- the only recipient a ladder-anchored account has
24
+ * -- with the entry proof signed by the ladder VM (the ceremony-tail
25
+ * license's first-entry shape). The account is credential-recoverable
26
+ * from the moment this lands.
27
+ * 4. Epoch[0] on every encrypted roster collection -- gated twice, unlike
28
+ * the durable flow. The roster stage must have landed, AND the roster's
29
+ * current epoch must BE the `userKey` this run was handed: the user key
30
+ * here exists only in this tab's memory, so installing collection epochs
31
+ * under a key the roster does not deliver would strand the collections
32
+ * on a key that dies with the tab. The second gate is what a re-run over
33
+ * an earlier run's roster hits: `read()` adopts a roster keyed to that
34
+ * run's user key, and this run's candidate key is a throwaway nobody
35
+ * holds -- installing epoch[0] under it on a collection the earlier run
36
+ * never reached would key that collection to nothing, permanently, since
37
+ * the install is create-if-absent and every later ensure adopts it. So
38
+ * the stage is skipped whole and reported on `epochsSkipped`; the caller
39
+ * that recovers the roster's real key is the one installer. With both
40
+ * gates the tear heal is always clean: no roster means no epochs, and a
41
+ * fresh user key re-runs both.
42
+ * 5. Space-controller promotion, last -- every earlier stage ran under the
43
+ * bootstrap did:key the Space's stored controller authorizes.
44
+ *
45
+ * Idempotent end to end on the durable flow's convention; the did:webvh
46
+ * stage adopts a published log iff the ladder attributes it (a naive re-run
47
+ * would mint a different SCID, so adoption IS the torn-signup convergence).
48
+ */
49
+ import { initRecipients } from '@interop/was-client/edv';
50
+ import { provisionWalletSpace } from '../space/index.js';
51
+ import { ladderVmAgent } from './zcap.js';
52
+ import { ensureLadderAnchoredDidWebvh } from './ladderAnchored.js';
53
+ import { ensureWalletSpaceEpochs, mintUserKey } from '../keys/index.js';
54
+ import { AccountGenesisSpaceError, ensurePromotedSpaceController, mintSpaceId } from '../genesis/accountGenesis.js';
55
+ /**
56
+ * The key set a credential-anchored signup mints locally before anything
57
+ * touches the network: the data Space id and the account's user key -- nothing else.
58
+ * No client seed and no client update-key seeds exist (that is the point);
59
+ * the ladder seed is minted by the unlock layer beside the record that
60
+ * carries it, and every other key derives from it.
61
+ *
62
+ * @returns {Promise<{ spaceId: string, userKey: Required<UserKey> }>}
63
+ */
64
+ export async function mintCredentialAnchoredAccountKeySet() {
65
+ return { spaceId: mintSpaceId(), userKey: await mintUserKey() };
66
+ }
67
+ /**
68
+ * Runs the credential-anchored account-genesis ceremony (see the module doc
69
+ * for the stage order and its whys). The caller has already durably written the
70
+ * unlock record carrying the ladder seed -- the transposed
71
+ * persist-before-publish rule: rung 0 must never publish before the seed
72
+ * that derives it is recoverable.
73
+ *
74
+ * @param options {object}
75
+ * @param options.was {WasClient} signing as the ladder VM's bare did:key
76
+ * (the bootstrap controller; build it over `ladderVmAgent`)
77
+ * @param options.wasServerUrl {string}
78
+ * @param options.spaceId {string}
79
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed,
80
+ * already sealed into the durably written unlock record
81
+ * @param options.keyAgreement {UnlockKeyAgreementPublication} the
82
+ * credential's key-agreement publication (commitment or verbatim), folded
83
+ * into the genesis document
84
+ * @param options.standingRecipient {RecipientPublicKey} the credential's
85
+ * standing key-agreement key as a roster recipient (`id` its roster kid)
86
+ * @param options.userKey {UserKey} the account's user key, epoch[0] of the
87
+ * roster and recipient zero of every encrypted collection
88
+ * @param options.idStore {WebvhIdStore} the account's `id` collection
89
+ * store, signing as the same bootstrap did:key
90
+ * @param options.rosterStoreFor {Function} `({ did }) =>
91
+ * EncryptionDescriptorStore` -- the user-key roster's store once the DID is
92
+ * known, with a LADDER-signed `ResourceLogSigner` (the first-entry shape)
93
+ * @param [options.expectedDid] {string} the account DID, when the caller
94
+ * holds a pointer that already names one (a heal re-run); a fresh signup
95
+ * and a fresh-terminal heal legitimately hold none
96
+ * @param [options.accountLogPinStore] {ResourceLogPinStore} the chain-head
97
+ * pins the genesis read and create ride (a transient signup passes the
98
+ * visit's in-memory store)
99
+ * @param [options.onDidPublished] {Function} `({ did }) => Promise<void>`
100
+ * @param [options.promoteController] {boolean} default `true`; an app whose
101
+ * account pointer must durably name the DID first (freewallet's record
102
+ * re-bind) passes `false` and promotes after that write
103
+ * @returns {Promise<AccountGenesisResult>}
104
+ */
105
+ export async function ensureCredentialAnchoredAccountGenesis({ was, wasServerUrl, spaceId, ladderSeed, keyAgreement, standingRecipient, userKey, idStore, rosterStoreFor, expectedDid, accountLogPinStore, onDidPublished, promoteController = true }) {
106
+ const failed = [];
107
+ const bootstrap = await ladderVmAgent({ ladderSeed });
108
+ // 1. The Space and its collection roster, create-if-absent under the
109
+ // ladder VM's bare did:key. The typed refusal, exactly as on the durable
110
+ // flow: nothing downstream can proceed without a Space.
111
+ try {
112
+ await provisionWalletSpace({ was, spaceId, controllerDid: bootstrap.id });
113
+ }
114
+ catch (err) {
115
+ throw new AccountGenesisSpaceError({ spaceId, cause: err });
116
+ }
117
+ // 2. The ladder-anchored did:webvh genesis -- probe, adopt
118
+ // (ladder-attributed), or create-and-publish. Fatal on failure, like the durable stage.
119
+ const { did } = await ensureLadderAnchoredDidWebvh({
120
+ idStore,
121
+ wasServerUrl,
122
+ spaceId,
123
+ ladderSeed,
124
+ keyAgreement,
125
+ ...(expectedDid !== undefined ? { expectedDid } : {}),
126
+ ...(accountLogPinStore ? { pinStore: accountLogPinStore } : {})
127
+ });
128
+ await onDidPublished?.({ did });
129
+ // 3. The roster genesis: epoch[0] IS the user key, wrapped once, to the
130
+ // credential's standing key-agreement key. The store's ladder-signed
131
+ // genesis append is the ceremony-tail license's first-entry shape.
132
+ let rosterDescriptor;
133
+ try {
134
+ const store = rosterStoreFor({ did });
135
+ const current = await store.read();
136
+ rosterDescriptor =
137
+ current !== null
138
+ ? current.descriptor
139
+ : await initRecipients({
140
+ store,
141
+ recipients: [standingRecipient],
142
+ epoch: { epochId: userKey.id, secret: userKey.secret }
143
+ });
144
+ }
145
+ catch (err) {
146
+ failed.push({ stage: 'roster', error: err });
147
+ }
148
+ // 4. Epoch[0] on every encrypted roster collection, only behind a landed
149
+ // roster whose current epoch IS this run's user key (see the module doc:
150
+ // the user key is memory-only here, and an adopted roster keyed to another
151
+ // run's key would have the collections installed under a throwaway).
152
+ let epochs;
153
+ let epochsSkipped;
154
+ if (rosterDescriptor) {
155
+ if (rosterDescriptor.currentEpoch === userKey.id) {
156
+ try {
157
+ epochs = await ensureWalletSpaceEpochs({ was, spaceId, userKey });
158
+ }
159
+ catch (err) {
160
+ failed.push({ stage: 'epochs', error: err });
161
+ }
162
+ }
163
+ else {
164
+ epochsSkipped =
165
+ rosterDescriptor.currentEpoch !== undefined
166
+ ? { rosterEpochId: rosterDescriptor.currentEpoch }
167
+ : {};
168
+ }
169
+ }
170
+ // 5. The controller promotion, last. The bootstrap client IS the bare
171
+ // did:key client, so it serves the heal branch too.
172
+ let promotion;
173
+ if (promoteController) {
174
+ try {
175
+ promotion = await ensurePromotedSpaceController({
176
+ was,
177
+ wasAsClient: was,
178
+ spaceId,
179
+ did
180
+ });
181
+ }
182
+ catch (err) {
183
+ failed.push({ stage: 'promotion', error: err });
184
+ }
185
+ }
186
+ return {
187
+ did,
188
+ ...(rosterDescriptor ? { rosterDescriptor } : {}),
189
+ ...(epochs ? { epochs } : {}),
190
+ ...(epochsSkipped ? { epochsSkipped } : {}),
191
+ ...(promotion ? { promotion } : {}),
192
+ failed
193
+ };
194
+ }
195
+ //# sourceMappingURL=credentialAnchoredGenesis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentialAnchoredGenesis.js","sourceRoot":"","sources":["../../src/clientAnnex/credentialAnchoredGenesis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * The forget ceremony: a remembered browser's durable client removes ITSELF
6
+ * from the account, through the standing unlock credential's bridge, before
7
+ * the app wipes its local state. Self-enrollment in reverse, run with what a
8
+ * live durable session already holds -- the credential's ladder seed and its
9
+ * delegated `did.jsonl` bridge -- and refused for the account's last enrolled
10
+ * durable client ({@link LastDurableClientForgetError}), whose forget is the
11
+ * ladder-anchored transition, a separate ceremony.
12
+ *
13
+ * The stage order INVERTS the revocation cascade's document-edit-first rule,
14
+ * and the inversion is forced twice over: once the removal entry lands, the
15
+ * forgetting client's key is out of `assertionMethod` at the post-edit head,
16
+ * so it can sign no roster append (the entry-proof rule), and its WAS
17
+ * invocations stop verifying (the current-key-set rule), so the collection
18
+ * fan-out cannot run either -- while a ladder-signed append is licensed only
19
+ * at a posture-changing document version, which a not-last-client removal is
20
+ * not. So:
21
+ *
22
+ * 1. **The roster rotation**, PRE-edit, signed by the still-enrolled
23
+ * forgetting client: the user key rotates off this client's wrap, retired
24
+ * by its roster kid explicitly (document convergence cannot drop a client
25
+ * the document still lists). The fresh key is read back through the
26
+ * CREDENTIAL's standing wrap -- the forgetting client just retired its
27
+ * own -- which the rotation fan-out keeps escrowed into every epoch.
28
+ * 2. **The collection fan-out**, still under this client's invocation
29
+ * authority: every encrypted collection re-epochs onto the fresh key, so
30
+ * writes stop landing under epochs a later holder of this browser's
31
+ * residue could open.
32
+ * 3. **The removal entry** ({@link forgetWebvhClient}): one atomic
33
+ * ladder-signed entry through the bridge takes the client's whole document
34
+ * footprint out. The app's local wipe runs after this ceremony returns, so
35
+ * a tear anywhere before the entry reads as "not forgotten" and a re-click
36
+ * resumes.
37
+ *
38
+ * Torn-state map: a run torn after stage 1 leaves the account rotated off a
39
+ * client the document still lists -- writes already land under the fresh key,
40
+ * the client-key record still stands, and the re-run's rotation no-ops (the
41
+ * wrap is already gone) while its later stages finish. Torn after stage 3
42
+ * (the removal published, the app's wipe not run) is the
43
+ * finish-the-wipe state the app's next login maps. What no re-run needs:
44
+ * the roster log's head stays anchored BEFORE the removal entry -- no signer
45
+ * this ceremony holds may append after it -- which is exactly the unsealed
46
+ * state any other enrolled client's login sweep detects and seals.
47
+ *
48
+ * There is deliberately no recovery-delegation or generation-delegation
49
+ * re-mint stage: the forgetting client cannot re-mint with a key that dies at
50
+ * stage 3 (the replacement would rot moments later), so a delegation this
51
+ * client had signed is left to the standing self-heals (a durable login's
52
+ * bridge refresh and `ensureGenerationDelegationCurrent` on the
53
+ * account-document axis).
54
+ *
55
+ * The honest limitation is the cascade's, as everywhere: ciphertext this
56
+ * browser already fetched stays forensically recoverable from its storage,
57
+ * and old epochs stay open to keys it already held. The rotation stops future
58
+ * reads; the wipe removes the local copies.
59
+ */
60
+ import type { IKeyAgreementKey } from '@interop/data-integrity-core';
61
+ import type { CollectionEncryption } from '@interop/was-client';
62
+ import type { EncryptionDescriptorStore } from '@interop/was-client/edv';
63
+ import type { RevokedClientKeys } from '../webvh/revokeClient.js';
64
+ import { type CascadeCollections, type UserKey, type UserKeyCascadeResult } from '../keys/index.js';
65
+ import type { UnlockLogStore } from '../unlock/standingWebvh.js';
66
+ /**
67
+ * What a completed forget reports: whether the roster's wrap for the
68
+ * forgotten client was actually retired on this run (a re-run of a
69
+ * torn-after-rotation ceremony reports `false`), the per-collection fan-out
70
+ * result, the document as the removal entry left it, and -- when the account
71
+ * has a roster -- the rotated key with the roster descriptor it was read
72
+ * from.
73
+ */
74
+ export interface DurableClientForgetResult {
75
+ rotated: boolean;
76
+ collections: UserKeyCascadeResult;
77
+ did: string;
78
+ document: object;
79
+ userKey?: UserKey;
80
+ rosterDescriptor?: CollectionEncryption;
81
+ }
82
+ /**
83
+ * Forgets one enrolled durable client -- this browser's own -- from its
84
+ * account. See the module doc for the stage order (rotation and fan-out
85
+ * BEFORE the removal entry, the self-forget inversion) and the torn-state
86
+ * map. The caller runs the local wipe only after this resolves.
87
+ *
88
+ * @param options {object}
89
+ * @param options.logStore {UnlockLogStore} the credential's delegated
90
+ * `did.jsonl` bridge store; also serves the ceremony's public pre-edit
91
+ * read. The caller is expected to have verified the account log under its
92
+ * own chain-head pins in the same session (the ceremony re-reads through
93
+ * the seam and checks `expectedDid`, but carries no pin store itself)
94
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed
95
+ * @param options.forgottenClient {RevokedClientKeys} this client's public
96
+ * halves; an `updateKeyMultibase` the log does not authorize (stale, or the
97
+ * staged key) is re-derived from the log
98
+ * @param options.forgottenKeyAgreementKeyMultibase {string} this client's
99
+ * identity key-agreement key (the X25519 twin), naming its roster wrap
100
+ * @param [options.knownLatentHashes] {string[]} standing latent commitments
101
+ * the caller vouches for (the recovery registry's update-key hashes),
102
+ * excluded from the staged-hash attribution
103
+ * @param options.expectedDid {string} the account DID from the caller's
104
+ * stored account pointer
105
+ * @param options.rosterStore {EncryptionDescriptorStore} the
106
+ * `key-map/user-key.jsonl` roster store, signing as the forgetting client
107
+ * @param options.credentialKeyAgreementKey {IKeyAgreementKey} the standing
108
+ * credential's key-agreement key -- the recipient whose wrap survives the
109
+ * rotation, reading the fresh key back and unwrapping the generations for
110
+ * the fan-out
111
+ * @param [options.userKey] {UserKey} this client's cached user key
112
+ * @param [options.pinnedEpochId] {string} the locally pinned latest-seen
113
+ * roster epoch
114
+ * @param [options.onUserKeyAdopted] {Function} persists a rotated key:
115
+ * called with `{ userKey, latestEpochId, descriptor }` after the roster
116
+ * read and BEFORE the fan-out
117
+ * @param options.collections {CascadeCollections} the fan-out's work
118
+ * @returns {Promise<DurableClientForgetResult>}
119
+ */
120
+ export declare function forgetDurableClient({ logStore, ladderSeed, forgottenClient, forgottenKeyAgreementKeyMultibase, knownLatentHashes, expectedDid, rosterStore, credentialKeyAgreementKey, userKey, pinnedEpochId, onUserKeyAdopted, collections }: {
121
+ logStore: UnlockLogStore;
122
+ ladderSeed: Uint8Array;
123
+ forgottenClient: RevokedClientKeys;
124
+ forgottenKeyAgreementKeyMultibase: string;
125
+ knownLatentHashes?: string[];
126
+ expectedDid: string;
127
+ rosterStore: EncryptionDescriptorStore;
128
+ credentialKeyAgreementKey: IKeyAgreementKey;
129
+ userKey?: UserKey;
130
+ pinnedEpochId?: string | null;
131
+ onUserKeyAdopted?: (adopted: {
132
+ userKey: UserKey;
133
+ latestEpochId: string;
134
+ descriptor: CollectionEncryption;
135
+ }) => Promise<void>;
136
+ collections: CascadeCollections;
137
+ }): Promise<DurableClientForgetResult>;
138
+ //# sourceMappingURL=forget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forget.d.ts","sourceRoot":"","sources":["../../src/clientAnnex/forget.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAA;AAGxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,OAAO,EACZ,KAAK,oBAAoB,EAC1B,MAAM,kBAAkB,CAAA;AAKzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhE;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,oBAAoB,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,oBAAoB,CAAA;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,QAAQ,EACR,UAAU,EACV,eAAe,EACf,iCAAiC,EACjC,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,yBAAyB,EACzB,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,WAAW,EACZ,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,UAAU,EAAE,UAAU,CAAA;IACtB,eAAe,EAAE,iBAAiB,CAAA;IAClC,iCAAiC,EAAE,MAAM,CAAA;IACzC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,yBAAyB,CAAA;IACtC,yBAAyB,EAAE,gBAAgB,CAAA;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC3B,OAAO,EAAE,OAAO,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;QACrB,UAAU,EAAE,oBAAoB,CAAA;KACjC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnB,WAAW,EAAE,kBAAkB,CAAA;CAChC,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAoGrC"}
@@ -0,0 +1,133 @@
1
+ import { readPublishedLog, relationIds } from '../webvh/didWebvh.js';
2
+ import { cascadeCollectionsToUserKey, readUserKeyRoster, rosterRecipientKid, rotateUserKeyRoster } from '../keys/index.js';
3
+ import { forgetWebvhClient, LastDurableClientForgetError } from './ladderAnchored.js';
4
+ /**
5
+ * Forgets one enrolled durable client -- this browser's own -- from its
6
+ * account. See the module doc for the stage order (rotation and fan-out
7
+ * BEFORE the removal entry, the self-forget inversion) and the torn-state
8
+ * map. The caller runs the local wipe only after this resolves.
9
+ *
10
+ * @param options {object}
11
+ * @param options.logStore {UnlockLogStore} the credential's delegated
12
+ * `did.jsonl` bridge store; also serves the ceremony's public pre-edit
13
+ * read. The caller is expected to have verified the account log under its
14
+ * own chain-head pins in the same session (the ceremony re-reads through
15
+ * the seam and checks `expectedDid`, but carries no pin store itself)
16
+ * @param options.ladderSeed {Uint8Array} the credential's ladder seed
17
+ * @param options.forgottenClient {RevokedClientKeys} this client's public
18
+ * halves; an `updateKeyMultibase` the log does not authorize (stale, or the
19
+ * staged key) is re-derived from the log
20
+ * @param options.forgottenKeyAgreementKeyMultibase {string} this client's
21
+ * identity key-agreement key (the X25519 twin), naming its roster wrap
22
+ * @param [options.knownLatentHashes] {string[]} standing latent commitments
23
+ * the caller vouches for (the recovery registry's update-key hashes),
24
+ * excluded from the staged-hash attribution
25
+ * @param options.expectedDid {string} the account DID from the caller's
26
+ * stored account pointer
27
+ * @param options.rosterStore {EncryptionDescriptorStore} the
28
+ * `key-map/user-key.jsonl` roster store, signing as the forgetting client
29
+ * @param options.credentialKeyAgreementKey {IKeyAgreementKey} the standing
30
+ * credential's key-agreement key -- the recipient whose wrap survives the
31
+ * rotation, reading the fresh key back and unwrapping the generations for
32
+ * the fan-out
33
+ * @param [options.userKey] {UserKey} this client's cached user key
34
+ * @param [options.pinnedEpochId] {string} the locally pinned latest-seen
35
+ * roster epoch
36
+ * @param [options.onUserKeyAdopted] {Function} persists a rotated key:
37
+ * called with `{ userKey, latestEpochId, descriptor }` after the roster
38
+ * read and BEFORE the fan-out
39
+ * @param options.collections {CascadeCollections} the fan-out's work
40
+ * @returns {Promise<DurableClientForgetResult>}
41
+ */
42
+ export async function forgetDurableClient({ logStore, ladderSeed, forgottenClient, forgottenKeyAgreementKeyMultibase, knownLatentHashes, expectedDid, rosterStore, credentialKeyAgreementKey, userKey, pinnedEpochId, onUserKeyAdopted, collections }) {
43
+ // The pre-edit read, doing double duty: the last-client refusal must fire
44
+ // BEFORE the rotation (or a refused forget would already have retired this
45
+ // client's wrap), and the rotation's recipient resolver needs the pre-edit
46
+ // document (which still keys every other recipient).
47
+ const published = await readPublishedLog({
48
+ // readPublishedLog only calls getIdResourceRaw, so the narrow seam is
49
+ // safe.
50
+ idStore: logStore,
51
+ expectedDid
52
+ });
53
+ if (!published) {
54
+ throw new Error('did:webvh: did.jsonl is missing; nothing to forget from.');
55
+ }
56
+ const signingVmId = `${published.did}#${forgottenClient.signingKeyMultibase}`;
57
+ const invocationIds = relationIds(published.doc.capabilityInvocation);
58
+ if (invocationIds.includes(signingVmId) &&
59
+ invocationIds.every(id => id === signingVmId)) {
60
+ throw new LastDurableClientForgetError();
61
+ }
62
+ // Stages 1 and 2: the roster rotation off this client's wrap and the
63
+ // collection fan-out, both under this client's still-standing authority.
64
+ let rotated = false;
65
+ let read;
66
+ let cascade = { outcomes: {}, failed: [] };
67
+ const current = await rosterStore.read();
68
+ if (current !== null) {
69
+ const forgottenKid = rosterRecipientKid({
70
+ signingKeyMultibase: forgottenClient.signingKeyMultibase,
71
+ keyAgreementKeyMultibase: forgottenKeyAgreementKeyMultibase
72
+ });
73
+ let descriptor = current.descriptor;
74
+ const currentEpoch = (descriptor.epochs ?? []).find(epoch => epoch.id === descriptor.currentEpoch);
75
+ const wrapped = currentEpoch?.recipients.some(entry => entry.header.kid === forgottenKid);
76
+ if (wrapped) {
77
+ descriptor = await rotateUserKeyRoster({
78
+ store: rosterStore,
79
+ document: published.doc,
80
+ retireRecipientId: forgottenKid
81
+ });
82
+ rotated = true;
83
+ }
84
+ // The fresh key comes back through the credential's standing wrap -- this
85
+ // client's own is gone from the current epoch -- with the continuity and
86
+ // possession checks still running on the threaded descriptor.
87
+ const adopted = await readUserKeyRoster({
88
+ store: rosterStore,
89
+ descriptor,
90
+ ...(userKey ? { userKey } : {}),
91
+ clientKeyAgreementKey: credentialKeyAgreementKey,
92
+ pinnedEpochId
93
+ });
94
+ if (adopted.rotated) {
95
+ await onUserKeyAdopted?.({
96
+ userKey: adopted.userKey,
97
+ latestEpochId: adopted.latestEpochId,
98
+ descriptor: adopted.descriptor
99
+ });
100
+ }
101
+ read = { userKey: adopted.userKey, descriptor: adopted.descriptor };
102
+ cascade = await cascadeCollectionsToUserKey({
103
+ collectionIds: typeof collections.collectionIds === 'function'
104
+ ? await collections.collectionIds()
105
+ : collections.collectionIds,
106
+ storeFor: collections.storeFor,
107
+ ...(collections.isEncrypted
108
+ ? { isEncrypted: collections.isEncrypted }
109
+ : {}),
110
+ rosterDescriptor: adopted.descriptor,
111
+ clientKeyAgreementKey: credentialKeyAgreementKey,
112
+ userKey: adopted.userKey
113
+ });
114
+ }
115
+ // Stage 3: the atomic ladder-signed removal entry, through the bridge.
116
+ const removed = await forgetWebvhClient({
117
+ store: logStore,
118
+ ladderSeed,
119
+ forgottenClient,
120
+ ...(knownLatentHashes ? { knownLatentHashes } : {}),
121
+ expectedDid
122
+ });
123
+ return {
124
+ rotated,
125
+ collections: cascade,
126
+ did: removed.did,
127
+ document: removed.doc,
128
+ ...(read
129
+ ? { userKey: read.userKey, rosterDescriptor: read.descriptor }
130
+ : {})
131
+ };
132
+ }
133
+ //# sourceMappingURL=forget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forget.js","sourceRoot":"","sources":["../../src/clientAnnex/forget.ts"],"names":[],"mappings":"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"}