@did-btcr2/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 (52) hide show
  1. package/README.md +95 -14
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cjs/index.js +674 -54
  4. package/dist/esm/src/cli.js +25 -3
  5. package/dist/esm/src/cli.js.map +1 -1
  6. package/dist/esm/src/commands/config.js +124 -8
  7. package/dist/esm/src/commands/config.js.map +1 -1
  8. package/dist/esm/src/commands/create.js +10 -1
  9. package/dist/esm/src/commands/create.js.map +1 -1
  10. package/dist/esm/src/commands/deactivate.js +33 -6
  11. package/dist/esm/src/commands/deactivate.js.map +1 -1
  12. package/dist/esm/src/commands/profile.js +5 -3
  13. package/dist/esm/src/commands/profile.js.map +1 -1
  14. package/dist/esm/src/commands/update.js +33 -6
  15. package/dist/esm/src/commands/update.js.map +1 -1
  16. package/dist/esm/src/config-schema.js +149 -0
  17. package/dist/esm/src/config-schema.js.map +1 -0
  18. package/dist/esm/src/config.js +515 -35
  19. package/dist/esm/src/config.js.map +1 -1
  20. package/dist/esm/src/keystore/paths.js +3 -2
  21. package/dist/esm/src/keystore/paths.js.map +1 -1
  22. package/dist/esm/src/output.js +49 -0
  23. package/dist/esm/src/output.js.map +1 -1
  24. package/dist/esm/src/types.js +11 -0
  25. package/dist/esm/src/types.js.map +1 -1
  26. package/dist/types/src/cli.d.ts.map +1 -1
  27. package/dist/types/src/commands/config.d.ts.map +1 -1
  28. package/dist/types/src/commands/create.d.ts.map +1 -1
  29. package/dist/types/src/commands/deactivate.d.ts.map +1 -1
  30. package/dist/types/src/commands/profile.d.ts.map +1 -1
  31. package/dist/types/src/commands/update.d.ts.map +1 -1
  32. package/dist/types/src/config-schema.d.ts +24 -0
  33. package/dist/types/src/config-schema.d.ts.map +1 -0
  34. package/dist/types/src/config.d.ts +228 -6
  35. package/dist/types/src/config.d.ts.map +1 -1
  36. package/dist/types/src/keystore/paths.d.ts.map +1 -1
  37. package/dist/types/src/output.d.ts +22 -0
  38. package/dist/types/src/output.d.ts.map +1 -1
  39. package/dist/types/src/types.d.ts +33 -0
  40. package/dist/types/src/types.d.ts.map +1 -1
  41. package/package.json +4 -4
  42. package/src/cli.ts +27 -3
  43. package/src/commands/config.ts +135 -8
  44. package/src/commands/create.ts +13 -1
  45. package/src/commands/deactivate.ts +53 -6
  46. package/src/commands/profile.ts +5 -3
  47. package/src/commands/update.ts +53 -6
  48. package/src/config-schema.ts +178 -0
  49. package/src/config.ts +693 -43
  50. package/src/keystore/paths.ts +3 -2
  51. package/src/output.ts +53 -0
  52. package/src/types.ts +23 -0
