@interop/wallet-core 0.62.0 → 0.66.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 (321) hide show
  1. package/README.md +41 -16
  2. package/dist/clientAnnex/credentialAnchoredGenesis.d.ts +46 -26
  3. package/dist/clientAnnex/credentialAnchoredGenesis.d.ts.map +1 -1
  4. package/dist/clientAnnex/credentialAnchoredGenesis.js +91 -39
  5. package/dist/clientAnnex/credentialAnchoredGenesis.js.map +1 -1
  6. package/dist/clientAnnex/establish.d.ts +119 -35
  7. package/dist/clientAnnex/establish.d.ts.map +1 -1
  8. package/dist/clientAnnex/establish.js +227 -160
  9. package/dist/clientAnnex/establish.js.map +1 -1
  10. package/dist/clientAnnex/forget.d.ts +18 -8
  11. package/dist/clientAnnex/forget.d.ts.map +1 -1
  12. package/dist/clientAnnex/forget.js +37 -64
  13. package/dist/clientAnnex/forget.js.map +1 -1
  14. package/dist/clientAnnex/forgetLast.d.ts +85 -38
  15. package/dist/clientAnnex/forgetLast.d.ts.map +1 -1
  16. package/dist/clientAnnex/forgetLast.js +155 -98
  17. package/dist/clientAnnex/forgetLast.js.map +1 -1
  18. package/dist/clientAnnex/gc.d.ts +3 -2
  19. package/dist/clientAnnex/gc.d.ts.map +1 -1
  20. package/dist/clientAnnex/gc.js +16 -7
  21. package/dist/clientAnnex/gc.js.map +1 -1
  22. package/dist/clientAnnex/heal.d.ts +65 -14
  23. package/dist/clientAnnex/heal.d.ts.map +1 -1
  24. package/dist/clientAnnex/heal.js +397 -298
  25. package/dist/clientAnnex/heal.js.map +1 -1
  26. package/dist/clientAnnex/index.d.ts +23 -7
  27. package/dist/clientAnnex/index.d.ts.map +1 -1
  28. package/dist/clientAnnex/index.js +26 -7
  29. package/dist/clientAnnex/index.js.map +1 -1
  30. package/dist/clientAnnex/ladder.d.ts +58 -0
  31. package/dist/clientAnnex/ladder.d.ts.map +1 -1
  32. package/dist/clientAnnex/ladder.js +249 -41
  33. package/dist/clientAnnex/ladder.js.map +1 -1
  34. package/dist/clientAnnex/ladderAnchored.d.ts +148 -22
  35. package/dist/clientAnnex/ladderAnchored.d.ts.map +1 -1
  36. package/dist/clientAnnex/ladderAnchored.js +391 -346
  37. package/dist/clientAnnex/ladderAnchored.js.map +1 -1
  38. package/dist/clientAnnex/log.d.ts +237 -53
  39. package/dist/clientAnnex/log.d.ts.map +1 -1
  40. package/dist/clientAnnex/log.js +533 -198
  41. package/dist/clientAnnex/log.js.map +1 -1
  42. package/dist/clientAnnex/mend.d.ts +12 -6
  43. package/dist/clientAnnex/mend.d.ts.map +1 -1
  44. package/dist/clientAnnex/mend.js +44 -72
  45. package/dist/clientAnnex/mend.js.map +1 -1
  46. package/dist/clientAnnex/recoveryLadderAnchored.d.ts +6 -4
  47. package/dist/clientAnnex/recoveryLadderAnchored.d.ts.map +1 -1
  48. package/dist/clientAnnex/recoveryLadderAnchored.js +56 -35
  49. package/dist/clientAnnex/recoveryLadderAnchored.js.map +1 -1
  50. package/dist/clientAnnex/spaceCapability.d.ts +123 -0
  51. package/dist/clientAnnex/spaceCapability.d.ts.map +1 -0
  52. package/dist/clientAnnex/spaceCapability.js +152 -0
  53. package/dist/clientAnnex/spaceCapability.js.map +1 -0
  54. package/dist/clientAnnex/stages.d.ts +63 -0
  55. package/dist/clientAnnex/stages.d.ts.map +1 -0
  56. package/dist/clientAnnex/stages.js +64 -0
  57. package/dist/clientAnnex/stages.js.map +1 -0
  58. package/dist/clientAnnex/zcap.d.ts +1 -1
  59. package/dist/clientAnnex/zcap.d.ts.map +1 -1
  60. package/dist/clientAnnex/zcap.js +42 -35
  61. package/dist/clientAnnex/zcap.js.map +1 -1
  62. package/dist/clients/policy.d.ts +15 -1
  63. package/dist/clients/policy.d.ts.map +1 -1
  64. package/dist/clients/policy.js +12 -6
  65. package/dist/clients/policy.js.map +1 -1
  66. package/dist/clients/revocation.d.ts +18 -10
  67. package/dist/clients/revocation.d.ts.map +1 -1
  68. package/dist/clients/revocation.js +13 -5
  69. package/dist/clients/revocation.js.map +1 -1
  70. package/dist/clients/rosterPolicy.d.ts +10 -2
  71. package/dist/clients/rosterPolicy.d.ts.map +1 -1
  72. package/dist/clients/rosterPolicy.js +41 -24
  73. package/dist/clients/rosterPolicy.js.map +1 -1
  74. package/dist/descriptors/acquire.d.ts.map +1 -1
  75. package/dist/descriptors/acquire.js +6 -23
  76. package/dist/descriptors/acquire.js.map +1 -1
  77. package/dist/descriptors/cipher.d.ts.map +1 -1
  78. package/dist/descriptors/cipher.js +5 -0
  79. package/dist/descriptors/cipher.js.map +1 -1
  80. package/dist/descriptors/errors.d.ts +43 -0
  81. package/dist/descriptors/errors.d.ts.map +1 -0
  82. package/dist/descriptors/errors.js +45 -0
  83. package/dist/descriptors/errors.js.map +1 -0
  84. package/dist/descriptors/index.d.ts +5 -0
  85. package/dist/descriptors/index.d.ts.map +1 -1
  86. package/dist/descriptors/index.js +5 -0
  87. package/dist/descriptors/index.js.map +1 -1
  88. package/dist/enrollment/enrollment.d.ts +37 -10
  89. package/dist/enrollment/enrollment.d.ts.map +1 -1
  90. package/dist/enrollment/enrollment.js +52 -15
  91. package/dist/enrollment/enrollment.js.map +1 -1
  92. package/dist/genesis/accountGenesis.d.ts +42 -11
  93. package/dist/genesis/accountGenesis.d.ts.map +1 -1
  94. package/dist/genesis/accountGenesis.js +80 -22
  95. package/dist/genesis/accountGenesis.js.map +1 -1
  96. package/dist/genesis/index.d.ts +3 -1
  97. package/dist/genesis/index.d.ts.map +1 -1
  98. package/dist/genesis/index.js +3 -1
  99. package/dist/genesis/index.js.map +1 -1
  100. package/dist/identity/agents.d.ts +17 -1
  101. package/dist/identity/agents.d.ts.map +1 -1
  102. package/dist/identity/agents.js +23 -7
  103. package/dist/identity/agents.js.map +1 -1
  104. package/dist/identity/index.d.ts +3 -1
  105. package/dist/identity/index.d.ts.map +1 -1
  106. package/dist/identity/index.js +3 -1
  107. package/dist/identity/index.js.map +1 -1
  108. package/dist/index.d.ts +6 -3
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +6 -3
  111. package/dist/index.js.map +1 -1
  112. package/dist/keyring/index.d.ts +2 -1
  113. package/dist/keyring/index.d.ts.map +1 -1
  114. package/dist/keyring/index.js +2 -1
  115. package/dist/keyring/index.js.map +1 -1
  116. package/dist/keyring/record.d.ts.map +1 -1
  117. package/dist/keyring/record.js +3 -6
  118. package/dist/keyring/record.js.map +1 -1
  119. package/dist/keyring/unlockSpace.d.ts +14 -5
  120. package/dist/keyring/unlockSpace.d.ts.map +1 -1
  121. package/dist/keyring/unlockSpace.js +31 -36
  122. package/dist/keyring/unlockSpace.js.map +1 -1
  123. package/dist/keys/index.d.ts +22 -8
  124. package/dist/keys/index.d.ts.map +1 -1
  125. package/dist/keys/index.js +20 -6
  126. package/dist/keys/index.js.map +1 -1
  127. package/dist/keys/rosterLogStore.d.ts +15 -12
  128. package/dist/keys/rosterLogStore.d.ts.map +1 -1
  129. package/dist/keys/rosterLogStore.js +21 -16
  130. package/dist/keys/rosterLogStore.js.map +1 -1
  131. package/dist/keys/rosterStore.d.ts +3 -6
  132. package/dist/keys/rosterStore.d.ts.map +1 -1
  133. package/dist/keys/rosterStore.js +10 -9
  134. package/dist/keys/rosterStore.js.map +1 -1
  135. package/dist/keys/spaceEpochs.d.ts.map +1 -1
  136. package/dist/keys/spaceEpochs.js +2 -3
  137. package/dist/keys/spaceEpochs.js.map +1 -1
  138. package/dist/keys/userKeyCascade.d.ts +8 -5
  139. package/dist/keys/userKeyCascade.d.ts.map +1 -1
  140. package/dist/keys/userKeyCascade.js +7 -6
  141. package/dist/keys/userKeyCascade.js.map +1 -1
  142. package/dist/keys/userKeyRoster.d.ts +95 -8
  143. package/dist/keys/userKeyRoster.d.ts.map +1 -1
  144. package/dist/keys/userKeyRoster.js +278 -35
  145. package/dist/keys/userKeyRoster.js.map +1 -1
  146. package/dist/keys/userKeyRosterCascade.d.ts +117 -16
  147. package/dist/keys/userKeyRosterCascade.d.ts.map +1 -1
  148. package/dist/keys/userKeyRosterCascade.js +184 -43
  149. package/dist/keys/userKeyRosterCascade.js.map +1 -1
  150. package/dist/keys/wasLabelsStore.d.ts +9 -2
  151. package/dist/keys/wasLabelsStore.d.ts.map +1 -1
  152. package/dist/keys/wasLabelsStore.js +14 -6
  153. package/dist/keys/wasLabelsStore.js.map +1 -1
  154. package/dist/log.d.ts +7 -2
  155. package/dist/log.d.ts.map +1 -1
  156. package/dist/log.js +6 -1
  157. package/dist/log.js.map +1 -1
  158. package/dist/recovery/index.d.ts +13 -9
  159. package/dist/recovery/index.d.ts.map +1 -1
  160. package/dist/recovery/index.js +12 -8
  161. package/dist/recovery/index.js.map +1 -1
  162. package/dist/recovery/recoveryCode.d.ts +27 -7
  163. package/dist/recovery/recoveryCode.d.ts.map +1 -1
  164. package/dist/recovery/recoveryCode.js +18 -6
  165. package/dist/recovery/recoveryCode.js.map +1 -1
  166. package/dist/recovery/recoveryDelegation.d.ts +23 -0
  167. package/dist/recovery/recoveryDelegation.d.ts.map +1 -1
  168. package/dist/recovery/recoveryDelegation.js +66 -46
  169. package/dist/recovery/recoveryDelegation.js.map +1 -1
  170. package/dist/recovery/recoveryWebvh.d.ts +75 -63
  171. package/dist/recovery/recoveryWebvh.d.ts.map +1 -1
  172. package/dist/recovery/recoveryWebvh.js +127 -116
  173. package/dist/recovery/recoveryWebvh.js.map +1 -1
  174. package/dist/request/appKey.d.ts +35 -1
  175. package/dist/request/appKey.d.ts.map +1 -1
  176. package/dist/request/appKey.js +29 -10
  177. package/dist/request/appKey.js.map +1 -1
  178. package/dist/request/classify.d.ts +32 -8
  179. package/dist/request/classify.d.ts.map +1 -1
  180. package/dist/request/classify.js +39 -14
  181. package/dist/request/classify.js.map +1 -1
  182. package/dist/request/ephemeralExchange.d.ts +1 -6
  183. package/dist/request/ephemeralExchange.d.ts.map +1 -1
  184. package/dist/request/ephemeralExchange.js.map +1 -1
  185. package/dist/request/onboarding.d.ts.map +1 -1
  186. package/dist/request/onboarding.js +2 -2
  187. package/dist/request/onboarding.js.map +1 -1
  188. package/dist/request/parse.d.ts.map +1 -1
  189. package/dist/request/parse.js +2 -3
  190. package/dist/request/parse.js.map +1 -1
  191. package/dist/resourceLog/controller.d.ts +34 -12
  192. package/dist/resourceLog/controller.d.ts.map +1 -1
  193. package/dist/resourceLog/controller.js +79 -86
  194. package/dist/resourceLog/controller.js.map +1 -1
  195. package/dist/resourceLog/document.d.ts +182 -0
  196. package/dist/resourceLog/document.d.ts.map +1 -0
  197. package/dist/resourceLog/document.js +159 -0
  198. package/dist/resourceLog/document.js.map +1 -0
  199. package/dist/resourceLog/errors.d.ts +47 -8
  200. package/dist/resourceLog/errors.d.ts.map +1 -1
  201. package/dist/resourceLog/errors.js +54 -8
  202. package/dist/resourceLog/errors.js.map +1 -1
  203. package/dist/resourceLog/index.d.ts +7 -3
  204. package/dist/resourceLog/index.d.ts.map +1 -1
  205. package/dist/resourceLog/index.js +7 -3
  206. package/dist/resourceLog/index.js.map +1 -1
  207. package/dist/resourceLog/ladderRungs.d.ts +35 -0
  208. package/dist/resourceLog/ladderRungs.d.ts.map +1 -0
  209. package/dist/resourceLog/ladderRungs.js +352 -0
  210. package/dist/resourceLog/ladderRungs.js.map +1 -0
  211. package/dist/resourceLog/license.d.ts +42 -17
  212. package/dist/resourceLog/license.d.ts.map +1 -1
  213. package/dist/resourceLog/license.js +38 -24
  214. package/dist/resourceLog/license.js.map +1 -1
  215. package/dist/space/activity.d.ts +15 -15
  216. package/dist/space/activity.d.ts.map +1 -1
  217. package/dist/space/activity.js +15 -15
  218. package/dist/space/activity.js.map +1 -1
  219. package/dist/space/collections.d.ts +11 -0
  220. package/dist/space/collections.d.ts.map +1 -1
  221. package/dist/space/collections.js +13 -0
  222. package/dist/space/collections.js.map +1 -1
  223. package/dist/space/deleteSpace.d.ts +28 -0
  224. package/dist/space/deleteSpace.d.ts.map +1 -0
  225. package/dist/space/deleteSpace.js +44 -0
  226. package/dist/space/deleteSpace.js.map +1 -0
  227. package/dist/space/errors.d.ts.map +1 -1
  228. package/dist/space/errors.js +0 -1
  229. package/dist/space/errors.js.map +1 -1
  230. package/dist/space/index.d.ts +6 -0
  231. package/dist/space/index.d.ts.map +1 -1
  232. package/dist/space/index.js +6 -0
  233. package/dist/space/index.js.map +1 -1
  234. package/dist/space/plaintextCollection.d.ts +43 -0
  235. package/dist/space/plaintextCollection.d.ts.map +1 -0
  236. package/dist/space/plaintextCollection.js +17 -0
  237. package/dist/space/plaintextCollection.js.map +1 -0
  238. package/dist/stages.d.ts +23 -0
  239. package/dist/stages.d.ts.map +1 -0
  240. package/dist/stages.js +23 -0
  241. package/dist/stages.js.map +1 -0
  242. package/dist/sync/index.d.ts +7 -0
  243. package/dist/sync/index.d.ts.map +1 -1
  244. package/dist/sync/index.js +7 -0
  245. package/dist/sync/index.js.map +1 -1
  246. package/dist/sync/push.js +4 -4
  247. package/dist/sync/push.js.map +1 -1
  248. package/dist/sync/remint.js +2 -2
  249. package/dist/sync/remint.js.map +1 -1
  250. package/dist/sync/types.d.ts +41 -1
  251. package/dist/sync/types.d.ts.map +1 -1
  252. package/dist/sync/types.js +47 -1
  253. package/dist/sync/types.js.map +1 -1
  254. package/dist/unlock/index.d.ts +5 -1
  255. package/dist/unlock/index.d.ts.map +1 -1
  256. package/dist/unlock/index.js +5 -1
  257. package/dist/unlock/index.js.map +1 -1
  258. package/dist/unlock/retire.d.ts +35 -7
  259. package/dist/unlock/retire.d.ts.map +1 -1
  260. package/dist/unlock/retire.js +52 -14
  261. package/dist/unlock/retire.js.map +1 -1
  262. package/dist/unlock/standingClient.d.ts.map +1 -1
  263. package/dist/unlock/standingClient.js +5 -1
  264. package/dist/unlock/standingClient.js.map +1 -1
  265. package/dist/unlock/standingWebvh.d.ts +217 -35
  266. package/dist/unlock/standingWebvh.d.ts.map +1 -1
  267. package/dist/unlock/standingWebvh.js +469 -210
  268. package/dist/unlock/standingWebvh.js.map +1 -1
  269. package/dist/webvh/accountEntry.d.ts +146 -0
  270. package/dist/webvh/accountEntry.d.ts.map +1 -0
  271. package/dist/webvh/accountEntry.js +239 -0
  272. package/dist/webvh/accountEntry.js.map +1 -0
  273. package/dist/webvh/didWeb.d.ts +12 -7
  274. package/dist/webvh/didWeb.d.ts.map +1 -1
  275. package/dist/webvh/didWeb.js +2 -2
  276. package/dist/webvh/didWeb.js.map +1 -1
  277. package/dist/webvh/didWebProjection.d.ts +164 -0
  278. package/dist/webvh/didWebProjection.d.ts.map +1 -0
  279. package/dist/webvh/didWebProjection.js +230 -0
  280. package/dist/webvh/didWebProjection.js.map +1 -0
  281. package/dist/webvh/didWebvh.d.ts +275 -136
  282. package/dist/webvh/didWebvh.d.ts.map +1 -1
  283. package/dist/webvh/didWebvh.js +307 -340
  284. package/dist/webvh/didWebvh.js.map +1 -1
  285. package/dist/webvh/enrollClient.d.ts +65 -0
  286. package/dist/webvh/enrollClient.d.ts.map +1 -0
  287. package/dist/webvh/enrollClient.js +172 -0
  288. package/dist/webvh/enrollClient.js.map +1 -0
  289. package/dist/webvh/index.d.ts +37 -12
  290. package/dist/webvh/index.d.ts.map +1 -1
  291. package/dist/webvh/index.js +33 -10
  292. package/dist/webvh/index.js.map +1 -1
  293. package/dist/webvh/listClients.d.ts +1 -35
  294. package/dist/webvh/listClients.d.ts.map +1 -1
  295. package/dist/webvh/listClients.js +2 -30
  296. package/dist/webvh/listClients.js.map +1 -1
  297. package/dist/webvh/revokeClient.d.ts +41 -11
  298. package/dist/webvh/revokeClient.d.ts.map +1 -1
  299. package/dist/webvh/revokeClient.js +99 -48
  300. package/dist/webvh/revokeClient.js.map +1 -1
  301. package/dist/webvh/standingZcap.d.ts +61 -14
  302. package/dist/webvh/standingZcap.d.ts.map +1 -1
  303. package/dist/webvh/standingZcap.js +91 -0
  304. package/dist/webvh/standingZcap.js.map +1 -1
  305. package/dist/webvh/verifyLog.d.ts +59 -5
  306. package/dist/webvh/verifyLog.d.ts.map +1 -1
  307. package/dist/webvh/verifyLog.js +76 -11
  308. package/dist/webvh/verifyLog.js.map +1 -1
  309. package/dist/webvh/wasIdStore.d.ts +8 -8
  310. package/dist/webvh/wasIdStore.d.ts.map +1 -1
  311. package/dist/webvh/wasIdStore.js +39 -14
  312. package/dist/webvh/wasIdStore.js.map +1 -1
  313. package/dist/webvh/zcap.d.ts +14 -1
  314. package/dist/webvh/zcap.d.ts.map +1 -1
  315. package/dist/webvh/zcap.js +3 -27
  316. package/dist/webvh/zcap.js.map +1 -1
  317. package/package.json +2 -2
  318. package/dist/webvh/keyAgreement.d.ts +0 -97
  319. package/dist/webvh/keyAgreement.d.ts.map +0 -1
  320. package/dist/webvh/keyAgreement.js +0 -71
  321. package/dist/webvh/keyAgreement.js.map +0 -1
