@interop/did-cli 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +192 -4
  3. package/dist/commands/collection-command.d.ts +169 -0
  4. package/dist/commands/collection-command.d.ts.map +1 -0
  5. package/dist/commands/collection-command.js +241 -0
  6. package/dist/commands/collection-command.js.map +1 -0
  7. package/dist/commands/did/create.d.ts +63 -0
  8. package/dist/commands/did/create.d.ts.map +1 -0
  9. package/dist/commands/did/create.js +625 -0
  10. package/dist/commands/did/create.js.map +1 -0
  11. package/dist/commands/did/manage.d.ts +68 -0
  12. package/dist/commands/did/manage.d.ts.map +1 -0
  13. package/dist/commands/did/manage.js +287 -0
  14. package/dist/commands/did/manage.js.map +1 -0
  15. package/dist/commands/did/service.d.ts +93 -0
  16. package/dist/commands/did/service.d.ts.map +1 -0
  17. package/dist/commands/did/service.js +324 -0
  18. package/dist/commands/did/service.js.map +1 -0
  19. package/dist/commands/did/webvh-update.d.ts +170 -0
  20. package/dist/commands/did/webvh-update.d.ts.map +1 -0
  21. package/dist/commands/did/webvh-update.js +402 -0
  22. package/dist/commands/did/webvh-update.js.map +1 -0
  23. package/dist/commands/did.d.ts +9 -0
  24. package/dist/commands/did.d.ts.map +1 -1
  25. package/dist/commands/did.js +107 -597
  26. package/dist/commands/did.js.map +1 -1
  27. package/dist/commands/edv.d.ts +15 -6
  28. package/dist/commands/edv.d.ts.map +1 -1
  29. package/dist/commands/edv.js +38 -28
  30. package/dist/commands/edv.js.map +1 -1
  31. package/dist/commands/key.d.ts +104 -0
  32. package/dist/commands/key.d.ts.map +1 -1
  33. package/dist/commands/key.js +432 -402
  34. package/dist/commands/key.js.map +1 -1
  35. package/dist/commands/vc.d.ts +2 -1
  36. package/dist/commands/vc.d.ts.map +1 -1
  37. package/dist/commands/vc.js +88 -145
  38. package/dist/commands/vc.js.map +1 -1
  39. package/dist/commands/was/collection.d.ts.map +1 -1
  40. package/dist/commands/was/collection.js +31 -85
  41. package/dist/commands/was/collection.js.map +1 -1
  42. package/dist/commands/was/publish.d.ts.map +1 -1
  43. package/dist/commands/was/publish.js +16 -44
  44. package/dist/commands/was/publish.js.map +1 -1
  45. package/dist/commands/was/resource.d.ts.map +1 -1
  46. package/dist/commands/was/resource.js +24 -51
  47. package/dist/commands/was/resource.js.map +1 -1
  48. package/dist/commands/was/shared.d.ts +78 -0
  49. package/dist/commands/was/shared.d.ts.map +1 -1
  50. package/dist/commands/was/shared.js +84 -0
  51. package/dist/commands/was/shared.js.map +1 -1
  52. package/dist/commands/was/space.d.ts +17 -0
  53. package/dist/commands/was/space.d.ts.map +1 -1
  54. package/dist/commands/was/space.js +47 -18
  55. package/dist/commands/was/space.js.map +1 -1
  56. package/dist/commands/was/tree.d.ts.map +1 -1
  57. package/dist/commands/was/tree.js +4 -6
  58. package/dist/commands/was/tree.js.map +1 -1
  59. package/dist/commands/was.d.ts +1 -1
  60. package/dist/commands/was.d.ts.map +1 -1
  61. package/dist/commands/was.js +71 -76
  62. package/dist/commands/was.js.map +1 -1
  63. package/dist/commands/zcap.d.ts +0 -18
  64. package/dist/commands/zcap.d.ts.map +1 -1
  65. package/dist/commands/zcap.js +63 -155
  66. package/dist/commands/zcap.js.map +1 -1
  67. package/dist/documentLoader.d.ts +5 -0
  68. package/dist/documentLoader.d.ts.map +1 -0
  69. package/dist/documentLoader.js +29 -0
  70. package/dist/documentLoader.js.map +1 -0
  71. package/dist/edv/hmac.d.ts.map +1 -1
  72. package/dist/edv/hmac.js +12 -12
  73. package/dist/edv/hmac.js.map +1 -1
  74. package/dist/edv/recipients.d.ts +2 -0
  75. package/dist/edv/recipients.d.ts.map +1 -1
  76. package/dist/edv/recipients.js +12 -15
  77. package/dist/edv/recipients.js.map +1 -1
  78. package/dist/keys/webvh-signer.d.ts +29 -0
  79. package/dist/keys/webvh-signer.d.ts.map +1 -0
  80. package/dist/keys/webvh-signer.js +44 -0
  81. package/dist/keys/webvh-signer.js.map +1 -0
  82. package/dist/keys/webvh-update.d.ts +33 -0
  83. package/dist/keys/webvh-update.d.ts.map +1 -0
  84. package/dist/keys/webvh-update.js +62 -0
  85. package/dist/keys/webvh-update.js.map +1 -0
  86. package/dist/meta.d.ts +36 -11
  87. package/dist/meta.d.ts.map +1 -1
  88. package/dist/meta.js +95 -73
  89. package/dist/meta.js.map +1 -1
  90. package/dist/storage.d.ts +122 -13
  91. package/dist/storage.d.ts.map +1 -1
  92. package/dist/storage.js +105 -13
  93. package/dist/storage.js.map +1 -1
  94. package/dist/vc/issue.d.ts.map +1 -1
  95. package/dist/vc/issue.js +4 -7
  96. package/dist/vc/issue.js.map +1 -1
  97. package/dist/vc/verify.d.ts +10 -0
  98. package/dist/vc/verify.d.ts.map +1 -1
  99. package/dist/vc/verify.js +38 -1
  100. package/dist/vc/verify.js.map +1 -1
  101. package/dist/was/client.d.ts.map +1 -1
  102. package/dist/was/client.js +8 -2
  103. package/dist/was/client.js.map +1 -1
  104. package/dist/was/grant.d.ts +44 -0
  105. package/dist/was/grant.d.ts.map +1 -0
  106. package/dist/was/grant.js +78 -0
  107. package/dist/was/grant.js.map +1 -0
  108. package/dist/was/registry.d.ts +2 -1
  109. package/dist/was/registry.d.ts.map +1 -1
  110. package/dist/was/registry.js +25 -7
  111. package/dist/was/registry.js.map +1 -1
  112. package/dist/zcap/delegate.d.ts.map +1 -1
  113. package/dist/zcap/delegate.js +1 -6
  114. package/dist/zcap/delegate.js.map +1 -1
  115. package/dist/zcap/signer.d.ts.map +1 -1
  116. package/dist/zcap/signer.js.map +1 -1
  117. package/package.json +8 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,154 @@