package/README.md CHANGED
@@ -86,12 +86,15 @@ Required flags: `-s/--source-document`, `--source-version-id`, `-p/--patches`, `
86
86
  | `-p, --patches <json>` | JSON Patch operations as a JSON array string |
87
87
  | `-m, --verification-method-id <id>` | DID document verification method ID |
88
88
  | `-b, --beacon-id <json>` | Beacon ID as a JSON string |
89
+ | `--publish-to-cas <mode>` | Publish update artifacts to a writable CAS before broadcast: `auto`, `always`, or `never` (default: `never`). See [Publishing updates to CAS](#publishing-updates-to-cas) |
90
+ | `--fee-rate <satsPerVByte>` | Fee rate in sats/vByte for the beacon transaction (default: `5`). Raise it under congestion so the transaction confirms (also `BTCR2_FEE_RATE`, profile `btc.feeRate`) |
91
+ | `--change-address <address>` | Send transaction change to this address instead of the beacon address, so a DID's announcements are not linked on-chain (profile `btc.changeAddress`) |
89
92
 
90
93
  ### deactivate (alias: delete)
91
94
 
92
95
  Permanently deactivates a DID. This is irreversible. Deactivation applies the `{ "op": "add", "path": "/deactivated", "value": true }` patch and routes through the same signed-update path as `update`, so it also signs via the keystore.
93
96
 
94
- Required flags: `-s/--source-document`, `--source-version-id`, `-m/--verification-method-id`, `-b/--beacon-id`.
97
+ Required flags: `-s/--source-document`, `--source-version-id`, `-m/--verification-method-id`, `-b/--beacon-id`. Optional: `--publish-to-cas <mode>`, `--fee-rate <satsPerVByte>`, `--change-address <address>` (same as `update`).
95
98
 
96
99
  ### key
97
100
 
@@ -116,10 +119,14 @@ Read and write CLI configuration.
116
119
  | Subcommand | Alias | Description |
117
120
  |---|---|---|
118
121
  | `config init` | - | Create a default config file with one profile per network. `--force` overwrites |
119
- | `config get [path]` | - | Print a value at a dotted path, or the whole config |
120
- | `config set <path> <value>` | - | Set a value at a dotted path (value parsed as JSON when valid, else a string) |
122
+ | `config get [path]` | - | Print a value at a dotted path, or the whole config. Secret values are redacted; `--show-secrets` reveals them |
123
+ | `config set <path> <value>` | - | Set a value at a dotted path (value parsed as JSON when valid, else a string). An invalid enum for a known key is rejected; an unknown path warns but writes |
121
124
  | `config unset <path>` | - | Delete a value at a dotted path |
122
- | `config list` | `ls` | Print the entire config file |
125
+ | `config list` | `ls` | Print the entire config file. Secret values are redacted; `--show-secrets` reveals them |
126
+ | `config validate` | - | Report unknown keys, invalid enum values, and an unsupported schema version |
127
+ | `config effective` | - | Print the resolved connection config with per-value provenance (`flag`/`env`/`file`/`default`). `-n, --network <n>` selects the network; `--show-secrets` reveals the RPC password |
128
+ | `config path` | - | Print the resolved config-file and keystore paths |
129
+ | `config doctor` | - | Probe reachability of the resolved endpoints (read-only; touches the network). `-n, --network <n>` selects the network |
123
130
 
124
131
  ### profile
125
132
 
@@ -213,7 +220,7 @@ Override precedence, highest wins: CLI flags, then environment variables, then c
213
220
  | Flag | Description |
214
221
  |---|---|
215
222
  | `-v, --version` | Output the current version |
216
- | `-o, --output <format>` | Output format: `json` or `text` (default: `text`) |
223
+ | `-o, --output <format>` | Output format: `json` or `text` (default: config `defaults.output`, else `text`) |
217
224
  | `--verbose` | Verbose output |
218
225
  | `--quiet` | Suppress non-essential output |
219
226
  | `-c, --config <path>` | Path to config file (default: `$XDG_CONFIG_HOME/btcr2/config.json`) |
@@ -221,8 +228,14 @@ Override precedence, highest wins: CLI flags, then environment variables, then c
221
228
  | `--btc-rest <url>` | Override Bitcoin REST endpoint (Esplora API) |
222
229
  | `--btc-rpc-url <url>` | Override Bitcoin Core RPC endpoint |
223
230
  | `--btc-rpc-user <user>` | Bitcoin Core RPC username |
224
- | `--btc-rpc-pass <pass>` | Bitcoin Core RPC password |
225
- | `--cas-gateway <url>` | IPFS HTTP gateway for CAS reads |
231
+ | `--btc-rpc-pass <pass>` | Bitcoin Core RPC password (accepts an `env:<VAR>` or `file:<path>` secret reference) |
232
+ | `--btc-rpc-wallet <name>` | Bitcoin Core wallet name for wallet-scoped RPCs (`/wallet/<name>`) |
233
+ | `--btc-rpc-header <header>` | Extra Bitcoin Core RPC header `"Key: Value"` (repeatable) |
234
+ | `--btc-rest-header <header>` | Extra Bitcoin REST header `"Key: Value"` (repeatable), e.g. an API key |
235
+ | `--btc-timeout <ms>` | Bitcoin REST/RPC request timeout in milliseconds (default: unbounded) |
236
+ | `--cas-gateway <url>` | IPFS HTTP gateway for CAS reads (read-only) |
237
+ | `--cas-rpc-url <url>` | IPFS HTTP RPC endpoint for a writable CAS (reads + writes; enables `--publish-to-cas`) |
238
+ | `--cas-timeout <ms>` | CAS request timeout in milliseconds (default: `30000`; `0` disables) |
226
239
  | `--keystore <path>` | Path to the keystore file (default: `$XDG_DATA_HOME/btcr2/keystore.json`) |
227
240
  | `--passphrase-file <path>` | Read the keystore passphrase from a file (unattended use) |
228
241
  | `--signing-key <ref>` | Key for create/update/deactivate signing: a URN, fingerprint prefix, or name |
@@ -235,40 +248,108 @@ Override precedence, highest wins: CLI flags, then environment variables, then c
235
248
  | `BTCR2_BTC_RPC_URL` | `--btc-rpc-url` |
236
249
  | `BTCR2_BTC_RPC_USER` | `--btc-rpc-user` |
237
250
  | `BTCR2_BTC_RPC_PASS` | `--btc-rpc-pass` |
251
+ | `BTCR2_BTC_RPC_PASS_FILE` | file whose contents are the RPC password |
238
252
  | `BTCR2_CAS_GATEWAY` | `--cas-gateway` |
253
+ | `BTCR2_CAS_RPC_URL` | `--cas-rpc-url` |
254
+ | `BTCR2_BTC_TIMEOUT` | `--btc-timeout` |
255
+ | `BTCR2_CAS_TIMEOUT` | `--cas-timeout` |
256
+ | `BTCR2_FEE_RATE` | `--fee-rate` |
257
+ | `BTCR2_OUTPUT` | `-o, --output` |
239
258
 
240
259
  ### Config file
241
260
 
242
- Default location: `$XDG_CONFIG_HOME/btcr2/config.json` (falls back to `~/.config/btcr2/config.json`).
261
+ Default location: `$XDG_CONFIG_HOME/btcr2/config.json` (falls back to `~/.config/btcr2/config.json`). An empty `$XDG_CONFIG_HOME` is treated as unset. A malformed config file fails loudly (the CLI never silently falls back to public endpoints, and never overwrites an unparseable file).
243
262
 
244
- Profiles are matched by network name when `--profile` is not specified. For example, resolving a regtest DID automatically selects the `"regtest"` profile.
263
+ Profiles are matched by network name when `--profile` is not specified. For example, resolving a regtest DID automatically selects the `"regtest"` profile. A profile that is not named after a network can declare its network with a `network` field.
245
264
 
246
265
  ```json