@@ -28,15 +28,17 @@
28
28
  * one-entry forget -- live in `clientAnnex/ladderAnchored.ts`. What stays
29
29
  * here is the verify-side half every wallet needs regardless of account configuration.
30
30
  */
31
- import { deriveNextKeyHash, updateDID } from '@interop/did-method-webvh';
32
- import { assertCarryOverCommitments, MULTIKEY_COMMITMENT_VM_TYPE, MULTIKEY_VM_TYPE, ladderVerificationMethod, publishUpdatedLog, readPublishedLog, relationIds, updateKeyMultibase, updateKeySigner, withLogConflictRetry } from '../webvh/didWebvh.js';
33
- import { ladderVmIds } from '../webvh/listClients.js';
31
+ import { deriveNextKeyHash } from '@interop/did-method-webvh';
32
+ import { MULTIKEY_COMMITMENT_VM_TYPE, MULTIKEY_VM_TYPE, ladderVerificationMethod, readPublishedLogOrThrow, withLogConflictRetry } from '../webvh/didWebvh.js';
33
+ import { signAccountEntry } from '../webvh/accountEntry.js';
34
+ import { preEntryProjectionPublisher } from '../webvh/didWebProjection.js';
35
+ import { ladderVmIds, relationIds } from '../resourceLog/document.js';
34
36
  // The one deliberate base-side dependency on the annex subpath, pinned as an