1
1
  # History
2
2
 
3
+ ## 0.10.1 - 2026-06-26
4
+
5
+ ### Fixed
6
+
7
+ - `vc verify` now verifies credentials issued by `did:webvh` (and `did:web`)
8
+ issuers. Verification ran through `@interop/verifier-core`'s default document
9
+ loader, which resolves only `did:key` and `did:web`, so a `did:webvh` proof's
10
+ verification method could never be fetched and the signature was reported as
11
+ invalid. Verification now uses the CLI's shared loader (which registers the
12
+ `did:webvh` driver), passed through to `verifyCredential`.
13
+ - `vc issue --did` now accepts a metadata handle (not just a full DID id),
14
+ resolving it via the same lookup used by the other DID-referencing commands.
15
+ Previously passing a handle failed with a confusing `The "path" argument must
16
+ be of type string. Received undefined` error.
17
+
18
+ ### Changed
19
+
20
+ - The `list` / `show` / `meta` / `remove` subcommands and metadata handling of
21
+ the `vc`, `key`, and `zcap` command families now share a single
22
+ `src/commands/collection-command.ts` module (`runListCollection`,
23
+ `runMetaCollection`, `runRemoveCollection`, `resolveRefOrReport`,
24
+ `applyMetaEdits`, `requireSaveForMetaFlags`, and a unified `writeCreateMeta`),
25
+ replacing the near-identical clones previously copy-pasted across the three
26
+ files. `did`'s metadata edit and save-flag guard reuse the same helpers. No
27
+ behavior change.
28
+ - The `did` command file was split, mirroring `was/`: `src/commands/did.ts` now
29
+ holds only the `makeDidCommand()` wiring and delegates to `run*` functions in
30
+ `src/commands/did/` -- `create` (create / add-key), `service`
31
+ (add / remove-service), `manage` (get / show / list / meta / remove), and
32
+ `webvh-update` (the did:webvh log / update-key plumbing plus rotate-keys). The
33
+ in-`create` duplication was folded into shared `deriveSeed`,
34
+ `rejectSeedForNonDeterministic`, `resolveEcdsaCurveOrReport`, and
35
+ `printDidOutput` helpers (and a `DEFAULT_VERIFICATION_PURPOSES` constant), and
36
+ the `did.split(':')[1]` method-index idiom became `methodOf` in `storage.ts`.
37
+ No behavior change.
38
+ - All commands now share a single JSON-LD document loader (`src/documentLoader.ts`)
39
+ for DID resolution, DID-URL dereferencing, and context loading -- replacing the
40
+ per-module loaders previously built in `vc/issue`, `vc/verify` (none was passed
41
+ before), `edv/recipients`, `zcap/delegate`, and `commands/did`. The shared
42
+ loader resolves `did:key`, `did:web`, and `did:webvh`.
43
+ - `vc verify` prints a friendly `Cannot verify: ...` hint on stderr (stdout stays
44
+ machine-parseable JSON) when a proof's verification method uses a DID method the
45
+ loader has no driver for, distinguishing a loader misconfiguration from a
46
+ genuine invalid signature.
47
+ - Internal typing and consistency cleanups (no behavior change): the exported
48
+ key-pair shape is named once as `StoredKeyPair` in `storage.ts` (replacing the
49
+ three verbatim copies in `vc/issue`, `zcap/signer`, `was/client` and the inline
50
+ shapes in `storage`/`meta`); `loadMetaFromCollection` is generic over the
51
+ metadata type (so only the `keys` collection carries the key-specific `dids`
52
+ field); `loadFromCollection` / `saveToCollection` take an options object like
53
+ the rest of the storage helpers; `vc/issue` and `vc/verify` replace their
54
+ `as never` casts with typed ones; `edv/recipients` replaces `Record<string,
55
+ any>` with a named `VerificationMethodNode` type; `edv`'s encrypt functions
56
+ share an `EnvelopeOptions` type and a `resolveEncryptContextOrReport` wrapper;
57
+ and the `z6Mk` / `z6LS` multibase prefixes are named constants. Added the
58
+ file-level JSDoc header to `key.ts` and moved the `zcap revoke` stub message to
59
+ stderr.
60
+
61
+ ## 0.10.0 - 2026-06-25
62
+
63
+ ### Added
64
+
65
+ - `did show` now resolves a `did:webvh` DID from its stored history log
66
+ (`<did>.jsonl`) -- the source of truth -- rather than printing the saved
67
+ document snapshot, so the output reflects every appended log entry. With
68
+ `--meta` it also reports the parameters resolved from the log: version id,
69
+ last-updated time, portability, pre-rotation, deactivation status, and the
70
+ count of update keys, witnesses, and watchers (also included in
71
+ `--meta --json`). A `did:webvh` DID with no stored log still falls back to the
72
+ saved snapshot.
73
+ - Add `did add-service <did>` and `did remove-service <did>`, which add or
74
+ remove a [service](https://www.w3.org/TR/did-core/#services) entry on a stored
75
+ `did:web` or `did:webvh` DID (the DID may be given as a metadata handle).
76
+ `--id` accepts a bare fragment (expanded to `<did>#fragment`) or a full id;
77
+ the type comes from `--type` (repeatable) and the endpoint from either
78
+ `--endpoint` (repeatable) or `--endpoint-json` (a raw JSON value). For
79
+ `did:web` this edits the stored document in place; for `did:webvh` it appends
80
+ a sparse log entry that carries the update keys and document verification
81
+ methods forward unchanged -- except that, when pre-rotation is armed, the
82
+ update-key ratchet is advanced as part of the change (the staged key signs the
83
+ entry), with `--keep-old-key` and `-y` / `--yes` honored as in
84
+ `webvh rotate-keys`.
85
+ - Add richer create-time options to `did create webvh`, each declared in the
86
+ signed `did.jsonl` log `parameters`: `--portable` / `--no-portable` (portable
87
+ is the default -- a portable DID can later be moved to another domain),
88
+ `--witness <did...>` (repeatable; declare witness `did:key` DIDs authorized to
89
+ co-sign log entries) with `--witness-threshold <n>` (defaults to the number of
90
+ witnesses; requires `--witness`), and `--watcher <url...>` (repeatable;
91
+ `https://` or `http://localhost`). Witnesses are **declaration only** for now
92
+ -- generating witness proofs / a `did-witness.json` sidecar remains out of
93
+ scope.
94
+ - Add key **pre-rotation** to `did:webvh`. `did create webvh` now arms
95
+ pre-rotation by default: the DID commits, in advance, to the hash of the key
96
+ allowed to perform the next update, so a compromise of the active update key
97
+ cannot seize the DID. Update keys are now **decoupled** from the document's
98
+ verification key -- `create` generates an active update key A, a staged next
99
+ update key B (whose hash is committed as `nextKeyHashes`), and a separate
100
+ document key V (wired into the verification relationships as before). On
101
+ `--save`, V is stored in `<did>.keys.json` (keyed by its document
102
+ verification-method id, so it can be selected for signing) and A+B in a new
103
+ `<did>.update-keys.json` sidecar. Pass `--no-prerotation` to create without a
104
+ staged key. Requires `@interop/did-method-webvh` >= 3.2.0 (for the exported
105
+ `deriveNextKeyHash`).
106
+ - Add `did webvh rotate-keys <did>`, which rotates a stored `did:webvh` DID's
107
+ update (authorization) key and never touches the document's verification
108
+ methods. With no flags it advances the pre-rotation ratchet in one step --
109
+ revealing and activating the staged key, then staging a fresh one -- and
110
+ deletes the retired key's secret by default. Flags: `--stop-prerotation` (turn
111
+ pre-rotation off), `--enable-prerotation` (turn it on for a DID without it;
112
+ alone, stage only), `--update-key <multibase...>` (rotate to specific key(s)
113
+ in ordinary mode; rejected while pre-rotation is armed), `--keep-old-key`
114
+ (retain the retired secret), and `-y, --yes` (skip the confirmation prompt).
115
+ - Add `was space meta <space>`, which updates a registered space's local
116
+ registry metadata (`--handle` and/or `--description`) only, leaving the
117
+ server-side space untouched. At least one of the two flags is required;
118
+ passing an empty string (e.g. `--handle ''`) clears that field.
119
+
120
+ - Implement `did create webvh`, which creates a real did:webvh DID via the
121
+ `@interop/did-method-webvh` library (Ed25519 / `eddsa-jcs-2022` only for now;
122
+ `--type ecdsa` is rejected). Requires `--url` (passed as the DID's `address`)
123
+ and supports the same `--with-seed` / `--save` / `--handle` / `--description`
124
+ flags as the other methods. did:webvh is a two-part DID: on `--save`, the
125
+ resolved DID document, keys, and metadata are written as usual under
126
+ `dids/webvh/`, plus the signed `did.jsonl` history log as a raw
127
+ newline-delimited `<did>.jsonl` file alongside them; `did remove` deletes the
128
+ log too. The generated DID is portable, and its single Ed25519 key is wired
129
+ into the same verification relationships as did:web (`authentication`,
130
+ `assertionMethod`, `capabilityDelegation`, `capabilityInvocation`; not
131
+ `keyAgreement`). Requires `@interop/did-method-webvh` >= 3.1.0. Resolving a
132
+ stored webvh DID, witnesses, and the parallel did:web alias are deferred.
133
+ (Update-key rotation and pre-rotation are implemented separately below.)
134
+ - Support `did get`/`did resolve` for `did:webvh` DIDs. A `did:webvh` driver
135
+ (`src/keys/webvh-driver.ts`) wraps `resolveDID` from
136
+ `@interop/did-method-webvh` -- fetching and verifying the DID's history log --
137
+ and is registered onto the security document loader's resolver via the new
138
+ injectable `securityLoader({ didResolver })` seam, so the `did:webvh`
139
+ dependency stays out of the shared loader. A bare DID resolves to its DID
140
+ document; a `did#fragment` URL is dereferenced to its verification method.
141
+ Requires `@interop/security-document-loader` >= 9.4.0.
142
+
143
+ ### Changed
144
+
145
+ - Update to `@interop/did-method-webvh` >= 3.3.0. `updateDID` now performs a
146
+ sparse update -- it carries the prior DID document state forward and overlays
147
+ only the fields an update actually supplies -- so `did webvh rotate-keys` no
148
+ longer reconstructs and re-supplies the document's verification methods to
149
+ keep them unchanged; the key-only rotation simply omits all document
150
+ directives.
151
+
3
152
  ## 0.9.0 - 2026-06-14
4
153
 
5
154
  ### Added
package/README.md CHANGED
@@ -453,6 +453,164 @@ seed-derivable, so `--with-seed` is not supported with `--type ecdsa` or
453
453
  ./di did add-key did:web:example.com --with-seed
454
454
  ```
455
455
 
456
+ #### Create a did:webvh DID
457
+
458
+ Generate a `did:webvh` DID. Like `did:web` it is tied to a domain, so `--url`
459
+ (the HTTPS url that will host the DID's history log) is required:
460
+
461
+ ```
462
+ ./di did create webvh --url https://example.com
463
+ {
464
+ "id": "did:webvh:Qm...:example.com",
465
+ "didDocument": { ... }
466
+ }
467
+ ```
468
+
469
+ `did:webvh` separates two key roles: an **update (authorization) key** that
470
+ signs entries in the DID's append-only history log, and the **document
471
+ verification key** wired into the `authentication`, `assertionMethod`,
472
+ `capabilityDelegation`, and `capabilityInvocation` relationships. They are
473
+ distinct keys, so the update key can be rotated without ever disturbing the
474
+ document.
475
+
476
+ By default `did:webvh` arms **key pre-rotation**: the DID commits, in advance,
477
+ to the *hash* of the key allowed to perform the next update. A compromise of the
478
+ currently active update key cannot be used to seize the DID, because the
479
+ attacker still does not hold the pre-committed next key. So `create` generates
480
+ three keys: the active update key, a staged next update key (whose hash is
481
+ committed as `nextKeyHashes`), and the document key. Pass `--no-prerotation` to
482
+ create the DID without pre-rotation (no next key is staged):
483
+
484
+ ```
485
+ ./di did create webvh --url https://example.com --no-prerotation
486
+ ```
487
+
488
+ Save the DID document, history log, and key material to local storage with
489
+ `--save` (written to `~/.config/did-cli-wallet/dids/webvh/` by default, or
490
+ `$DIDS_DIR` if set). The document key is stored in `<did>.keys.json`; the update
491
+ keys (active, and the staged next key when pre-rotation is on) are stored in a
492
+ separate `<did>.update-keys.json` sidecar, and the signed history log in
493
+ `<did>.jsonl`:
494
+
495
+ ```
496
+ ./di did create webvh --url https://example.com --save
497
+ DID saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.json
498
+ DID history log saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.jsonl
499
+ Update keys saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.update-keys.json
500
+ {
501
+ "id": "did:webvh:Qm...:example.com",
502
+ "didDocument": { ... }
503
+ }
504
+ ```
505
+
506
+ Only Ed25519 update keys are supported (the `eddsa-jcs-2022` cryptosuite the
507
+ method uses requires them), so `--type ecdsa` is rejected.
508
+
509
+ A few more create-time options are recorded in the signed history-log
510
+ `parameters`:
511
+
512
+ - `--portable` / `--no-portable` -- a **portable** DID (the default) can later
513
+ be moved to a different domain; `--no-portable` pins it to its origin.
514
+ - `--witness <did...>` -- declare one or more **witness** `did:key` DIDs
515
+ authorized to co-sign the DID's log entries (repeatable). `--witness-threshold
516
+ <n>` sets how many witness approvals are required (defaults to the number of
517
+ witnesses; it requires `--witness`). This only *declares* the witnesses;
518
+ actually generating witness proofs is not yet supported.
519
+ - `--watcher <url...>` -- declare one or more **watcher** URLs that monitor the
520
+ DID's log (repeatable; `https://`, or `http://localhost` for local testing).
521
+
522
+ ```
523
+ ./di did create webvh --url https://example.com \
524
+ --witness did:key:z6Mk... --witness did:key:z6Mk... --witness-threshold 1 \
525
+ --watcher https://watcher.example.com --save
526
+ ```
527
+
528
+ #### Rotate a did:webvh update key
529
+
530
+ Rotate the update (authorization) key of a locally stored `did:webvh` DID with
531
+ `did webvh rotate-keys`. This appends a new entry to the DID's history log and
532
+ **never touches the document's verification methods** (those are separate keys).
533
+
534
+ With no flags it advances the pre-rotation ratchet in one step: it reveals and
535
+ activates the previously staged next key (signing the new entry with it), and
536
+ stages a fresh next key for the following rotation. The retired update key's
537
+ secret is deleted by default -- a retired key is only ever needed to *verify*
538
+ historic log entries, which uses the public key from the log, not the secret:
539
+
540
+ ```
541
+ ./di did webvh rotate-keys did:webvh:Qm...:example.com
542
+ DID document saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.json
543
+ DID history log saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.jsonl
544
+ Update keys saved to /home/user/.config/did-cli-wallet/dids/webvh/did:webvh:Qm...:example.com.update-keys.json
545
+ Pre-rotation is armed: a next update key is staged.
546
+ {
547
+ "id": "did:webvh:Qm...:example.com",
548
+ "didDocument": { ... }
549
+ }
550
+ ```
551
+
552
+ Pre-rotation requires the staged key to sign its own activation, so the staged
553
+ secret in `<did>.update-keys.json` is what makes the next rotation possible --
554
+ losing it means the DID can never be updated again. Keep that sidecar backed up.
555
+
556
+ Flags:
557
+
558
+ - `--stop-prerotation` -- rotate but commit no next-key hash; pre-rotation turns
559
+ **off** after this entry.
560
+ - `--enable-prerotation` -- for a DID with pre-rotation currently off, turn it
561
+ **on** by staging a next key. Alone it stages only (the active key is
562
+ unchanged, signed by the current key).
563
+ - `--update-key <multibase...>` -- in ordinary (non-pre-rotation) mode, rotate
564
+ to specific update key(s) by public key instead of generating a fresh one.
565
+ Rejected while pre-rotation is armed, where the next keys are fixed by the
566
+ prior commitment.
567
+ - `--keep-old-key` -- retain the retired update key's secret in the sidecar
568
+ instead of dropping it.
569
+ - `-y`, `--yes` -- skip the confirmation prompt (rotation is hard to undo).
570
+
571
+ #### Add or remove a service entry
572
+
573
+ Add or remove a [service](https://www.w3.org/TR/did-core/#services) entry on a
574
+ locally stored `did:web` or `did:webvh` DID. The DID may be given as a full DID
575
+ or a metadata handle. For `did:web` this edits the stored document in place; for
576
+ `did:webvh` it appends a new entry to the history log.
577
+
578
+ ```
579
+ ./di did add-service did:web:example.com \
580
+ --id files --type LinkedDomains --endpoint https://example.com
581
+ {
582
+ "id": "did:web:example.com",
583
+ "didDocument": { ..., "service": [ ... ] }
584
+ }
585
+ ```
586
+
587
+ `--id` accepts a bare fragment (`files`), which is expanded to `<did>#files`, or
588
+ a full service id. The service type comes from `--type` (repeat for multiple
589
+ types). The endpoint comes from either `--endpoint` (repeat for multiple values;
590
+ a single value stays a string, several become an array) or `--endpoint-json` (a
591
+ raw JSON value, e.g. an object); exactly one of the two is required.
592
+
593
+ ```
594
+ ./di did add-service did:web:example.com \
595
+ --id dwn --type DecentralizedWebNode \
596
+ --endpoint-json '{"nodes":["https://dwn.example"]}'
597
+ ```
598
+
599
+ Remove a service by its id (a bare fragment is expanded the same way):
600
+
601
+ ```
602
+ ./di did remove-service did:web:example.com --id files
603
+ ```
604
+
605
+ For `did:webvh`, both commands sign and append a log entry (and so accept `-y` /
606
+ `--yes` to skip the confirmation prompt). The update keys and document
607
+ verification methods are carried forward unchanged -- with one exception: when
608
+ pre-rotation is armed the library requires the staged key to sign the entry, so
609
+ the update-key ratchet is **advanced** as part of the change (the staged key is
610
+ revealed and activated, and a fresh next key is staged), exactly as in
611
+ `webvh rotate-keys`. Pass `--keep-old-key` to retain the retired update key's
612
+ secret in that case.
613
+
456
614
  #### List DIDs
457
615
 
458
616
  List the DIDs saved in local storage (via `did create --save`) as a table of
@@ -492,7 +650,8 @@ did:key:z6Mks...
492
650
 
493
651
  Resolve a DID to its DID document through the security document loader. Unlike
494
652
  `did show` (which reads local storage), `did get` resolves live: did:key is
495
- resolved offline, did:web is fetched over HTTPS. Pass a DID URL (a
653
+ resolved offline, did:web is fetched over HTTPS, and did:webvh is resolved by
654
+ fetching and verifying its history log over HTTPS. Pass a DID URL (a
496
655
  `did#fragment` key id) to dereference straight to its verification method:
497
656
 
498
657
  ```
@@ -534,6 +693,11 @@ printed as-is:
534
693
 
535
694
  Aliases: `view`, `cat`.
536
695
 
696
+ For a `did:webvh` DID the document is **resolved from its stored history log**
697
+ (`<did>.jsonl`) -- the source of truth -- rather than the saved snapshot, so the
698
+ output reflects every appended log entry. If no log is stored the saved snapshot
699
+ is shown instead.
700
+
537
701
  Pass `--meta` to show the DID's metadata instead of the DID document:
538
702
 
539
703
  ```
@@ -548,7 +712,29 @@ Description
548
712
  Keys 1
549
713
  ```
550
714
 
551
- `--meta --json` prints the same metadata as a JSON object.
715
+ For a `did:webvh` DID, `--meta` also reports the parameters resolved from the
716
+ log -- the current version id, last-updated time, portability, pre-rotation,
717
+ deactivation status, and the number of update keys, witnesses, and watchers:
718
+
719
+ ```
720
+ ./di did show my-webvh --meta
721
+ FIELD VALUE
722
+ ----------- ----------------------------------------------
723
+ DID did:webvh:Qm...:example.com
724
+ Method webvh
725
+ ...
726
+ Version 1-Qm...
727
+ Updated 2026-06-10T17:22:31Z
728
+ Portable yes
729
+ Prerotation yes
730
+ Deactivated no
731
+ Update keys 1
732
+ Witnesses 0
733
+ Watchers 0
734
+ ```
735
+
736
+ `--meta --json` prints the same metadata as a JSON object (the `did:webvh`
737
+ fields are included there too).
552
738
 
553
739
  #### Edit DID metadata
554
740
 
@@ -1146,8 +1332,10 @@ the server, or the local registry record with `--meta`:
1146
1332
  `was space update` (alias: `configure`) upserts description fields
1147
1333
  (`--name`), also refreshing the registry entry. `was space add` registers an
1148
1334
  *existing* remote space (a full space URL, or a bare id plus `--server`) in
1149
- the local registry, verifying it with a describe first. The local/remote
1150
- delete pair:
1335
+ the local registry, verifying it with a describe first. `was space meta
1336
+ <space>` updates only a registered space's local metadata (`--handle` and/or
1337
+ `--description`); the server-side space is untouched, and passing an empty
1338
+ string (`--handle ''`) clears that field. The local/remote delete pair:
1151
1339
 
1152
1340
  - `was space delete <space>` (alias: `rm`) deletes the space **on the
1153
1341
  server** (idempotent) and removes the registry entry;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Shared helpers for the wallet "collection" command families (`vc`, `key`,
3
+ * and `zcap`), whose `list` / `show` / `meta` / `remove` subcommands and
4
+ * metadata handling are otherwise near-identical clones. Each command file
5
+ * declares its collection name and supplies the per-collection projection
6
+ * (how to load an item, turn it into a table row / JSON object, and resolve a
7
+ * reference); the control flow -- plain/json/empty/table listing, the
8
+ * set-or-clear metadata edits, and the resolve-then-validate preamble -- lives
9
+ * here once.
10
+ */
11
+ import { type ItemMetadata, type KeyMetadata } from '../storage.js';
12
+ import { type Column } from '../table.js';
13
+ /**
14
+ * Guards the `--handle` / `--description` metadata flags against being given
15
+ * without `--save`. Prints the standard message to stderr and returns false
16
+ * when the combination is invalid; the caller chooses the exit code.
17
+ *
18
+ * @param options {object}
19
+ * @param [options.save] {boolean}
20
+ * @param [options.handle] {string}
21
+ * @param [options.description] {string}
22
+ * @returns {boolean} true when the flags are valid.
23
+ */
24
+ export declare function requireSaveForMetaFlags({ save, handle, description }: {
25
+ save?: boolean;
26
+ handle?: string;
27
+ description?: string;
28
+ }): boolean;
29
+ /**
30
+ * Apply the `--handle` / `--description` set-or-clear edits to a metadata
31
+ * object in place: a defined non-empty value sets the field, an empty string
32
+ * clears it, and an undefined value leaves it untouched.
33
+ *
34
+ * @param meta {ItemMetadata} The metadata object to mutate.
35
+ * @param edits {object}
36
+ * @param [edits.handle] {string}
37
+ * @param [edits.description] {string}
38
+ * @returns {void}
39
+ */
40
+ export declare function applyMetaEdits(meta: ItemMetadata, { handle, description }: {
41
+ handle?: string;
42
+ description?: string;
43
+ }): void;
44
+ /**
45
+ * Write the `.meta.json` metadata sidecar of a freshly saved wallet item: the
46
+ * creation timestamp plus the handle and description when given. When
47
+ * `mergeExisting` is set, any existing sidecar is loaded first and its fields
48
+ * take precedence over `created` (so re-saving an already-stored item keeps
49
+ * its original timestamp) -- used by `vc import` / `vc issue --save`, which may
50
+ * re-store a credential that is already in the wallet.
51
+ *
52
+ * @param options {object}
53
+ * @param options.collection {string}
54
+ * @param options.storageId {string}
55
+ * @param options.created {string}
56
+ * @param [options.handle] {string}
57
+ * @param [options.description] {string}
58
+ * @param [options.mergeExisting] {boolean}
59
+ * @returns {Promise<void>}
60
+ */
61
+ export declare function writeCreateMeta({ collection, storageId, created, handle, description, mergeExisting }: {
62
+ collection: string;
63
+ storageId: string;
64
+ created: string;
65
+ handle?: string;
66
+ description?: string;
67
+ mergeExisting?: boolean;
68
+ }): Promise<void>;
69
+ /**
70
+ * Resolve a wallet item reference, reporting failures to stderr and returning
71
+ * undefined: prints the thrown error message on an ambiguous handle, or the
72
+ * standard "No locally stored <noun> found for <ref>" message when nothing
73
+ * matches. Collapses the resolve-then-validate preamble shared by the
74
+ * `show` / `meta` / `remove` subcommands; callers do `if (!resolved) return 1`.
75
+ *
76
+ * @param options {object}
77
+ * @param options.resolve {(ref: string) => Promise<T | undefined>}
78
+ * @param options.ref {string}
79
+ * @param options.noun {string} The item noun for the not-found message.
80
+ * @returns {Promise<T | undefined>}
81
+ */
82
+ export declare function resolveRefOrReport<T>({ resolve, ref, noun }: {
83
+ resolve: (ref: string) => Promise<T | undefined>;
84
+ ref: string;
85
+ noun: string;
86
+ }): Promise<T | undefined>;
87
+ /**
88
+ * Render a wallet collection listing: one id per line with `plain`, a JSON
89
+ * array with `json`, an empty result as no output, otherwise a column-aligned
90
+ * table. Shared by `vc list`, `key list`, and `zcap list`; each caller
91
+ * supplies how to load an item, project it to a row / JSON object, and the
92
+ * table columns. A `toEntry` returning undefined drops the item from the
93
+ * non-plain output (e.g. an id-less zcap).
94
+ *
95
+ * @param options {object}
96
+ * @param options.collection {string}
97
+ * @param [options.plain] {boolean}
98
+ * @param [options.json] {boolean}
99
+ * @param options.plainId {(item: Item, storageId: string) => string | undefined}
100
+ * The id to print in `--plain` mode; undefined skips the item.
101
+ * @param options.toEntry {(args: {storageId: string, item: Item, meta?: KeyMetadata}) => Entry | undefined | Promise<Entry | undefined>}
102
+ * @param options.toJson {(entry: Entry) => object}
103
+ * @param options.columns {Column[]}
104
+ * @param options.toRow {(entry: Entry) => string[]}
105
+ * @returns {Promise<number>} The process exit code.
106
+ */
107
+ export declare function runListCollection<Item, Entry>({ collection, plain, json, plainId, toEntry, toJson, columns, toRow }: {
108
+ collection: string;
109
+ plain?: boolean;
110
+ json?: boolean;
111
+ plainId: (item: Item, storageId: string) => string | undefined;
112
+ toEntry: (args: {
113
+ storageId: string;
114
+ item: Item;
115
+ meta?: KeyMetadata;
116
+ }) => Entry | undefined | Promise<Entry | undefined>;
117
+ toJson: (entry: Entry) => object;
118
+ columns: Column[];
119
+ toRow: (entry: Entry) => string[];
120
+ }): Promise<number>;
121
+ /**
122
+ * Show or edit the metadata of a wallet item (by id or handle): with no
123
+ * `--handle` / `--description` edits, prints the current metadata; otherwise
124
+ * applies the set-or-clear edits, saves the sidecar, and prints the result.
125
+ * Shared by `vc meta` and `zcap meta`. (`key meta` keeps its own runner: it
126
+ * additionally backfills the created date and refreshes the cached DID
127
+ * associations.)
128
+ *
129
+ * @param options {object}
130
+ * @param options.collection {string}
131
+ * @param options.noun {string}
132
+ * @param options.resolve {(ref: string) => Promise<{storageId: string, meta?: ItemMetadata} | undefined>}
133
+ * @param options.ref {string}
134
+ * @param [options.handle] {string}
135
+ * @param [options.description] {string}
136
+ * @returns {Promise<number>} The process exit code.
137
+ */
138
+ export declare function runMetaCollection({ collection, noun, resolve, ref, handle, description }: {
139
+ collection: string;
140
+ noun: string;
141
+ resolve: (ref: string) => Promise<{
142
+ storageId: string;
143
+ meta?: ItemMetadata;
144
+ } | undefined>;
145
+ ref: string;
146
+ handle?: string;
147
+ description?: string;
148
+ }): Promise<number>;
149
+ /**
150
+ * Resolve a wallet item by reference and remove it (and its metadata sidecar),
151
+ * printing each removed file path to stderr. Shared by `vc remove`,
152
+ * `key remove`, and `zcap remove`.
153
+ *
154
+ * @param options {object}
155
+ * @param options.collection {string}
156
+ * @param options.noun {string}
157
+ * @param options.resolve {(ref: string) => Promise<{storageId: string} | undefined>}
158
+ * @param options.ref {string}
159
+ * @returns {Promise<number>} The process exit code.
160
+ */
161
+ export declare function runRemoveCollection({ collection, noun, resolve, ref }: {
162
+ collection: string;
163
+ noun: string;
164
+ resolve: (ref: string) => Promise<{
165
+ storageId: string;
166
+ } | undefined>;
167
+ ref: string;
168
+ }): Promise<number>;
169
+ //# sourceMappingURL=collection-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-command.d.ts","sourceRoot":"","sources":["../../src/commands/collection-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAe,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAEtD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAI,EACJ,MAAM,EACN,WAAW,EACZ,EAAE;IACD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAMV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,IAAI,CAeN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,EACpC,UAAU,EACV,SAAS,EACT,OAAO,EACP,MAAM,EACN,WAAW,EACX,aAAa,EACd,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYhB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,EAC1C,OAAO,EACP,GAAG,EACH,IAAI,EACL,EAAE;IACD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAA;IAChD,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAazB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,EACnD,UAAU,EACV,KAAK,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,KAAK,EACN,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAC9D,OAAO,EAAE,CAAC,IAAI,EAAE;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,IAAI,CAAA;QACV,IAAI,CAAC,EAAE,WAAW,CAAA;KACnB,KAAK,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAA;IACpD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAA;IAChC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,EAAE,CAAA;CAClC,GAAG,OAAO,CAAC,MAAM,CAAC,CAyClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,UAAU,EACV,IAAI,EACJ,OAAO,EACP,GAAG,EACH,MAAM,EACN,WAAW,EACZ,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CACP,GAAG,EAAE,MAAM,KACR,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,YAAY,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;IACpE,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CAAC,EACxC,UAAU,EACV,IAAI,EACJ,OAAO,EACP,GAAG,EACJ,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;IACpE,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAalB"}