@interop/did-cli 0.13.0 → 0.15.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 (102) hide show
  1. package/CHANGELOG.md +166 -6
  2. package/README.md +172 -26
  3. package/dist/commands/did/create.d.ts +22 -0
  4. package/dist/commands/did/create.d.ts.map +1 -1
  5. package/dist/commands/did/create.js +6 -27
  6. package/dist/commands/did/create.js.map +1 -1
  7. package/dist/commands/did/service.d.ts +19 -4
  8. package/dist/commands/did/service.d.ts.map +1 -1
  9. package/dist/commands/did/service.js +46 -45
  10. package/dist/commands/did/service.js.map +1 -1
  11. package/dist/commands/did/webvh-update.d.ts +72 -9
  12. package/dist/commands/did/webvh-update.d.ts.map +1 -1
  13. package/dist/commands/did/webvh-update.js +177 -61
  14. package/dist/commands/did/webvh-update.js.map +1 -1
  15. package/dist/commands/did.d.ts.map +1 -1
  16. package/dist/commands/did.js +10 -1
  17. package/dist/commands/did.js.map +1 -1
  18. package/dist/commands/key.d.ts.map +1 -1
  19. package/dist/commands/key.js +5 -8
  20. package/dist/commands/key.js.map +1 -1
  21. package/dist/commands/was/request-grant.d.ts +39 -0
  22. package/dist/commands/was/request-grant.d.ts.map +1 -0
  23. package/dist/commands/was/request-grant.js +250 -0
  24. package/dist/commands/was/request-grant.js.map +1 -0
  25. package/dist/commands/was/resource.d.ts +21 -7
  26. package/dist/commands/was/resource.d.ts.map +1 -1
  27. package/dist/commands/was/resource.js +40 -15
  28. package/dist/commands/was/resource.js.map +1 -1
  29. package/dist/commands/was/shared.d.ts +43 -3
  30. package/dist/commands/was/shared.d.ts.map +1 -1
  31. package/dist/commands/was/shared.js +82 -4
  32. package/dist/commands/was/shared.js.map +1 -1
  33. package/dist/commands/was/shell/completer.d.ts +24 -0
  34. package/dist/commands/was/shell/completer.d.ts.map +1 -0
  35. package/dist/commands/was/shell/completer.js +99 -0
  36. package/dist/commands/was/shell/completer.js.map +1 -0
  37. package/dist/commands/was/shell/dispatcher.d.ts +27 -0
  38. package/dist/commands/was/shell/dispatcher.d.ts.map +1 -0
  39. package/dist/commands/was/shell/dispatcher.js +227 -0
  40. package/dist/commands/was/shell/dispatcher.js.map +1 -0
  41. package/dist/commands/was/shell/session.d.ts +37 -0
  42. package/dist/commands/was/shell/session.d.ts.map +1 -0
  43. package/dist/commands/was/shell/session.js +67 -0
  44. package/dist/commands/was/shell/session.js.map +1 -0
  45. package/dist/commands/was/shell/tokenize.d.ts +19 -0
  46. package/dist/commands/was/shell/tokenize.d.ts.map +1 -0
  47. package/dist/commands/was/shell/tokenize.js +77 -0
  48. package/dist/commands/was/shell/tokenize.js.map +1 -0
  49. package/dist/commands/was/shell.d.ts +30 -0
  50. package/dist/commands/was/shell.d.ts.map +1 -0
  51. package/dist/commands/was/shell.js +170 -0
  52. package/dist/commands/was/shell.js.map +1 -0
  53. package/dist/commands/was/tree.d.ts +6 -1
  54. package/dist/commands/was/tree.d.ts.map +1 -1
  55. package/dist/commands/was/tree.js +12 -5
  56. package/dist/commands/was/tree.js.map +1 -1
  57. package/dist/commands/was.d.ts.map +1 -1
  58. package/dist/commands/was.js +34 -1
  59. package/dist/commands/was.js.map +1 -1
  60. package/dist/commands/zcap.d.ts +22 -2
  61. package/dist/commands/zcap.d.ts.map +1 -1
  62. package/dist/commands/zcap.js +75 -4
  63. package/dist/commands/zcap.js.map +1 -1
  64. package/dist/keys/seed.d.ts +21 -0
  65. package/dist/keys/seed.d.ts.map +1 -0
  66. package/dist/keys/seed.js +41 -0
  67. package/dist/keys/seed.js.map +1 -0
  68. package/dist/keys/webvh-signer.d.ts +18 -13
  69. package/dist/keys/webvh-signer.d.ts.map +1 -1
  70. package/dist/keys/webvh-signer.js +5 -20
  71. package/dist/keys/webvh-signer.js.map +1 -1
  72. package/dist/storage.d.ts.map +1 -1
  73. package/dist/storage.js +57 -10
  74. package/dist/storage.js.map +1 -1
  75. package/dist/was/address.d.ts +24 -0
  76. package/dist/was/address.d.ts.map +1 -1
  77. package/dist/was/address.js +49 -3
  78. package/dist/was/address.js.map +1 -1
  79. package/dist/was/capability.d.ts.map +1 -1
  80. package/dist/was/capability.js +4 -1
  81. package/dist/was/capability.js.map +1 -1
  82. package/dist/was/client.d.ts +10 -3
  83. package/dist/was/client.d.ts.map +1 -1
  84. package/dist/was/client.js +27 -6
  85. package/dist/was/client.js.map +1 -1
  86. package/dist/was/request-grant.d.ts +147 -0
  87. package/dist/was/request-grant.d.ts.map +1 -0
  88. package/dist/was/request-grant.js +256 -0
  89. package/dist/was/request-grant.js.map +1 -0
  90. package/dist/zcap/create.d.ts +1 -1
  91. package/dist/zcap/create.js +1 -1
  92. package/dist/zcap/delegate.d.ts +1 -1
  93. package/dist/zcap/delegate.js +1 -1
  94. package/dist/zcap/encoding.d.ts +17 -5
  95. package/dist/zcap/encoding.d.ts.map +1 -1
  96. package/dist/zcap/encoding.js +31 -17
  97. package/dist/zcap/encoding.js.map +1 -1
  98. package/dist/zcap/resolve.d.ts +17 -4
  99. package/dist/zcap/resolve.d.ts.map +1 -1
  100. package/dist/zcap/resolve.js +25 -8
  101. package/dist/zcap/resolve.js.map +1 -1
  102. package/package.json +22 -20