35
37
  // exception in the lint rule: this module resolves a credential's CURRENT
36
38
  // ladder inventory from the log itself (the shared attribution helpers in
37
39
  // `clientAnnex/ladder.ts`), never touching the annex log machinery, and
38
40
  // derives the credential's ladder VM from its seed at the install.
39
- import { attributeLadderInventory, LadderAttributionError, ladderVmKeyMultibase } from '../clientAnnex/ladder.js';
41
+ import { attributeLadderInventory, LadderAttributionError, ladderVmIdsIntroducedWithCredential, ladderVmKeyMultibase } from '../clientAnnex/ladder.js';
40
42
  /**
41
43
  * The ladder inventory the removal edit resolved from the log diverges from
42
44
  * what the caller was told one read earlier. A ceremony that names its
@@ -62,6 +64,54 @@ export class LadderInventoryDriftError extends Error {
62
64
  this.attributed = attributed;
63
65
  }
64
66
  }
67
+ /**
68
+ * A retirement whose ladder attribution could not claim the retired
69
+ * credential's ladder VM, refused with nothing written. The shape is the
70
+ * seedless strike claiming nothing: the credential still stands in the
71
+ * document, the walk struck no ladder VM, and ladder VMs stand there that it
72
+ * could not claim. A leftover VM would keep the retired credential's
73
+ * delegation authority alive -- under `capabilityDelegation` it can still
74
+ * sign a DELETE-only capability on the account Space -- and nothing
75
+ * downstream can tell such a leftover from a sibling credential's standing
76
+ * VM, so the retirement is the one place the state can be closed
77
+ * (`decisions/0015`).
78
+ *
79
+ * `unclaimedLadderVmIds` names every ladder VM the walk left unclaimed, and
80
+ * `anchorKeyMultibase` the update key the walk was anchored on (a recovery
81
+ * code's revocation anchors on the rung-0 multibase the registry recorded at
82
+ * issuance). On a
83
+ * multi-credential account that list carries the siblings' VMs beside the
84
+ * retired credential's, since telling them apart is exactly what the walk
85
+ * could not do. `retryableWithLadderSeed` says whether a retry supplying the
86
+ * credential's ladder seed can let attribution succeed. The gate raises this
87
+ * error only from a seedless claim (a seeded one either strikes the derived
88
+ * VM or proves there is none), so the hint is `true` from this library; the
89
+ * member is the wallets' read for the retry they offer.
90
+ * Matched on `name` (the error crosses app-injected seams that may resolve
91
+ * to another copy of this package).
92
+ */
93
+ export class UnclaimedLadderVmRetirementError extends Error {
94
+ unclaimedLadderVmIds;
95
+ retryableWithLadderSeed;
96
+ anchorKeyMultibase;
97
+ constructor({ unclaimedLadderVmIds, retryableWithLadderSeed, anchorKeyMultibase }) {
98
+ super("did:webvh: the retirement cannot claim the retired credential's ladder " +
99
+ `VM (standing unclaimed: ${unclaimedLadderVmIds.join(', ')}` +
100
+ (anchorKeyMultibase === undefined
101
+ ? ''
102
+ : `; anchored on ${anchorKeyMultibase}`) +
103
+ '); nothing was published and the credential still stands. ' +
104
+ (retryableWithLadderSeed
105
+ ? "Retry with the credential's ladder seed in hand."
106
+ : 'No retry with the ladder seed can claim it.'));
107
+ this.name = 'UnclaimedLadderVmRetirementError';
108
+ this.unclaimedLadderVmIds = unclaimedLadderVmIds;
109
+ this.retryableWithLadderSeed = retryableWithLadderSeed;
110
+ if (anchorKeyMultibase !== undefined) {
111
+ this.anchorKeyMultibase = anchorKeyMultibase;
112
+ }
113
+ }
114
+ }
65
115
  /**
66
116
  * The verification-method id a credential's key-agreement entry publishes
67
117
  * under: `<did>#<multibase>` for a verbatim key (indistinguishable by id from
@@ -111,6 +161,191 @@ export async function attributeUnlockLadderInventory({ log, did, unlockKeys, lad
111
161
  ...(ladderSeed ? { ladderSeed } : {})
112
162
  });
113
163
  }
164
+ /**
165
+ * What of the document's ladder VMs a credential's attribution claims: the
166
+ * VM its seed derives (when the ceremony holds one), plus every VM the log
167
+ * attributes to its ladder. Resolved once here and shared by the removal
168
+ * edit, the retirement ceremony's pre-edit stage, and the read-only
169
+ * pre-flight, so the three agree on what is struck and what is left.
170
+ *
171
+ * `struck` is what the removal edit strikes: the derived id when it stands,
172
+ * and the attributed ids. `unclaimed` is every ladder VM standing in the
173
+ * document that neither the seed nor the attribution claims -- on a
174
+ * multi-credential account, the siblings' VMs at least. A supplied seed also
175
+ * cross-checks the attribution: a log attributing a VM the seed does not
176
+ * derive refuses with {@link LadderAttributionError}.
177
+ *
178
+ * @param options {object}
179
+ * @param options.doc {DIDDoc} the document the attribution ran over
180
+ * @param options.did {string} the account DID
181
+ * @param options.inventory {LadderStandingInventory} the credential's
182
+ * attributed ladder inventory ({@link attributeUnlockLadderInventory})
183
+ * @param [options.ladderSeed] {Uint8Array} the credential's ladder seed
184
+ * @returns {Promise<{ ladderVmId?: string, struck: string[], unclaimed:
185
+ * string[] }>} the seed-derived VM id when a seed was held
186
+ */
187
+ export async function ladderVmClaimOf({ doc, did, inventory, ladderSeed }) {
188
+ const ladderVmId = ladderSeed
189
+ ? `${did}#${await ladderVmKeyMultibase({ ladderSeed })}`
190
+ : undefined;
191
+ if (ladderVmId !== undefined) {
192
+ const foreign = inventory.ladderVmIds.filter(id => id !== ladderVmId);
193
+ if (foreign.length > 0) {
194
+ throw new LadderAttributionError("The published log attributes a ladder VM this credential's seed " +
195
+ 'does not derive; refusing to strike on an ambiguous ' +
196
+ 'attribution.');
197
+ }
198
+ }
199
+ const standing = ladderVmIds({ doc });
200
+ const struck = new Set();
201
+ if (ladderVmId !== undefined && standing.includes(ladderVmId)) {
202
+ struck.add(ladderVmId);
203
+ }
204
+ for (const id of inventory.ladderVmIds) {
205
+ struck.add(id);
206
+ }
207
+ const claimed = new Set([
208
+ ...struck,
209
+ ...(ladderVmId !== undefined ? [ladderVmId] : [])
210
+ ]);
211
+ return {
212
+ ...(ladderVmId !== undefined ? { ladderVmId } : {}),
213
+ struck: [...struck],
214
+ unclaimed: standing.filter(id => !claimed.has(id))
215
+ };
216
+ }
217
+ /**
218
+ * The retirement gate (`decisions/0015`): refuses, with
219
+ * {@link UnclaimedLadderVmRetirementError}, a retirement of a
220
+ * ladder-carrying credential whose SEEDLESS claim struck nothing while a
221
+ * ladder VM that COULD BE THIS CREDENTIAL'S stands unclaimed and the
222
+ * credential itself still stands in the document. Deliberately narrower than
223
+ * "`unclaimed` is non-empty", which every retirement on a healthy
224
+ * multi-credential account produces, and narrower again than the standing
225
+ * unclaimed set: a sibling credential's VM is nothing this retirement could
226
+ * leave behind.
227
+ *
228
+ * Which unclaimed VMs are candidates is
229
+ * {@link ladderVmIdsIntroducedWithCredential}'s question, read off the log's
230
+ * entry shapes rather than off an attribution that has already refused: a VM
231
+ * introduced by the entry that introduced this credential's `keyAgreement`
232
+ * member, or by the entry that committed or authorized its anchor (the split
233
+ * bind, whose key and authority entries sit two versions apart). None, and
234
+ * the credential never had a VM to leave standing, so the retirement
235
+ * completes and strikes what it can. That is the torn issuance's orphan -- a
236
+ * credential with a `keyAgreement` member, no ladder VM, and no committed
237
+ * rung -- which previously could never be removed at all, since a sibling's
238
+ * standing VM refused it forever.
239
+ *
240
+ * Two shapes pass ahead of that. A credential whose `keyAgreement` member is
241
+ * already gone is a completed retirement re-running. And a claim resolved
242
+ * WITH the seed never refuses: the derived VM is either standing (and
243
+ * struck) or absent, and an absent derived VM is proof the credential has
244
+ * nothing to claim -- the last-client transition torn between its strike and
245
+ * reinstall entries leaves exactly that, and a seeded retirement there must
246
+ * complete rather than wait on the transition's re-run. So the error's retry
247
+ * hint is `true` whenever this gate raises it.
248
+ *
249
+ * The caller decides whether the credential carries a ladder.
250
+ *
251
+ * @param options {object}
252
+ * @param options.log {DIDLog} the verified log the claim was resolved over
253
+ * @param options.doc {DIDDoc} the document the claim was resolved over
254
+ * @param options.credentialVmId {string} the credential's `keyAgreement`
255
+ * verification-method id ({@link unlockKeyVmId})
256
+ * @param options.claim {{ ladderVmId?: string, struck: string[], unclaimed:
257
+ * string[] }} from {@link ladderVmClaimOf}
258
+ * @param [options.anchorKeyMultibase] {string} the update key the walk was
259
+ * anchored on: the candidate reading's second anchor form, and named in
260
+ * the refusal
261
+ * @returns {Promise<void>}
262
+ */
263
+ export async function assertLadderVmClaimed({ log, doc, credentialVmId, claim, anchorKeyMultibase }) {
264
+ const credentialStands = (doc.verificationMethod ?? []).some(method => method.id === credentialVmId);
265
+ if (!credentialStands ||
266
+ claim.ladderVmId !== undefined ||
267
+ claim.struck.length > 0 ||
268
+ claim.unclaimed.length === 0) {
269
+ return;
270
+ }
271
+ const candidates = await ladderVmIdsIntroducedWithCredential({
272
+ log,
273
+ credentialVmId,
274
+ ...(anchorKeyMultibase !== undefined ? { anchorKeyMultibase } : {})
275
+ });
276
+ const unclaimed = claim.unclaimed.filter(id => candidates.includes(id));
277
+ if (unclaimed.length === 0) {
278
+ return;
279
+ }
280
+ throw new UnclaimedLadderVmRetirementError({
281
+ unclaimedLadderVmIds: unclaimed,
282
+ retryableWithLadderSeed: true,
283
+ ...(anchorKeyMultibase !== undefined ? { anchorKeyMultibase } : {})
284
+ });
285
+ }
286
+ /**
287
+ * The retirement gate run read-only, before anything is written: one pinned
288
+ * read of the account log, the credential's ladder attribution, and
289
+ * {@link assertLadderVmClaimed} over the result. A caller that establishes a
290
+ * replacement credential before it retires the old one (a passphrase change,
291
+ * a tap-confirmed passkey removal) runs this first, so a gate refusal lands
292
+ * the way an invalid-input check does -- nothing established, no
293
+ * pending-shaped registry entry written -- rather than after establishment,
294
+ * where the refusal would leave a torn state no seedless repair can clear.
295
+ * The in-ceremony gate stays as defense in depth, and it is what answers a
296
+ * log entry landing between the pre-flight and the retirement: the
297
+ * pre-flight's verdict holds for the head it read, and nothing binds the two
298
+ * reads.
299
+ *
300
+ * @param options {object}
301
+ * @param options.idStore {UnlockLogStore} the account's `id` collection
302
+ * read side
303
+ * @param options.unlockKeys {StandingUnlockKeys} the credential's recorded
304
+ * public inventory
305
+ * @param [options.ladderSeed] {Uint8Array} the credential's ladder seed,
306
+ * when the caller holds it
307
+ * @param [options.expectedDid] {string} the account DID the log must
308
+ * resolve to
309
+ * @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
310
+ * pins
311
+ * @param [options.logId] {string} the account log's pin slot; required
312
+ * whenever a `pinStore` is supplied
313
+ * @returns {Promise<LadderVmRemovalReport>} what the retirement would
314
+ * strike and what it would leave unclaimed
315
+ */
316
+ export async function preflightUnlockCredentialRetirement({ idStore, unlockKeys, ladderSeed, expectedDid, pinStore, logId }) {
317
+ const published = await readPublishedLogOrThrow({
318
+ idStore,
319
+ ...(expectedDid !== undefined ? { expectedDid } : {}),
320
+ ...(pinStore ? { pinStore } : {}),
321
+ ...(logId !== undefined ? { logId } : {}),
322
+ missingMessage: 'did:webvh: did.jsonl is missing; nothing to retire from.'
323
+ });
324
+ const { did, doc } = published;
325
+ const inventory = await attributeUnlockLadderInventory({
326
+ log: published.log,
327
+ did,
328
+ unlockKeys,
329
+ ...(ladderSeed ? { ladderSeed } : {})
330
+ });
331
+ const claim = await ladderVmClaimOf({
332
+ doc,
333
+ did,
334
+ inventory,
335
+ ...(ladderSeed ? { ladderSeed } : {})
336
+ });
337
+ await assertLadderVmClaimed({
338
+ log: published.log,
339
+ doc,
340
+ credentialVmId: unlockKeyVmId({
341
+ did,
342
+ keyAgreement: unlockKeys.keyAgreement
343
+ }),
344
+ claim,
345
+ anchorKeyMultibase: unlockKeys.updateKeyMultibase
346
+ });
347
+ return { struck: claim.struck, unclaimed: claim.unclaimed };
348
+ }
114
349
  /**
115
350
  * The credential's `keyAgreement` verification method: an ordinary unmarked
116
351
  * entry carrying either the key verbatim (a `Multikey` with
@@ -144,34 +379,6 @@ export function unlockKeyVerificationMethod({ did, keyAgreement }) {
144
379
  publicKeyCommitment: keyAgreement.commitment
145
380
  };
146
381
  }
147
- /**
148
- * Reads and resolves the published log through the narrow store seam.
149
- *
150
- * @param options {object}
151
- * @param options.store {UnlockLogStore}
152
- * @param [options.expectedDid] {string} the account DID the log must resolve
153
- * to, where the caller holds one
154
- * @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
155
- * pins; a served log that is a rollback, a fork, or an identity switch
156
- * against the pinned head is refused (`ResourceLogContinuityError`)
157
- * @param [options.logId] {string} the account log's pin slot
158
- * (`accountLogPinId({ spaceId })`); required whenever a `pinStore` is
159
- * supplied
160
- * @returns {Promise<PublishedWebvhLog>}
161
- */
162
- export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
163
- // readPublishedLog only calls getIdResourceRaw, so the narrow seam is safe.
164
- const published = await readPublishedLog({
165
- idStore: store,
166
- ...(expectedDid !== undefined ? { expectedDid } : {}),
167
- ...(pinStore ? { pinStore } : {}),
168
- ...(logId !== undefined ? { logId } : {})
169
- });
170
- if (!published) {
171
- throw new Error('did:webvh: did.jsonl is missing; nothing to enroll into.');
172
- }
173
- return published;
174
- }
175
382
  /**
176
383
  * BIND (run by an enrolled client, root authority): publishes a standing
177
384
  * credential's split configuration into the document -- one entry adding the
@@ -187,8 +394,13 @@ export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
187
394
  * idempotence against the SAME seed, finds the completed stage and publishes
188
395
  * nothing -- where a mint-when-absent would publish a second VM that no
189
396
  * anchored attribution could later strike. A credential with no ladder at all
190
- * (a recovery code, whose inventory is one key-agreement method and one
191
- * update key) passes `null` and gets no VM.
397
+ * passes `null` and gets no VM.
398
+ *
399
+ * `part` splits the bind across two entries where a ceremony needs the
400
+ * credential's decryption material to precede its authority: `'key'`
401
+ * publishes the `keyAgreement` member alone, `'authority'` installs the
402
+ * ladder VM and commits the rung-0 hash, and `'all'` (the default) is the one
403
+ * merged entry every other caller writes.
192
404
  *
193
405
  * Idempotent: an inventory already published is a no-op, so re-running a torn
194
406
  * bind converges. The entry publishes conditionally on the log this call
@@ -197,13 +409,16 @@ export async function readLogOrThrow({ store, expectedDid, pinStore, logId }) {
197
409
  *
198
410
  * @param options {object}
199
411
  * @param options.idStore {WebvhIdStore}
200
- * @param options.updateKeys {ClientWebvhUpdateKeys} the BINDING client's own
201
- * did:webvh update-key seeds
412
+ * @param options.signer {AccountLogSigner} who signs the entry: the BINDING
413
+ * client's own did:webvh update-key seeds, or the acting credential's
414
+ * ladder seed
202
415
  * @param options.unlockKeys {StandingUnlockKeys} the credential's public
203
416
  * inventory
204
417
  * @param options.ladderSeed {Uint8Array | null} the credential's ladder
205
418
  * seed, whose VM this entry installs; `null` for a credential that carries
206
419
  * no ladder
420
+ * @param [options.part] {string} `'all'` (the default), `'key'`, or
421
+ * `'authority'` -- see above
207
422
  * @param [options.expectedDid] {string} the account DID the log must resolve
208
423
  * to, from the caller's stored account pointer
209
424
  * @param [options.pinStore] {ResourceLogPinStore} the caller's chain-head
@@ -276,6 +491,15 @@ export async function publishUnlockKey(options) {
276
491
  * @param options {object} see {@link publishUnlockKey}, plus:
277
492
  * @param [options.ladderSeed] {Uint8Array} the retired credential's ladder
278
493
  * seed, when in hand
494
+ * @param [options.projectionStore] {object} an `id`-collection store the
495
+ * caller may write through (a transient session's, bound to its generation
496
+ * delegation; an enrolled client's own root-invoking store). Supplied, the
497
+ * post-strike `did:web` projection is PUT through it immediately BEFORE
498
+ * this entry publishes, which is what keeps a ladder-signed removal from
499
+ * leaving `did.json` naming the retired credential. Best-effort: a failed
500
+ * PUT is warned and the removal proceeds. Omitted, the ladder arm leaves
501
+ * the projection to the next visit's `ensureDidWebProjection` and the
502
+ * client arm publishes it after the entry, as before
279
503
  * @param [options.expectedLadderVmIds] {string[]} the ladder VM ids the
280
504
  * caller already resolved for this credential, from its own read of the
281
505
  * log. Supplied, this edit's own attribution must match them as a set --
@@ -283,6 +507,14 @@ export async function publishUnlockKey(options) {
283
507
  * {@link LadderInventoryDriftError} before writing anything. That is what
284
508
  * ties the retirement's stage-0 read (whose list the dependent-record
285
509
  * re-mint pass acted on) to this one, which is otherwise independent
510
+ * @param [options.requireLadderVmClaim] {boolean} the credential carries a
511
+ * ladder, so its VM must be claimed: the edit refuses with
512
+ * {@link UnclaimedLadderVmRetirementError} before writing when the claim
513
+ * struck nothing while ladder VMs stand unclaimed and the credential still
514
+ * stands ({@link assertLadderVmClaimed}). The retirement ceremony sets it,
515
+ * and so does a recovery code's removal, whose inventory carries the code's
516
+ * own ladder VM. The refusal names the recorded update key the walk was
517
+ * anchored on
286
518
  * @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog, ladderVm:
287
519
  * LadderVmRemovalReport }>} see {@link publishUnlockKey}, plus the ladder
288
520
  * VM report: what this entry struck, and what stands unclaimed after it
@@ -299,189 +531,216 @@ export async function removeUnlockKey(options) {
299
531
  * @param options {object} see {@link publishUnlockKey}, plus `polarity`
300
532
  * @returns {Promise<{ did: string, doc: DIDDoc, log: DIDLog }>}
301
533
  */