247
266
  {
267
+ "schemaVersion": 1,
268
+ "defaults": {
269
+ "profile": "production",
270
+ "network": "bitcoin",
271
+ "output": "text"
272
+ },
248
273
  "profiles": {
249
274
  "regtest": {
250
275
  "btc": {
251
276
  "rest": "http://localhost:3000",
252
277
  "rpcUrl": "http://localhost:18443",
253
278
  "rpcUser": "polaruser",
254
- "rpcPass": "polarpass"
279
+ "rpcPass": "polarpass",
280
+ "wallet": "primary",
281
+ "feeRate": 5,
282
+ "timeoutMs": 30000
255
283
  }
256
284
  },
257
- "bitcoin": {
258
- "btc": { "rest": "https://my-mempool/api" },
259
- "cas": { "gateway": "https://ipfs.io" }
285
+ "production": {
286
+ "network": "bitcoin",
287
+ "btc": {
288
+ "rest": "https://my-mempool/api",
289
+ "headers": { "Authorization": "Bearer <api-key>" },
290
+ "feeRate": 20
291
+ },
292
+ "cas": { "gateway": "https://ipfs.io", "rpcUrl": "http://127.0.0.1:5001", "timeoutMs": 30000 },
293
+ "identity": { "keystore": "/secure/prod-keystore.json", "default": "did:btcr2:...#key-0" }
260
294
  }
261
295
  }
262
296
  }
263
297
  ```
264
298
 
299
+ Field notes:
300
+
301
+ - **`defaults`**: `profile` selects the active profile; `network` fixes the network `create` encodes when `-n` is absent; `output` sets the default output format. `schemaVersion` is stamped on every write; a file written by a newer CLI is refused.
302
+ - **`btc`**: `rest`/`rpcUrl`/`rpcUser`/`rpcPass` are endpoints and credentials; `wallet` targets a Bitcoin Core wallet (`/wallet/<name>`); `headers`/`rpcHeaders` add REST/RPC headers; `feeRate` (sats/vByte), `changeAddress`, and `timeoutMs` set broadcast and request behavior. The RPC url, user, and pass are resolved as one atomic unit, so a URL from a higher-precedence layer never inherits credentials from a lower one.
303
+ - **`cas`**: `gateway` is a read-only IPFS HTTP gateway; `cas.rpcUrl` is a writable IPFS HTTP RPC endpoint (enables `--publish-to-cas`; `rpcUrl` wins over `gateway`); `timeoutMs` bounds CAS operations (`0` disables).
304
+ - **`identity`**: `keystore` points the profile at its own keystore file, and `default` is the profile's default signing key. Both fall **below** the corresponding `--keystore` / `--signing-key` flags.
305
+
306
+ Use `config validate` to check a file, and `config effective` to see the resolved values with their provenance.
307
+
308
+ ### RPC password and secrets
309
+
310
+ `config get` and `config list` redact secret-looking values (RPC password and any `pass`/`secret`/`token` key) by default; pass `--show-secrets` to reveal them.
311
+
312
+ An `rpcPass` written directly into `config.json` is stored in cleartext (the file is mode 0600 but not encrypted). For anything sensitive, keep the secret out of the file with a reference or an RPC-URL-embedded credential:
313
+
314
+ - `"rpcPass": "env:MY_RPC_PASS"` reads the password from the `MY_RPC_PASS` environment variable.
315
+ - `"rpcPass": "file:/run/secrets/rpc-pass"` reads it from a file (a single trailing newline is trimmed).
316
+ - `BTCR2_BTC_RPC_PASS_FILE=/run/secrets/rpc-pass` names a file to read when no other RPC password source applies.
317
+
265
318
  ### Defaults
266
319
 
267
320
  When no overrides are configured:
268
321
 
269
322
  - **Bitcoin REST**: [mempool.space](https://mempool.space) for `bitcoin`, `testnet3`, `testnet4`, and `signet`; [mutinynet.com](https://mutinynet.com) for `mutinynet`; `http://localhost:3000` for `regtest`
270
323
  - **Bitcoin RPC**: `http://localhost:18443` for `regtest` (credentials required), not configured for public networks
271
- - **CAS**: [ipfs.io](https://ipfs.io) HTTP gateway (read-only)
324
+ - **CAS**: [ipfs.io](https://ipfs.io) HTTP gateway (read-only). Configure a writable CAS with `--cas-rpc-url` (or `cas.rpcUrl`) to publish with `--publish-to-cas`
325
+
326
+ ## Publishing updates to CAS
327
+
328
+ CAS publication is **optional and never required**. Every `update` and `deactivate` can be completed and shared entirely via sidecar: the command always prints the artifacts a resolver needs (the signed update, the transaction id, the CAS announcement for CAS beacons, and the SMT proof for SMT beacons) for you to distribute yourself.
329
+
330
+ Optionally, the signed update (and, for CAS beacons, the announcement) can be published to a content-addressed store before the on-chain broadcast, so any OP_RETURN update hash is fetchable from CAS at resolution time without sidecar data. This is opt-in via `--publish-to-cas`:
331
+
332
+ | Mode | Behavior |
333
+ |---|---|
334
+ | `never` (default) | Publish nothing. Distribute the printed artifacts via sidecar. |
335
+ | `auto` | Best-effort. Publish when a writable CAS is configured; otherwise skip publication silently for every beacon type and proceed. Never blocks an update. |
336
+ | `always` | Require a writable CAS; error up-front for every beacon type when none is configured. |
337
+
338
+ A writable CAS is configured with `--cas-rpc-url <url>` (an IPFS HTTP RPC endpoint, e.g. a local Kubo node at `http://127.0.0.1:5001`), the `BTCR2_CAS_RPC_URL` environment variable, or a profile's `cas.rpcUrl`. The default IPFS gateway is read-only, so without a configured `--cas-rpc-url`, `--publish-to-cas auto` publishes nothing and completes the update sidecar-only, while `--publish-to-cas always` errors up-front (naming the fix) for every beacon type.
339
+
340
+ **Privacy:** under `auto`/`always`, canonical signed updates (and announcements) are published to the configured, possibly public, CAS before the on-chain anchor. Keep `never` (the default) to distribute update data privately via sidecar.
341
+
342
+ ```bash
343
+ # Opt into CAS publication against a local IPFS (Kubo) node
344
+ btcr2 update \
345
+ --cas-rpc-url http://127.0.0.1:5001 \
346
+ --publish-to-cas auto \
347
+ -s "$(cat did.json)" \
348
+ --source-version-id 1 \
349
+ -p '[{"op":"add","path":"/service/-","value":{"id":"#svc","type":"X","serviceEndpoint":"https://x"}}]' \
350
+ -m 'did:btcr2:k1qq...#key-0' \
351
+ -b '{"id":"#beacon-0","type":"SingletonBeacon","serviceEndpoint":"bitcoin:bc1..."}'
352
+ ```
272
353
 
273
354
  ## Links
274
355