package/CHANGELOG.md CHANGED
@@ -1,5 +1,165 @@
1
1
  # History
2
2
 
3
+ ## 0.15.0 - 2026-09-14
4
+
5
+ ### Added
6
+
7
+ - `was request-grant` accepts an explicit `--save` (the default), so the
8
+ documented `--save --handle agent` invocation no longer fails with
9
+ "unknown option".
10
+ - An integration test for `was request-grant` against the WAS server's
11
+ ephemeral-exchange facet, with a scripted wallet that opens the interaction
12
+ URL, delegates the public collection from the space controller's key, and
13
+ posts the response presentation back. It then publishes `index.html`
14
+ through the stored handle and fetches it anonymously as `text/html`.
15
+ - `zcap import <capability>` validates a capability received outside the CLI
16
+ (a multibase `u...` string or a JSON file) and stores it, with optional
17
+ `--handle` / `--description`, so `--capability <handle>` can name it. It
18
+ refuses a capability whose id is already stored or a handle already in use.
19
+
20
+ ### Fixed
21
+
22
+ - The `--wallet` deep link now carries the route and the `url` parameter in
23
+ the URL fragment (`<wallet>/#/external/request?url=<interaction url>`).
24
+ Freewallet routes on the fragment, so the earlier path form opened the
25
+ landing page instead of the approval page.
26
+
27
+ ### Changed
28
+
29
+ - `@interop/zcap` is at `^11.3.0`, which exports the `checkCapability`
30
+ validator used by `zcap import`.
31
+ - BREAKING: `was request-grant` takes the exchange host as `--exchange <url>`
32
+ instead of `--server <url>`. The flag only names the WAS server that hosts
33
+ the ephemeral exchange; the granted capability targets whichever space the
34
+ wallet picks. `WAS_SERVER_URL` remains the fallback.
35
+ - BREAKING: the `encoded` form of a capability (printed by `zcap create`,
36
+ `zcap delegate`, `was grant`, and `was request-grant`) is now multibase
37
+ base64url (`u...`) instead of base58btc (`z...`); the `z` form is no longer
38
+ accepted by `--capability`. base58 is quadratic in the input size and
39
+ `@scure/base` refuses it past 2048 bytes, which a wallet-delegated
40
+ capability exceeds once it embeds its chain; `was request-grant` failed
41
+ after saving such a grant.
42
+ - The `was` commands run was-client's service discovery against a space-owned
43
+ URL (the capability's invocation target, or the addressed space) instead of
44
+ the server origin, so a deployment whose origin serves a static page with
45
+ no service link (such as freewallet.cloud) still resolves.
46
+ - Bumped `@interop/was-client` to `^0.64.0`. The Space root capability id is
47
+ now the canonical trailing-slash container URL and signed requests run
48
+ service discovery first, which was-teaching-server 0.33 and later require;
49
+ against those servers the previous client's delegated invocations were
50
+ refused as 404.
51
+
52
+ ## 0.14.0 - 2026-09-14
53
+
54
+ ### Added
55
+
56
+ - `was request-grant` -- the requesting side of capability delegation, the
57
+ inverse of `was grant`. It mints an Ed25519 `did:key` for itself, asks a
58
+ user's wallet for a capability on one of its public collections, prints an
59
+ approval link for the user to open, waits for their answer, and files the
60
+ received capability in the zcap store. The grantee key is minted by the
61
+ command rather than passed in, so a caller driving the CLI never handles key
62
+ material: stdout carries the capability (or, with `--json`, one object holding
63
+ the DID, the handle, the link, and the capability), and the approval link and
64
+ progress notes go to stderr. The key is written only once the grant arrives,
65
+ and a handle already taken by a stored DID or capability is refused up front,
66
+ so handle lookups stay unambiguous across runs. Options are
67
+ `--collection` (default `web`), `--action` (default `GET HEAD PUT POST`),
68
+ `--reason`, `--timeout` (default 600 seconds, the server's exchange
69
+ lifetime), `--handle` (default `agent`), `--description`, `--no-save`,
70
+ `--json`, and `--server`. Persistence is on by default because
71
+ `--capability` resolves its signer out of the local DID store, so a key held
72
+ only for the run cannot sign the write that follows; `--no-save` prints the
73
+ capability without keeping either half. The request carries a single
74
+ `AuthorizationCapabilityQuery` naming a public-collection descriptor, with no
75
+ `DIDAuthentication` query and no `domain`.
76
+
77
+ - `was request-grant --name <name>` sends the agent's self-declared display
78
+ name (the VPR's root `agent: { name }` member, wallet-core 0.53.0), shown on
79
+ the wallet consent screen as what the agent calls itself; at most 64
80
+ characters, no control characters.
81
+
82
+ - `was request-grant --wallet <url>` also prints a link that opens the given
83
+ wallet straight onto its approval page for the exchange
84
+ (`<wallet>/external/request?url=<interaction url>`). The interaction URL is
85
+ still printed, for a wallet on another device. The wallet URL must be
86
+ absolute http(s), and a bad one is refused before any exchange is opened.
87
+
88
+ - `--resource <id>` on `was get`, `was put`, `was meta get`, `was meta put`,
89
+ and `was rm`: names one resource beneath a collection-scoped
90
+ `--capability`, so a grant issued on a whole collection can read, write,
91
+ and delete at a caller-chosen id. `resource add` also takes a collection
92
+ capability, but the server picks the id there. The resource handle inherits
93
+ the collection's bound capability, so the request stays an invocation of
94
+ the received grant. `--resource` without a capability, or alongside a
95
+ capability that already targets a resource, is an input error.
96
+ - A `publish-page` Claude Code skill (`.claude/skills/publish-page/`) and the
97
+ agent storage demo it scripts (`demo/agent-storage/README.md`): an LLM agent
98
+ drafts an `index.html`, asks the user's wallet for a grant on a public
99
+ collection with `was request-grant`, and publishes the page through the
100
+ delegated capability. The skill is model-invoked, states that `--save` is
101
+ required (a key held only for the run cannot sign the write that follows),
102
+ keeps the agent away from key material, and sends a user with no wallet
103
+ account to `<wallet>/signup` before resuming.
104
+
105
+ - `was shell` -- an interactive REPL over the `was` command tree. Start it with
106
+ `di was shell [path]` (`--server`/`--did` seed the session defaults), then run
107
+ any `was` subcommand without re-typing space handles or re-paying the
108
+ cold-start cost. A "current directory" (`cd`/`use`, with `..`, `/`, relative
109
+ paths, and full space URLs) makes every command's path relative to it, and
110
+ `pwd`, `connect <url>`, `did <ref>`, `help`, and `exit`/`quit` round out the
111
+ builtins. Tab completion covers builtins, subcommands, and registered space
112
+ handles. The prompt and diagnostics go to stderr while command data stays on
113
+ stdout, so `di was shell < script` keeps a pipe-clean stdout.
114
+
115
+ ### Changed
116
+
117
+ - Update to latest d-i-core, verifier-core, was-client and didwebvh deps.
118
+ - Added `@interop/wallet-request` as a dependency, for the ephemeral-exchange
119
+ create and poll helpers `was request-grant` transports over, and for the
120
+ zcap-only presentation-request composer it sends (moved there from
121
+ wallet-core's `request` subpath).
122
+ - `did webvh rotate-keys` and `did service add|remove` now pass the
123
+ already-resolved log state to `updateDID` as `priorMeta`, so each update
124
+ verifies the history log once instead of twice. The pairing between the log
125
+ and its resolved metadata is now asserted (O(1)) before signing.
126
+ - `did webvh rotate-keys` edits the authorized `updateKeys` set instead of
127
+ rebuilding it from the single local key: a stage-only `--enable-prerotation`
128
+ leaves the set unchanged, and an ordinary rotation replaces only the retired
129
+ key, so co-authorized update keys are no longer silently revoked.
130
+ - `rotate-keys --update-key` now authorizes every supplied key instead of
131
+ silently dropping all but the first.
132
+ - did:webvh updates persist crash-safely: the update-keys sidecar (including
133
+ the superseded secret) is written before the log that authorizes the new
134
+ key, and the signer loaders can recover from a rotation interrupted between
135
+ the two writes.
136
+ - Stored artifacts (DID documents, history logs, sidecars, wallet items) are
137
+ written atomically (temp file + rename), so an interrupted write can no
138
+ longer leave a truncated file.
139
+ - Stored artifacts are now written with mode `0600` (owner read/write only)
140
+ instead of the ambient umask default, since keys are held as plaintext
141
+ Multikey documents. Wallet and DID directories are created with mode `0700`,
142
+ since a DID document is named after its DID. Existing files are not
143
+ migrated.
144
+ - The atomic-write temp file is unlinked and reopened with `wx` rather than
145
+ chmod-ed after the write, so a temp file left behind by an interrupted run
146
+ cannot receive a secret at its own wider mode.
147
+ - Confirmation prompts no longer auto-confirm when stdin is not interactive;
148
+ non-interactive runs must pass `--yes`, and a declined confirmation now
149
+ exits 1.
150
+ - An empty `SECRET_KEY_SEED` env var is treated as unset, and an invalid one
151
+ is reported as a one-line error; seed derivation is shared across
152
+ `key create`, `did create`, and `rotate-keys`.
153
+ - Command errors that escape a runner are reported as one-line messages with
154
+ exit 1 instead of surfacing as unhandled rejections; a corrupt update-keys
155
+ sidecar reports its file path.
156
+ - `did add-service` validates `--endpoint`/`--endpoint-json` arguments before
157
+ resolving (and re-verifying) a did:webvh history log; `rotate-keys` likewise
158
+ checks flag conflicts before resolution.
159
+ - Bumped `@interop/ed25519-verification-key` to `^8.2.0` and switched the
160
+ did:webvh entry signer to its new `didKeySigner()` method, so the caller no
161
+ longer mutates `keyPair.id` before signing.
162
+
3
163
  ## 0.13.0 - 2026-07-12
4
164
 
5
165
  ### Added
@@ -82,7 +242,7 @@
82
242
  - `vc issue --did` now accepts a metadata handle (not just a full DID id),
83
243
  resolving it via the same lookup used by the other DID-referencing commands.
84
244
  Previously passing a handle failed with a confusing `The "path" argument must
85
- be of type string. Received undefined` error.
245
+ be of type string. Received undefined` error.
86
246
 
87
247
  ### Changed
88
248
 
@@ -121,7 +281,7 @@
121
281
  field); `loadFromCollection` / `saveToCollection` take an options object like
122
282
  the rest of the storage helpers; `vc/issue` and `vc/verify` replace their
123
283
  `as never` casts with typed ones; `edv/recipients` replaces `Record<string,
124
- any>` with a named `VerificationMethodNode` type; `edv`'s encrypt functions
284
+ any>` with a named `VerificationMethodNode` type; `edv`'s encrypt functions
125
285
  share an `EnvelopeOptions` type and a `resolveEncryptContextOrReport` wrapper;
126
286
  and the `z6Mk` / `z6LS` multibase prefixes are named constants. Added the
127
287
  file-level JSDoc header to `key.ts` and moved the `zcap revoke` stub message to
@@ -457,7 +617,7 @@
457
617
  `--handle` / `--description` tag it (exit `1` without `--save`).
458
618
  - Add `vc list` (`--json` / `--plain`) to render a metadata table of the
459
619
  stored credentials (`HANDLE | TYPE | ISSUER | CREATED | ID |
460
- DESCRIPTION`), `vc show <id>` (aliases: `view`, `cat`; `--meta` for the
620
+ DESCRIPTION`), `vc show <id>` (aliases: `view`, `cat`; `--meta` for the
461
621
  metadata, `--meta --json` for it as JSON), `vc meta <id>` to edit the
462
622
  metadata sidecar, and `vc remove <id>` (aliases: `delete`, `rm`). All
463
623
  accept a credential id, a storage id (for id-less credentials), or a
@@ -494,7 +654,7 @@
494
654
  `did create --save` and `did add-key`).
495
655
  - Add metadata support for locally stored keys and DIDs, persisted as
496
656
  `.meta.json` sidecar files next to the stored item (`~/.wallet/keys/
497
- <storageId>.meta.json` and `~/.dids/<method>/<did>.meta.json`, following the
657
+ <storageId>.meta.json` and `~/.dids/<method>/<did>.meta.json`, following the
498
658
  existing `.keys.json` sidecar pattern). Metadata fields: `created` (ISO 8601
499
659
  timestamp written at `--save` time), `handle` (a short user-defined tag),
500
660
  `description` (longer free text), and -- for keys -- `dids`, a cache of the
@@ -534,8 +694,8 @@
534
694
  the new `--plain` flag for the previous one-item-per-line output.
535
695
  - **BREAKING**: `key list --json` and `did list --json` now output an array of
536
696
  objects with metadata (`{fingerprint, storageId, type, curve?, created?,
537
- handle?, description?, dids}` for keys; `{did, method, created?, handle?,
538
- description?}` for DIDs) instead of an array of plain strings.
697
+ handle?, description?, dids}` for keys; `{did, method, created?, handle?,
698
+ description?}` for DIDs) instead of an array of plain strings.
539
699
 
540
700
  ## 0.4.0 - 2026-06-09
541
701
 
package/README.md CHANGED
@@ -25,7 +25,7 @@ cryptographic key pairs that underpin them.
25
25
  It lets you generate and manage these objects locally -- minting DIDs, issuing
26
26
  and verifying credentials, delegating capabilities, and encrypting data -- and
27
27
  interact with remote
28
- [Wallet Attached Storage](https://digitalcredentials.github.io/wallet-attached-storage-spec/)
28
+ [Wallet Attached Storage](https://w3c-ccg.github.io/wallet-attached-storage-spec/)
29
29
  servers, all from the terminal and backed by a local file-based wallet.
30
30
 
31
31
  ### Features
@@ -91,6 +91,7 @@ di vc remove|delete|rm <id> remove a stored credential
91
91
 
92
92
  di zcap create create a root capability
93
93
  di zcap delegate delegate (attenuate) a capability
94
+ di zcap import <capability> validate and store a received capability
94
95
  di zcap list list stored capabilities
95
96
  di zcap show|view|cat <id> show a stored capability
96
97
  di zcap meta <id> show/edit a capability's local metadata
@@ -109,6 +110,7 @@ di was ls|get|put|rm [path] depth-dispatching shorthands
109
110
  di was policy <show|set|clear> manage access-control policies
110
111
  di was publish|unpublish <path> toggle world-readable access
111
112
  di was grant <path> delegate access via a signed capability
113
+ di was request-grant ask a wallet for a capability on a collection
112
114
  ```
113
115
 
114
116
  ### Environment Variables
@@ -118,14 +120,33 @@ or secret-key seeds for individual commands. Each is also documented inline in
118
120
  the relevant command section below.
119
121
 
120
122
  | Variable | Used by | Purpose |
121
- |----------------------------|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
123
+ | -------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
122
124
  | `WALLET_DIR` | all | Wallet collections directory (`keys/`, `zcaps/`, `credentials/`, `was-spaces/`). Defaults to `~/.config/did-cli-wallet/` (honors `XDG_CONFIG_HOME`). |
123
125
  | `DIDS_DIR` | `did` | DID-documents directory. Defaults to `<WALLET_DIR>/dids/`. |
124
126
  | `SECRET_KEY_SEED` | `key create`, `did create` | Multibase-encoded seed for deterministic key/DID generation. Not supported with `--type ecdsa` or `--type x25519`. |
125
127
  | `WAS_DID` | `was` | Default signing DID (or stored-DID handle) when `--did` is omitted. |
126
- | `WAS_SERVER_URL` | `was` | Default WAS server base URL when `--server` is omitted. |
128
+ | `WAS_SERVER_URL` | `was` | Default WAS server base URL when `--server` (or `--exchange` for `request-grant`) is omitted. |
127
129
  | `ZCAP_CONTROLLER_KEY_SEED` | `zcap` | Controller signing-key seed for delegating capabilities. |
128
130
 
131
+ ### File Permissions
132
+
133
+ Everything written under `WALLET_DIR` and `DIDS_DIR` -- keys, zcaps,
134
+ credentials, space records, DID documents, sidecars, and history logs -- is
135
+ created with mode `0600`, owner read/write only. Directories are created with
136
+ mode `0700`, since a DID document is named after its DID and the file names
137
+ alone reveal what you hold. Secret key material is stored as plaintext Multikey
138
+ documents, so the file mode is what keeps it off other local accounts.
139
+
140
+ Files written before this became the default are not migrated. To tighten an
141
+ existing wallet directory:
142
+
143
+ ```
144
+ chmod -R u=rwX,go= ~/.config/did-cli-wallet
145
+ ```
146
+
147
+ The capital `X` matters -- a plain `chmod -R 600` would clear the traverse bit
148
+ on the directories and leave the wallet unreadable to you as well.
149
+
129
150
  ### Key Management
130
151
 
131
152
  #### Create a key pair
@@ -594,7 +615,7 @@ distinct keys, so the update key can be rotated without ever disturbing the
594
615
  document.
595
616
 
596
617
  By default `did:webvh` arms **key pre-rotation**: the DID commits, in advance,
597
- to the *hash* of the key allowed to perform the next update. A compromise of the
618
+ to the _hash_ of the key allowed to perform the next update. A compromise of the
598
619
  currently active update key cannot be used to seize the DID, because the
599
620
  attacker still does not hold the pre-committed next key. So `create` generates
600
621
  three keys: the active update key, a staged next update key (whose hash is
@@ -633,8 +654,8 @@ A few more create-time options are recorded in the signed history-log
633
654
  be moved to a different domain; `--no-portable` pins it to its origin.
634
655
  - `--witness <did...>` -- declare one or more **witness** `did:key` DIDs
635
656
  authorized to co-sign the DID's log entries (repeatable). `--witness-threshold
636
- <n>` sets how many witness approvals are required (defaults to the number of
637
- witnesses; it requires `--witness`). This only *declares* the witnesses;
657
+ <n>` sets how many witness approvals are required (defaults to the number of
658
+ witnesses; it requires `--witness`). This only _declares_ the witnesses;
638
659
  actually generating witness proofs is not yet supported.
639
660
  - `--watcher <url...>` -- declare one or more **watcher** URLs that monitor the
640
661
  DID's log (repeatable; `https://`, or `http://localhost` for local testing).
@@ -654,7 +675,7 @@ Rotate the update (authorization) key of a locally stored `did:webvh` DID with
654
675
  With no flags it advances the pre-rotation ratchet in one step: it reveals and
655
676
  activates the previously staged next key (signing the new entry with it), and
656
677
  stages a fresh next key for the following rotation. The retired update key's
657
- secret is deleted by default -- a retired key is only ever needed to *verify*
678
+ secret is deleted by default -- a retired key is only ever needed to _verify_
658
679
  historic log entries, which uses the public key from the log, not the secret:
659
680
 
660
681
  ```
@@ -693,6 +714,8 @@ Flags:
693
714
  new key (a bare `--stop-prerotation` reveal, or rotating to an external
694
715
  `--update-key`).
695
716
  - `-y`, `--yes` -- skip the confirmation prompt (rotation is hard to undo).
717
+ Required when stdin is not interactive (scripts, cron), where the prompt
718
+ cannot be asked.
696
719
 
697
720
  #### Add or remove a service entry
698
721
 
@@ -1046,7 +1069,7 @@ Store an existing Verifiable Credential in local wallet storage with
1046
1069
  `vc import`. The credential is read from a file argument, an http(s) URL, or,
1047
1070
  if neither is given, from stdin. The input must structurally look like a
1048
1071
  credential (its `type` must include `VerifiableCredential`); it is stored
1049
- as-is and is *not* verified on import (run `vc verify` for that). `--handle` /
1072
+ as-is and is _not_ verified on import (run `vc verify` for that). `--handle` /
1050
1073
  `--description` tag the saved credential:
1051
1074
 
1052
1075
  ```
@@ -1178,7 +1201,7 @@ handed down a chain of signed _delegated_ capabilities, each one optionally
1178
1201
  narrowing the allowed actions or the target.
1179
1202
 
1180
1203
  Both commands print the capability as JSON together with an `encoded` field --
1181
- the capability serialized and `base58btc`-encoded with a multibase `z` prefix --
1204
+ the capability serialized and base64url-encoded with a multibase `u` prefix --
1182
1205
  which is the compact form you pass to `zcap delegate --capability` to delegate
1183
1206
  it
1184
1207
  further. Pass `--save` to also write the capability to local wallet storage
@@ -1207,7 +1230,7 @@ Root capabilities are unsigned, so no key is needed:
1207
1230
  "controller": "did:key:z6Mkfeco2NSEPeFV3DkjNSabaCza1EoS3CmqLb1eJ5BriiaR",
1208
1231
  "invocationTarget": "https://example.com/api"
1209
1232
  },
1210
- "encoded": "z3g9TJBrQTdKemE9BC43N9WsT8snKvQzwCpCWs8o..."
1233
+ "encoded": "ueyJAY29udGV4dCI6Imh0dHBzOi8vdzNpZC5vcmcvemNhcC92MSIsImlkIjoi..."
1211
1234
  }
1212
1235
  ```
1213
1236
 
@@ -1217,7 +1240,7 @@ and a root capability grants all actions (it has no `allowedAction`).
1217
1240
 
1218
1241
  #### Note about the `encoded` field
1219
1242
 
1220
- The multibase- (that's the `z` prefix) and base58btc-encoded JSON of the zcap
1243
+ The multibase- (that's the `u` prefix) and base64url-encoded JSON of the zcap
1221
1244
  is returned, for convenience, in the `encoded` field.
1222
1245
 
1223
1246
  This is done for easier "double-click to copy" and pasting into other tools,
@@ -1265,7 +1288,7 @@ To delegate from the root capability for a target, pass `--url` (the same
1265
1288
  "proofValue": "z5tuwwdJE6VXLhf1v8SNAquBmMcJCD7zJ4bXDi6rh1Fk..."
1266
1289
  }
1267
1290
  },
1268
- "encoded": "zkL8vet8M2mn7akSpHEVvgFUCTVq4VSGs1s8Zsq9bYba..."
1291
+ "encoded": "ueyJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3pjYXAvdjEi..."
1269
1292
  }
1270
1293
  ```
1271
1294
 
@@ -1290,7 +1313,7 @@ metadata handle of a zcap saved in local wallet storage. Use
1290
1313
  ./di zcap delegate \
1291
1314
  --did did:key:z6MknBxr... \
1292
1315
  --delegatee did:key:z6Mks... \
1293
- --capability zkL8vet8M2mn7akSpHEVvgFUCTVq4VSGs1s8Zsq9bYba... \
1316
+ --capability ueyJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3pjYXAvdjEi... \
1294
1317
  --invocation-target https://example.com/documents/reports \
1295
1318
  --allow read
1296
1319
  ```
@@ -1419,7 +1442,7 @@ valid until it expires (see `--ttl` / `--expires`).
1419
1442
  ### Wallet Attached Storage (WAS)
1420
1443
 
1421
1444
  The `was` command group is a client for
1422
- [Wallet Attached Storage](https://digitalcredentials.github.io/wallet-attached-storage-spec/)
1445
+ [Wallet Attached Storage](https://w3c-ccg.github.io/wallet-attached-storage-spec/)
1423
1446
  servers, which organize content as `Space > Collection > Resource` behind
1424
1447
  zcap-authorized HTTP. Every request is signed with a `did:key` DID stored in
1425
1448
  the local wallet (saved with `did create --save`; Ed25519 keys only for now).
@@ -1498,7 +1521,7 @@ the server, or the local registry record with `--meta`:
1498
1521
 
1499
1522
  `was space update` (alias: `configure`) upserts description fields
1500
1523
  (`--name`), also refreshing the registry entry. `was space add` registers an
1501
- *existing* remote space (a full space URL, or a bare id plus `--server`) in
1524
+ _existing_ remote space (a full space URL, or a bare id plus `--server`) in
1502
1525
  the local registry, verifying it with a describe first. `was space meta
1503
1526
  <space>` updates only a registered space's local metadata (`--handle` and/or
1504
1527
  `--description`); the server-side space is untouched, and passing an empty
@@ -1689,12 +1712,114 @@ the zcap store (`~/.config/did-cli-wallet/zcaps/`):
1689
1712
  "expires": "2027-06-11T17:30:00Z",
1690
1713
  "proof": { ... }
1691
1714
  },
1692
- "encoded": "zkL8vet8M2mn..."
1715
+ "encoded": "ueyJAY29udGV4dCI6..."
1693
1716
  }
1694
1717
  ```
1695
1718
 
1696
1719
  Hand the `encoded` string (or the JSON) to the delegatee out-of-band.
1697
1720
 
1721
+ #### Request a grant
1722
+
1723
+ `was request-grant` is the inverse of `was grant`, for the case where you are
1724
+ the one who needs access. It asks a user's wallet to delegate a capability on
1725
+ one of its public collections, and is what lets a program publish into someone
1726
+ else's storage without ever logging into their wallet.
1727
+
1728
+ The grantee key is minted by the command rather than passed in, so a script (or
1729
+ an LLM agent) driving the CLI never handles key material: the secret goes
1730
+ straight into local DID storage, and stdout carries only the capability. The
1731
+ approval link and the progress notes go to stderr; `--json` puts the DID, the
1732
+ handle, the link, and the capability into one object on stdout instead.
1733
+
1734
+ ```
1735
+ ./di was request-grant --exchange https://freewallet.cloud/spaces/ \
1736
+ --reason "Publish a demo page" --name "demo-publisher"
1737
+ Requesting "web" access for did:key:z6MkAgent...
1738
+
1739
+ Open this in your wallet to approve:
1740
+
1741
+ https://freewallet.cloud/workflows/ephemeral/exchanges/abc-123/protocols?iuv=1
1742
+
1743
+ Waiting for approval...
1744
+ ```
1745
+
1746
+ If you know which wallet the user runs, `--wallet <url>` also prints a link
1747
+ that opens it straight onto the approval page for this request:
1748
+
1749
+ ```
1750
+ ./di was request-grant --exchange https://freewallet.cloud/spaces/ --wallet https://freewallet.me
1751
+ ...
1752
+ Or open your wallet directly:
1753
+
1754
+ https://freewallet.me/#/external/request?url=https%3A%2F%2Ffreewallet.cloud%2F...
1755
+ ```
1756
+
1757
+ The interaction URL is still printed beside it, since that is what a wallet on
1758
+ another device can be pointed at.
1759
+
1760
+ The user opens that link in their wallet and approves. The command then prints
1761
+ the capability it received (the same `u...` form `--capability` accepts) and
1762
+ files it in the zcap store under `--handle` (default `agent`), together with the
1763
+ minted key:
1764
+
1765
+ ```
1766
+ Capability saved to ~/.config/did-cli-wallet/zcaps/urn_uuid_....json
1767
+ Granted. Use it with --capability agent, for example:
1768
+ di was put ./index.html --capability agent --did agent --resource index.html --content-type text/html
1769
+ ueyJAY29udGV4dCI6...
1770
+ ```
1771
+
1772
+ Saving is what makes the grant usable: `--capability` resolves its signing key
1773
+ out of the local DID store, so a key held only for the run cannot sign the write
1774
+ that follows. `--no-save` prints the capability without keeping either half, for
1775
+ inspecting a grant you do not intend to use.
1776
+
1777
+ The signing DID is taken from `--did` first, then `WAS_DID`, and only then the
1778
+ capability's own `controller`. Naming the minted key explicitly
1779
+ (`--did agent`, matching the handle the grant was filed under) is therefore
1780
+ worth doing whenever `WAS_DID` is set in the environment, or the write is signed
1781
+ by your own DID and the server rejects it.
1782
+
1783
+ A run files the minted key and the received capability under the same handle, so
1784
+ a handle already taken by a stored DID or capability is refused before anything
1785
+ is minted; pass a different `--handle` for a second grant. Nothing is written
1786
+ until the grant arrives -- a request that is declined, expires, or times out
1787
+ leaves no key behind.
1788
+
1789
+ Options are `--collection <name>` (default `web`), `--action <verb...>` (default
1790
+ `GET HEAD PUT POST`), `--reason <text>` (shown to the user at the consent step),
1791
+ `--name <name>` (what the agent calls itself, shown to the user beside its
1792
+ key), `--wallet <url>` (a wallet base URL to print an approval deep link for),
1793
+ `--timeout <seconds>` (default 600, matching the server's exchange
1794
+ lifetime), `--handle` / `--description`, `--no-save`, `--json`, and
1795
+ `--exchange <url>` (or `WAS_SERVER_URL`).
1796
+
1797
+ `--exchange` names the WAS server that hosts the ephemeral exchange carrying
1798
+ the request. It is only the meeting point between this command and the wallet.
1799
+ The grant itself names its own target, whichever space the user's wallet picks,
1800
+ so the two servers need not be the same.
1801
+
1802
+ The end-to-end flow this command exists for -- an LLM agent drafting a page and
1803
+ publishing it to the user's own storage -- is scripted in
1804
+ [demo/agent-storage](demo/agent-storage/README.md), with the agent-facing
1805
+ version in the `publish-page` skill under `.claude/skills/`.
1806
+
1807
+ `--name` is self-declared, not verified: the wallet shows it as what the agent
1808
+ calls itself, next to the grantee key, so the user should still compare the
1809
+ key rather than trust the name alone. It is at most 64 characters and cannot
1810
+ contain control characters.
1811
+
1812
+ Two things the wallet decides, not this command:
1813
+
1814
+ - A public collection is only ever created public. If the named collection
1815
+ already exists and is not world-readable, the wallet cannot satisfy the
1816
+ request, and the approval comes back granting nothing.
1817
+ - The actions you ask for are a request, not an instruction. The wallet caps
1818
+ them by what the collection allows, and may grant fewer than you asked for.
1819
+
1820
+ The exchange lives on the server for ten minutes. After that the link is dead
1821
+ and the command reports it; run it again for a fresh one.
1822
+
1698
1823
  #### Use a received capability
1699
1824
 
1700
1825
  On the receiving side, `ls` / `get` / `put` / `rm` (and `resource
@@ -1706,21 +1831,32 @@ of:
1706
1831
  - the capability id or metadata **handle of a zcap** stored in
1707
1832
  `~/.config/did-cli-wallet/zcaps/`.
1708
1833
 
1709
- Note that a `--capability` reference is *not* a WAS path -- no space,
1834
+ Note that a `--capability` reference is _not_ a WAS path -- no space,
1710
1835
  collection, or resource address is given (or needed). The capability itself
1711
1836
  records what it grants access to in its `invocationTarget`, and that is what
1712
1837
  the command operates on:
1713
1838
 
1714
- - a capability granted on a **resource** drives `get` / `put` / `rm`;
1839
+ - a capability granted on a **resource** drives `get` / `put` / `rm` and
1840
+ `meta get` / `meta put`;
1715
1841
  - one granted on a **collection** drives `ls`, `resource add`, and `rm`;
1716
1842
  - one granted on a whole **space** drives `ls` and `rm`.
1717
1843
 
1718
- A depth mismatch (e.g. `get` with a collection-scoped capability) is an
1719
- input error. The server URL is taken from the invocation target's origin,
1720
- and the signing DID defaults to the capability's controller (the delegatee)
1721
- when that DID is stored locally -- so usually no flags are needed at all.
1722
-
1723
- In the examples below, `bob-share` is the metadata handle of a *stored zcap*
1844
+ A collection-scoped capability also reaches one resource inside it, named
1845
+ with `--resource <id>`: `get`, `put`, `meta get`, `meta put`, and `rm` then
1846
+ act on that id beneath the capability's collection (without the flag, `rm`
1847
+ deletes the collection itself). This is how a grant issued on a whole
1848
+ collection writes at an id you choose (`resource add` also takes a collection
1849
+ capability, but the server picks the id, so it cannot produce `index.html`).
1850
+ The resource handle inherits the collection's capability, so the request is
1851
+ still an invocation of the grant you received.
1852
+
1853
+ Any other depth mismatch (e.g. `get` with a space-scoped capability) is an
1854
+ input error, as is `--resource` without a capability to anchor it. The
1855
+ server URL is taken from the invocation target's origin, and the signing DID
1856
+ defaults to the capability's controller (the delegatee) when that DID is
1857
+ stored locally -- so usually no flags are needed at all.
1858
+
1859
+ In the examples below, `bob-share` is the metadata handle of a _stored zcap_
1724
1860
  (not a space or collection handle): say Alice granted Bob `GET`/`PUT` on the
1725
1861
  single resource `home/credentials/vc-1`, and the capability was saved with
1726
1862
  `--save --handle bob-share` (on Alice's machine via `was grant --save`; on
@@ -1733,7 +1869,7 @@ Bob's machine he can pass the encoded string or a JSON file directly):
1733
1869
 
1734
1870
  # Bob, with the encoded string he received out-of-band -- this reads the
1735
1871
  # resource the capability targets (home/credentials/vc-1):
1736
- ./di was get --capability zkL8vet8M2mn...
1872
+ ./di was get --capability ueyJAY29udGV4dCI6...
1737
1873
  {
1738
1874
  "name": "Alice"
1739
1875
  }
@@ -1747,7 +1883,17 @@ Bob's machine he can pass the encoded string or a JSON file directly):
1747
1883
 
1748
1884
  # Had the grant been on the whole collection (home/credentials), ls would
1749
1885
  # list it and `resource add` could post new resources into it:
1750
- ./di was ls --capability zkL8vet8M2mn...
1886
+ ./di was ls --capability ueyJAY29udGV4dCI6...
1887
+
1888
+ # ...and --resource picks one id inside that collection, so the write lands
1889
+ # at a name you choose rather than a server-generated one:
1890
+ ./di was put ./index.html --capability ueyJAY29udGV4dCI6... \
1891
+ --resource index.html --content-type text/html
1892
+ ./di was get --capability ueyJAY29udGV4dCI6... --resource index.html
1893
+
1894
+ # ...and the same flag deletes that one resource, rather than the whole
1895
+ # collection the capability targets:
1896
+ ./di was rm --capability ueyJAY29udGV4dCI6... --resource index.html
1751
1897
  ```
1752
1898
 
1753
1899
  #### Policies and public sharing
@@ -4,6 +4,28 @@
4
4
  * `add-key` default purpose set (described in its help text).
5
5
  */
6
6
  export declare const DEFAULT_VERIFICATION_PURPOSES: readonly ["authentication", "assertionMethod", "capabilityDelegation", "capabilityInvocation"];
7
+ /**
8
+ * Save the artifacts of a newly created DID: the DID document, its keys file,
9
+ * a metadata sidecar (creation timestamp plus the handle and description when
10
+ * given), and the key-to-DID association cache of any matching wallet keys.
11
+ *
12
+ * @param options {object}
13
+ * @param options.method {string}
14
+ * @param options.didDocument {object}
15
+ * @param options.exportedKeys {object}
16
+ * @param options.fingerprints {(string | undefined)[]}
17
+ * @param [options.handle] {string}
18
+ * @param [options.description] {string}
19
+ * @returns {Promise<void>}
20
+ */
21
+ export declare function saveDidArtifacts({ method, didDocument, exportedKeys, fingerprints, handle, description }: {
22
+ method: string;
23
+ didDocument: object;
24
+ exportedKeys: object;
25
+ fingerprints: (string | undefined)[];
26
+ handle?: string;
27
+ description?: string;
28
+ }): Promise<void>;
7
29
  /**
8
30
  * Create a new DID of the given method (key, web, or webvh), optionally saving
9
31
  * its document, keys, and metadata to local storage, and print it to stdout.
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/did/create.ts"],"names":[],"mappings":"AAsCA;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,gGAKhC,CAAA;AAuJV;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2XlB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsIlB"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/did/create.ts"],"names":[],"mappings":"AAmCA;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,gGAKhC,CAAA;AAEV;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,MAAM,EACN,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,WAAW,EACZ,EAAE;IACD,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,CAAA;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB;AA8ED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2XlB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsIlB"}
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * DID creation and key addition: `runCreate` (key, web, webvh) and `runAddKey`
3
- * (add a verification key to a stored did:web). Both share the seed-derivation,
4
- * ECDSA-curve, non-deterministic-seed-guard, and output helpers at the top of
5
- * this module; the webvh signer/sidecar plumbing is reused from
6
- * `./webvh-update.js`.
3
+ * (add a verification key to a stored did:web). Both share the ECDSA-curve,
4
+ * non-deterministic-seed-guard, and output helpers at the top of this module;
5
+ * seed derivation comes from `../../keys/seed.js` and the webvh signer/sidecar
6
+ * plumbing is reused from `./webvh-update.js`.
7
7
  */
8
- import { decodeSecretKeySeed, generateSecretKeySeed } from '@digitalcredentials/bnid';
9
8
  import { driver } from '@interop/did-method-key';
10
9
  import * as didWeb from '@interop/did-web-resolver';
11
10
  import { createDID } from '@interop/did-method-webvh';
@@ -15,6 +14,7 @@ import { X25519KeyAgreementKey2020 } from '@interop/x25519-key-agreement-key';
15
14
  import { loadDidDocument, loadDidKeys, saveDidLog, saveDidMeta, saveToDids } from '../../storage.js';
16
15
  import { recordKeyDidAssociation } from '../../meta.js';
17
16
  import { normalizeEcdsaCurve, SUPPORTED_ECDSA_CURVES, warnIfNotVcIssuanceCapable } from '../../keys/ecdsa.js';
17
+ import { deriveSeed } from '../../keys/seed.js';
18
18
  import { exportUpdateKey, generateStagedKey } from '../../keys/webvh-update.js';
19
19
  import { requireSaveForMetaFlags } from '../collection-command.js';
20
20
  import { makeWebvhEntrySigner, persistUpdateKeysSidecar } from './webvh-update.js';
@@ -43,7 +43,7 @@ export const DEFAULT_VERIFICATION_PURPOSES = [
43
43
  * @param [options.description] {string}
44
44
  * @returns {Promise<void>}
45
45
  */
46
- async function saveDidArtifacts({ method, didDocument, exportedKeys, fingerprints, handle, description }) {
46
+ export async function saveDidArtifacts({ method, didDocument, exportedKeys, fingerprints, handle, description }) {
47
47
  const did = didDocument.id;
48
48
  const docPath = await saveToDids({ method, did, data: didDocument });
49
49
  await saveToDids({ method, did, suffix: 'keys', data: exportedKeys });
@@ -62,27 +62,6 @@ async function saveDidArtifacts({ method, didDocument, exportedKeys, fingerprint
62
62
  }
63
63
  console.error(`DID saved to ${docPath}`);
64
64
  }
65
- /**
66
- * Resolve the secret key seed for a deterministic (Ed25519) key. With
67
- * `--with-seed`, an existing `SECRET_KEY_SEED` env var is honored or a fresh
68
- * seed generated; without it, only an explicitly set env seed is used. Returns
69
- * the encoded seed (echoed back to the user) and its decoded bytes (for key
70
- * generation).
71
- *
72
- * @param options {object}
73
- * @param [options.withSeed] {boolean}
74
- * @returns {Promise<{ secretKeySeed?: string, seedBytes?: Uint8Array }>}
75
- */
76
- async function deriveSeed({ withSeed }) {
77
- const envSeed = process.env.SECRET_KEY_SEED;
78
- const secretKeySeed = withSeed
79
- ? (envSeed ?? (await generateSecretKeySeed()))
80
- : envSeed;
81
- const seedBytes = secretKeySeed
82
- ? decodeSecretKeySeed({ secretKeySeed })
83
- : undefined;
84
- return { secretKeySeed, seedBytes };
85
- }
86
65
  /**
87
66
  * Guard a non-deterministic key type against `--with-seed`: ECDSA and X25519
88
67
  * keys are generated non-deterministically and cannot be derived from a seed.