302
- async function setUnlockKeyInventoryOnce({ idStore, updateKeys, unlockKeys, ladderSeed, expectedLadderVmIds, expectedDid, pinStore, logId, verb, polarity }) {
303
- const published = await readLogOrThrow({
304
- store: idStore,
534
+ async function setUnlockKeyInventoryOnce({ idStore, signer, projectionStore, unlockKeys, ladderSeed, part = 'all', expectedLadderVmIds, requireLadderVmClaim, expectedDid, pinStore, logId, verb, polarity }) {
535
+ let ladderVmReport = { struck: [], unclaimed: [] };
536
+ const outcome = await signAccountEntry({
537
+ idStore,
538
+ signer,
305
539
  ...(expectedDid !== undefined ? { expectedDid } : {}),
306
540
  ...(pinStore ? { pinStore } : {}),
307
- ...(logId !== undefined ? { logId } : {})
308
- });
309
- const { did, doc } = published;
310
- const keyHash = await deriveNextKeyHash(unlockKeys.updateKeyMultibase);
311
- const vmId = unlockKeyVmId({ did, keyAgreement: unlockKeys.keyAgreement });
312
- const vmPresent = (doc.verificationMethod ?? []).some(method => method.id === vmId);
313
- // The remove polarity strikes the ladder's CURRENT inventory, resolved from
314
- // the log with the recorded key as anchor -- never just the recorded key's
315
- // hash, which a self-enrollment since the bind leaves stale (see
316
- // {@link removeUnlockKey}). The credential's own verification-method id
317
- // goes along: it is what tells the walk a climb from a spend, so the
318
- // removal never annexes the commitment a spend handed to its replacement.
319
- const inventory = polarity === 'remove'
320
- ? await attributeUnlockLadderInventory({
321
- log: published.log,
322
- did,
323
- unlockKeys,
324
- ...(ladderSeed ? { ladderSeed } : {})
325
- })
326
- : { revealedKeys: [], committedHashes: [], ladderVmIds: [] };
327
- const removedHashes = new Set(inventory.committedHashes);
328
- const removedKeys = new Set(inventory.revealedKeys);
329
- // The credential's ladder VM: installed by the publish polarity in this
330
- // same entry, struck by the remove polarity in this same entry. The
331
- // derived id is what the install publishes; the removal takes it from the
332
- // seed when the ceremony holds one and from the log's attribution
333
- // otherwise, so a seedless retirement still ends the credential's
334
- // delegation authority.
335
- const ladderVmKey = ladderSeed
336
- ? await ladderVmKeyMultibase({ ladderSeed })
337
- : undefined;
338
- const ladderVmId = ladderVmKey === undefined ? undefined : `${did}#${ladderVmKey}`;
339
- const standingLadderVmIds = ladderVmIds({ doc });
340
- const struckLadderVmIds = new Set();
341
- if (polarity === 'remove') {
342
- if (ladderVmId !== undefined) {
343
- const foreign = inventory.ladderVmIds.filter(id => id !== ladderVmId);
344
- if (foreign.length > 0) {
345
- throw new LadderAttributionError("The published log attributes a ladder VM this credential's seed " +
346
- 'does not derive; refusing to strike on an ambiguous ' +
347
- 'attribution.');
541
+ ...(logId !== undefined ? { logId } : {}),
542
+ missingMessage: 'did:webvh: did.jsonl is missing; nothing to enroll into.',
543
+ verb: verb ?? 'changing an unlock credential',
544
+ // The post-strike projection, published while the caller's store can
545
+ // still write it and before the entry the ladder arm cannot publish it
546
+ // with. Only the removal polarity is ever handed one: a publish adds
547
+ // inventory, which the served projection under-lists until some later
548
+ // writer refreshes it -- the safe direction.
549
+ ...(projectionStore
550
+ ? {
551
+ beforePublish: preEntryProjectionPublisher({
552
+ store: projectionStore
553
+ })
348
554
  }
349
- if (standingLadderVmIds.includes(ladderVmId)) {
350
- struckLadderVmIds.add(ladderVmId);
555
+ : {}),
556
+ build: async ({ published }) => {
557
+ const { did, doc } = published;
558
+ const keyHash = await deriveNextKeyHash(unlockKeys.updateKeyMultibase);
559
+ const vmId = unlockKeyVmId({ did, keyAgreement: unlockKeys.keyAgreement });
560
+ const vmPresent = (doc.verificationMethod ?? []).some(method => method.id === vmId);
561
+ // The remove polarity strikes the ladder's CURRENT inventory, resolved
562
+ // from the log with the recorded key as anchor -- never just the
563
+ // recorded key's hash, which a self-enrollment since the bind leaves
564
+ // stale (see {@link removeUnlockKey}). The credential's own
565
+ // verification-method id goes along: it is what tells the walk a climb
566
+ // from a spend, so the removal never annexes the commitment a spend
567
+ // handed to its replacement.
568
+ const inventory = polarity === 'remove'
569
+ ? await attributeUnlockLadderInventory({
570
+ log: published.log,
571
+ did,
572
+ unlockKeys,
573
+ ...(ladderSeed ? { ladderSeed } : {})
574
+ })
575
+ : { revealedKeys: [], committedHashes: [], ladderVmIds: [] };
576
+ const removedHashes = new Set(inventory.committedHashes);
577
+ const removedKeys = new Set(inventory.revealedKeys);
578
+ // The credential's ladder VM: installed by the publish polarity in this
579
+ // same entry, struck by the remove polarity in this same entry. The
580
+ // derived id is what the install publishes; the removal takes it from
581
+ // the seed when the ceremony holds one and from the log's attribution
582
+ // otherwise, so a seedless retirement still ends the credential's
583
+ // delegation authority.
584
+ const ladderVmKey = ladderSeed
585
+ ? await ladderVmKeyMultibase({ ladderSeed })
586
+ : undefined;
587
+ const ladderVmId = ladderVmKey === undefined ? undefined : `${did}#${ladderVmKey}`;
588
+ const standingLadderVmIds = ladderVmIds({ doc });
589
+ const claim = polarity === 'remove'
590
+ ? await ladderVmClaimOf({
591
+ doc,
592
+ did,
593
+ inventory,
594
+ ...(ladderSeed ? { ladderSeed } : {})
595
+ })
596
+ : { struck: [], unclaimed: [] };
597
+ if (polarity === 'remove') {
598
+ // The drift check, before any write: this edit's own attribution
599
+ // against the list the caller resolved a read earlier. A concurrent
600
+ // ceremony, or a host serving two different log versions to the two
601
+ // reads, would otherwise let the strike diverge from what the
602
+ // caller's dependent-record pass already acted on.
603
+ if (expectedLadderVmIds !== undefined) {
604
+ const attributed = new Set(inventory.ladderVmIds);
605
+ const expected = new Set(expectedLadderVmIds);
606
+ const sameSet = attributed.size === expected.size &&
607
+ [...expected].every(id => attributed.has(id));
608
+ if (!sameSet) {
609
+ throw new LadderInventoryDriftError({
610
+ expected: [...expected],
611
+ attributed: [...attributed]
612
+ });
613
+ }
614
+ }
615
+ // The retirement gate, before any write and after the drift check: a
616
+ // ladder-carrying credential whose claim struck nothing while ladder
617
+ // VMs stand unclaimed is refused rather than retired with its VM left
618
+ // standing.
619
+ if (requireLadderVmClaim) {
620
+ await assertLadderVmClaimed({
621
+ log: published.log,
622
+ doc,
623
+ credentialVmId: vmId,
624
+ claim,
625
+ anchorKeyMultibase: unlockKeys.updateKeyMultibase
626
+ });
627
+ }
351
628
  }
352
- }
353
- for (const id of inventory.ladderVmIds) {
354
- struckLadderVmIds.add(id);
355
- }
356
- // The drift check, before any write: this edit's own attribution against
357
- // the list the caller resolved a read earlier. A concurrent ceremony, or
358
- // a host serving two different log versions to the two reads, would
359
- // otherwise let the strike diverge from what the caller's dependent-record
360
- // pass already acted on.
361
- if (expectedLadderVmIds !== undefined) {
362
- const attributed = new Set(inventory.ladderVmIds);
363
- const expected = new Set(expectedLadderVmIds);
364
- const sameSet = attributed.size === expected.size &&
365
- [...expected].every(id => attributed.has(id));
366
- if (!sameSet) {
367
- throw new LadderInventoryDriftError({
368
- expected: [...expected],
369
- attributed: [...attributed]
370
- });
629
+ const struckLadderVmIds = new Set(claim.struck);
630
+ const ladderVmPresent = polarity === 'publish'
631
+ ? ladderVmId !== undefined && standingLadderVmIds.includes(ladderVmId)
632
+ : struckLadderVmIds.size > 0;
633
+ const struckIds = new Set([vmId, ...struckLadderVmIds]);
634
+ const hashCommitted = published.nextKeyHashes.includes(keyHash);
635
+ // What this entry is responsible for, by `part`: the key half publishes
636
+ // the `keyAgreement` member alone, the authority half the ladder VM and
637
+ // the rung's commitment, and the default entry both.
638
+ const publishesKey = part === 'all' || part === 'key';
639
+ const publishesAuthority = part === 'all' || part === 'authority';
640
+ const settled = polarity === 'publish'
641
+ ? (!publishesKey || vmPresent) &&
642
+ (!publishesAuthority ||
643
+ (hashCommitted && (ladderVmId === undefined || ladderVmPresent)))
644
+ : !vmPresent &&
645
+ !ladderVmPresent &&
646
+ removedHashes.size === 0 &&
647
+ removedKeys.size === 0;
648
+ ladderVmReport = {
649
+ struck: claim.struck,
650
+ unclaimed: claim.unclaimed
651
+ };
652
+ if (settled) {
653
+ return undefined;
371
654
  }
372
- }
373
- }
374
- const ladderVmPresent = polarity === 'publish'
375
- ? ladderVmId !== undefined && standingLadderVmIds.includes(ladderVmId)
376
- : struckLadderVmIds.size > 0;
377
- const struckIds = new Set([vmId, ...struckLadderVmIds]);
378
- const hashCommitted = published.nextKeyHashes.includes(keyHash);
379
- const settled = polarity === 'publish'
380
- ? vmPresent &&
381
- hashCommitted &&
382
- (ladderVmId === undefined || ladderVmPresent)
383
- : !vmPresent &&
384
- !ladderVmPresent &&
385
- removedHashes.size === 0 &&
386
- removedKeys.size === 0;
387
- const ladderVmReport = (resultDoc, struck) => {
388
- const claimed = new Set([
389
- ...struck,
390
- ...inventory.ladderVmIds,
391
- ...(ladderVmId !== undefined ? [ladderVmId] : [])
392
- ]);
393
- return {
394
- struck: [...struck],
395
- unclaimed: ladderVmIds({ doc: resultDoc }).filter(id => !claimed.has(id))
396
- };
397
- };
398
- if (settled) {
399
- return {
400
- did,
401
- doc,
402
- log: published.log,
403
- ladderVm: ladderVmReport(doc, struckLadderVmIds)
404
- };
405
- }
406
- const activeKey = await updateKeyMultibase({ seed: updateKeys.updateSeed });
407
- if (!published.updateKeys.includes(activeKey)) {
408
- throw new Error("did:webvh: the published log does not authorize this client's active " +
409
- 'update key; finalize the pending rotation before ' +
410
- `${verb ?? 'changing an unlock credential'}.`);
411
- }
412
- await assertCarryOverCommitments({ published });
413
- const existingMethods = (doc.verificationMethod ?? []);
414
- const signer = await updateKeySigner({ seed: updateKeys.updateSeed });
415
- const nextKeyHashes = polarity === 'publish'
416
- ? [...new Set([...published.nextKeyHashes, keyHash])]
417
- : published.nextKeyHashes.filter(hash => !removedHashes.has(hash));
418
- // A torn self-enrollment leaves a revealed rung in `updateKeys`; the remove
419
- // polarity strikes it in the same entry as its hash, keeping the carry-over
420
- // invariant self-consistent. On the publish polarity and the ordinary
421
- // committed-only removal this is the published set unchanged.
422
- const statedUpdateKeys = polarity === 'publish'
423
- ? published.updateKeys
424
- : published.updateKeys.filter(key => !removedKeys.has(key));
425
- const verificationMethods = polarity === 'publish'
426
- ? [
427
- ...existingMethods.filter(method => method.id !== vmId && method.id !== ladderVmId),
428
- unlockKeyVerificationMethod({
429
- did,
430
- keyAgreement: unlockKeys.keyAgreement
431
- }),
432
- ...(ladderVmKey !== undefined
655
+ const existingMethods = (doc.verificationMethod ??
656
+ []);
657
+ // The publish polarity commits the credential's update-key hash through
658
+ // the seam's `commitHashes`, so on a ladder-signed entry it lands after
659
+ // the acting rung's own carry-over hash (`decisions/0007` order).
660
+ const commitHashes = polarity === 'publish' && publishesAuthority && !hashCommitted
661
+ ? [keyHash]
662
+ : [];
663
+ const nextKeyHashes = polarity === 'publish'
664
+ ? undefined
665
+ : published.nextKeyHashes.filter(hash => !removedHashes.has(hash));
666
+ // A torn self-enrollment leaves a revealed rung in `updateKeys`; the
667
+ // remove polarity strikes it in the same entry as its hash, keeping the
668
+ // carry-over invariant self-consistent. On the publish polarity and the
669
+ // ordinary committed-only removal this is the published set unchanged.
670
+ const statedUpdateKeys = polarity === 'publish'
671
+ ? undefined
672
+ : published.updateKeys.filter(key => !removedKeys.has(key));
673
+ const installedLadderVmKey = publishesAuthority ? ladderVmKey : undefined;
674
+ const verificationMethods = polarity === 'publish'
433
675
  ? [
434
- ladderVerificationMethod({
435
- controller: did,
436
- publicKeyMultibase: ladderVmKey
437
- })
676
+ ...existingMethods.filter(method => method.id !== (publishesKey ? vmId : undefined) &&
677
+ method.id !== (publishesAuthority ? ladderVmId : undefined)),
678
+ ...(publishesKey
679
+ ? [
680
+ unlockKeyVerificationMethod({
681
+ did,
682
+ keyAgreement: unlockKeys.keyAgreement
683
+ })
684
+ ]
685
+ : []),
686
+ ...(installedLadderVmKey !== undefined
687
+ ? [
688
+ ladderVerificationMethod({
689
+ controller: did,
690
+ publicKeyMultibase: installedLadderVmKey
691
+ })
692
+ ]
693
+ : [])
438
694
  ]
439
- : [])
440
- ]
441
- : existingMethods.filter(method => method.id === undefined || !struckIds.has(method.id));
442
- // On the remove polarity every relation drops the struck ids: the
443
- // credential's entry sits under `keyAgreement` alone and the ladder VM under
444
- // `assertionMethod` and `capabilityDelegation` alone, so one filter serves
445
- // all five without restating either placement here.
446
- const relation = (ids) => polarity === 'publish'
447
- ? relationIds(ids)
448
- : relationIds(ids).filter(id => !struckIds.has(id));
449
- const keyAgreement = polarity === 'publish'
450
- ? [...new Set([...relationIds(doc.keyAgreement), vmId])]
451
- : relation(doc.keyAgreement);
452
- // The ladder VM's two relations, and only those: the asymmetry is what
453
- // recognizes it (`ladderVmIds`) and what keeps it out of every client
454
- // listing.
455
- const withLadderVm = (ids) => ladderVmId === undefined
456
- ? relationIds(ids)
457
- : [...new Set([...relationIds(ids), ladderVmId])];
458
- const assertionMethod = polarity === 'publish'
459
- ? withLadderVm(doc.assertionMethod)
460
- : relation(doc.assertionMethod);
461
- const capabilityDelegation = polarity === 'publish'
462
- ? withLadderVm(doc.capabilityDelegation)
463
- : relation(doc.capabilityDelegation);
464
- const updated = await updateDID({
465
- log: published.log,
466
- signer,
467
- alsoKnownAsWeb: true,
468
- // The byoe context that defines a commitment entry's terms is installed
469
- // at genesis and carried forward by every update, so no edit re-appends it.
470
- updateKeys: statedUpdateKeys,
471
- nextKeyHashes,
472
- verificationMethods,
473
- authentication: relation(doc.authentication),
474
- assertionMethod,
475
- keyAgreement,
476
- capabilityInvocation: relation(doc.capabilityInvocation),
477
- capabilityDelegation
695
+ : existingMethods.filter(method => method.id === undefined || !struckIds.has(method.id));
696
+ // On the remove polarity every relation drops the struck ids: the
697
+ // credential's entry sits under `keyAgreement` alone and the ladder VM
698
+ // under `assertionMethod` and `capabilityDelegation` alone, so one
699
+ // filter serves all five without restating either placement here.
700
+ const relation = (ids) => polarity === 'publish'
701
+ ? relationIds(ids)
702
+ : relationIds(ids).filter(id => !struckIds.has(id));
703
+ const keyAgreement = polarity === 'publish'
704
+ ? publishesKey
705
+ ? [...new Set([...relationIds(doc.keyAgreement), vmId])]
706
+ : relationIds(doc.keyAgreement)
707
+ : relation(doc.keyAgreement);
708
+ // The ladder VM's two relations, and only those: the asymmetry is what
709
+ // recognizes it (`ladderVmIds`) and what keeps it out of every client
710
+ // listing.
711
+ const withLadderVm = (ids) => installedLadderVmKey === undefined || ladderVmId === undefined
712
+ ? relationIds(ids)
713
+ : [...new Set([...relationIds(ids), ladderVmId])];
714
+ const assertionMethod = polarity === 'publish'
715
+ ? withLadderVm(doc.assertionMethod)
716
+ : relation(doc.assertionMethod);
717
+ const capabilityDelegation = polarity === 'publish'
718
+ ? withLadderVm(doc.capabilityDelegation)
719
+ : relation(doc.capabilityDelegation);
720
+ return {
721
+ // The byoe context that defines a commitment entry's terms is
722
+ // installed at genesis and carried forward by every update, so no
723
+ // edit re-appends it.
724
+ ...(statedUpdateKeys !== undefined
725
+ ? { updateKeys: statedUpdateKeys }
726
+ : {}),
727
+ ...(nextKeyHashes !== undefined ? { nextKeyHashes } : {}),
728
+ ...(commitHashes.length > 0 ? { commitHashes } : {}),
729
+ verificationMethods,
730
+ authentication: relation(doc.authentication),
731
+ assertionMethod,
732
+ keyAgreement,
733
+ capabilityInvocation: relation(doc.capabilityInvocation),
734
+ capabilityDelegation
735
+ };
736
+ }
478
737
  });
479
- await publishUpdatedLog({ idStore, updated, ifMatch: published.etag });
738
+ const settledHead = outcome.updated ?? outcome.published;
480
739
  return {
481
- did: updated.did,
482
- doc: updated.doc,
483
- log: updated.log,
484
- ladderVm: ladderVmReport(updated.doc, struckLadderVmIds)
740
+ did: settledHead.did,
741
+ doc: settledHead.doc,
742
+ log: settledHead.log,
743
+ ladderVm: ladderVmReport
485
744
  };
486
745
  }
487
746
  //# sourceMappingURL=standingWebvh.js.map