@did-btcr2/cli 0.14.0 → 0.16.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 (83) hide show
  1. package/README.md +106 -17
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cjs/index.js +1160 -131
  4. package/dist/esm/src/cli.js +29 -5
  5. package/dist/esm/src/cli.js.map +1 -1
  6. package/dist/esm/src/commands/config.js +130 -18
  7. package/dist/esm/src/commands/config.js.map +1 -1
  8. package/dist/esm/src/commands/create.js +13 -1
  9. package/dist/esm/src/commands/create.js.map +1 -1
  10. package/dist/esm/src/commands/deactivate.js +16 -2
  11. package/dist/esm/src/commands/deactivate.js.map +1 -1
  12. package/dist/esm/src/commands/index.js +2 -0
  13. package/dist/esm/src/commands/index.js.map +1 -1
  14. package/dist/esm/src/commands/init.js +63 -0
  15. package/dist/esm/src/commands/init.js.map +1 -0
  16. package/dist/esm/src/commands/keystore.js +81 -0
  17. package/dist/esm/src/commands/keystore.js.map +1 -0
  18. package/dist/esm/src/commands/profile.js +6 -4
  19. package/dist/esm/src/commands/profile.js.map +1 -1
  20. package/dist/esm/src/commands/update.js +16 -2
  21. package/dist/esm/src/commands/update.js.map +1 -1
  22. package/dist/esm/src/config-schema.js +149 -0
  23. package/dist/esm/src/config-schema.js.map +1 -0
  24. package/dist/esm/src/config.js +579 -55
  25. package/dist/esm/src/config.js.map +1 -1
  26. package/dist/esm/src/keystore/file-key-store.js +340 -32
  27. package/dist/esm/src/keystore/file-key-store.js.map +1 -1
  28. package/dist/esm/src/keystore/passphrase.js +40 -10
  29. package/dist/esm/src/keystore/passphrase.js.map +1 -1
  30. package/dist/esm/src/keystore/paths.js +6 -17
  31. package/dist/esm/src/keystore/paths.js.map +1 -1
  32. package/dist/esm/src/output.js +49 -0
  33. package/dist/esm/src/output.js.map +1 -1
  34. package/dist/esm/src/paths.js +59 -0
  35. package/dist/esm/src/paths.js.map +1 -0
  36. package/dist/esm/src/types.js +11 -0
  37. package/dist/esm/src/types.js.map +1 -1
  38. package/dist/types/src/cli.d.ts.map +1 -1
  39. package/dist/types/src/commands/config.d.ts.map +1 -1
  40. package/dist/types/src/commands/create.d.ts.map +1 -1
  41. package/dist/types/src/commands/deactivate.d.ts.map +1 -1
  42. package/dist/types/src/commands/index.d.ts +2 -0
  43. package/dist/types/src/commands/index.d.ts.map +1 -1
  44. package/dist/types/src/commands/init.d.ts +13 -0
  45. package/dist/types/src/commands/init.d.ts.map +1 -0
  46. package/dist/types/src/commands/keystore.d.ts +10 -0
  47. package/dist/types/src/commands/keystore.d.ts.map +1 -0
  48. package/dist/types/src/commands/profile.d.ts.map +1 -1
  49. package/dist/types/src/commands/update.d.ts.map +1 -1
  50. package/dist/types/src/config-schema.d.ts +24 -0
  51. package/dist/types/src/config-schema.d.ts.map +1 -0
  52. package/dist/types/src/config.d.ts +252 -14
  53. package/dist/types/src/config.d.ts.map +1 -1
  54. package/dist/types/src/keystore/file-key-store.d.ts +86 -10
  55. package/dist/types/src/keystore/file-key-store.d.ts.map +1 -1
  56. package/dist/types/src/keystore/passphrase.d.ts +16 -1
  57. package/dist/types/src/keystore/passphrase.d.ts.map +1 -1
  58. package/dist/types/src/keystore/paths.d.ts +6 -10
  59. package/dist/types/src/keystore/paths.d.ts.map +1 -1
  60. package/dist/types/src/output.d.ts +22 -0
  61. package/dist/types/src/output.d.ts.map +1 -1
  62. package/dist/types/src/paths.d.ts +54 -0
  63. package/dist/types/src/paths.d.ts.map +1 -0
  64. package/dist/types/src/types.d.ts +70 -0
  65. package/dist/types/src/types.d.ts.map +1 -1
  66. package/package.json +5 -5
  67. package/src/cli.ts +32 -4
  68. package/src/commands/config.ts +143 -18
  69. package/src/commands/create.ts +16 -1
  70. package/src/commands/deactivate.ts +24 -2
  71. package/src/commands/index.ts +2 -0
  72. package/src/commands/init.ts +74 -0
  73. package/src/commands/keystore.ts +98 -0
  74. package/src/commands/profile.ts +6 -4
  75. package/src/commands/update.ts +24 -2
  76. package/src/config-schema.ts +178 -0
  77. package/src/config.ts +752 -58
  78. package/src/keystore/file-key-store.ts +455 -43
  79. package/src/keystore/passphrase.ts +48 -8
  80. package/src/keystore/paths.ts +6 -18
  81. package/src/output.ts +53 -0
  82. package/src/paths.ts +79 -0
  83. package/src/types.ts +34 -0
@@ -1,5 +1,8 @@
1
- import { type DidBtcr2Api } from '@did-btcr2/api';
2
- import { type NetworkOption, type OutputFormat } from './types.js';
1
+ import { type BitcoinApiConfig, type CasConfig, type DidBtcr2Api } from '@did-btcr2/api';
2
+ import type { BroadcastOptions } from '@did-btcr2/method';
3
+ import { defaultConfigPath } from './paths.js';
4
+ import { type KeystoreProtectionLabel, type NetworkOption, type OutputFormat } from './types.js';
5
+ export { defaultConfigPath };
3
6
  /**
4
7
  * Endpoint overrides provided via CLI flags, env vars, or config file.
5
8
  * These override the per-network defaults the SDK applies
@@ -17,12 +20,26 @@ export type ConnectionOverrides = {
17
20
  casGateway?: string;
18
21
  /** IPFS HTTP RPC endpoint for a writable CAS (reads + writes). */
19
22
  casRpcUrl?: string;
23
+ /** Bitcoin REST/RPC request timeout in milliseconds (raw flag/env string). */
24
+ btcTimeout?: string;
25
+ /** CAS request timeout in milliseconds (raw flag/env string; `0` disables). */
26
+ casTimeout?: string;
27
+ /** Extra Bitcoin REST headers as raw `Key: Value` flag values (repeatable). */
28
+ btcRestHeader?: string[];
29
+ /** Bitcoin Core RPC wallet name for wallet-scoped RPCs. */
30
+ btcRpcWallet?: string;
31
+ /** Extra Bitcoin Core RPC headers as raw `Key: Value` flag values (repeatable). */
32
+ btcRpcHeader?: string[];
33
+ /** CLI home root from `--home`. Colocates config.json + keystore.json (ADR 079). */
34
+ home?: string;
20
35
  config?: string;
21
36
  profile?: string;
22
- /** Keystore file path. Overrides the default `$XDG_DATA_HOME/btcr2/keystore.json`. */
37
+ /** Keystore file path. Overrides the home default `<home>/keystore.json`. */
23
38
  keystore?: string;
24
39
  /** Path to a file holding the keystore passphrase (for unattended use). */
25
40
  passphraseFile?: string;
41
+ /** Signing key reference (URN, fingerprint prefix, or name) from `--signing-key`. */
42
+ signingKey?: string;
26
43
  };
27
44
  /**
28
45
  * On-disk config file schema.
@@ -57,17 +74,38 @@ export type ConfigFile = {
57
74
  output?: OutputFormat;
58
75
  };
59
76
  profiles?: Record<string, {
77
+ /**
78
+ * The Bitcoin network this profile's endpoints target. Declaring it lets a
79
+ * profile that is not named after a network (e.g. `production`) still fix
80
+ * the network its `create` runs encode, and lets the CLI warn when the
81
+ * network being encoded disagrees with the profile's endpoints.
82
+ */
83
+ network?: NetworkOption;
60
84
  btc?: {
61
85
  rest?: string;
62
86
  rpcUrl?: string;
63
87
  rpcUser?: string;
64
88
  rpcPass?: string;
89
+ /** Fee rate in sats/vByte for beacon transactions (update/deactivate). */
90
+ feeRate?: number;
91
+ /** Change address for beacon transactions (ADR 044 unlinkability opt-out). */
92
+ changeAddress?: string;
93
+ /** Request timeout in milliseconds for REST/RPC calls. No default (unbounded). */
94
+ timeoutMs?: number;
95
+ /** Extra headers sent on REST (Esplora) requests, e.g. an API key. */
96
+ headers?: Record<string, string>;
97
+ /** Bitcoin Core wallet name for wallet-scoped RPCs. */
98
+ wallet?: string;
99
+ /** Extra headers sent on Bitcoin Core RPC requests. */
100
+ rpcHeaders?: Record<string, string>;
65
101
  };
66
102
  cas?: {
67
103
  /** IPFS HTTP gateway for CAS reads (read-only). */
68
104
  gateway?: string;
69
105
  /** IPFS HTTP RPC endpoint for a writable CAS (reads + writes). */
70
106
  rpcUrl?: string;
107
+ /** Request timeout in milliseconds for CAS operations. Default 30000; `0` disables. */
108
+ timeoutMs?: number;
71
109
  };
72
110
  /** Signing identity references. Never embeds key material; the secret lives in the keystore. */
73
111
  identity?: {
@@ -82,8 +120,20 @@ export declare const CONFIG_SCHEMA_VERSION = 1;
82
120
  * Read-modify-write a config file, preserving unknown keys. Reads the raw JSON
83
121
  * (so keys outside {@link ConfigFile} survive a rewrite), applies `mutate`,
84
122
  * stamps the schema version, and writes atomically (file 0600, dir 0700).
123
+ *
124
+ * A file that exists but cannot be parsed makes {@link readConfigFile} throw, so
125
+ * a write never starts from `{}` over a malformed-but-recoverable file and can
126
+ * never clobber the other profiles and defaults it still holds. A genuinely
127
+ * absent file (ENOENT) still starts from `{}`.
85
128
  */
86
129
  export declare function writeConfigFile(path: string, mutate: (raw: Record<string, unknown>) => void): void;
130
+ /**
131
+ * Writes a default config scaffold to `path`: schema version, a `text` output
132
+ * default, and one empty profile per supported network. Shared by `config init`
133
+ * and `btcr2 init` so the seeded config is identical. Writes atomically (file
134
+ * 0600, dir 0700); the caller decides whether to overwrite an existing file.
135
+ */
136
+ export declare function writeDefaultConfigFile(path: string): void;
87
137
  /** Reads the value at a dotted path (e.g. `profiles.regtest.btc.rest`). */
88
138
  export declare function getConfigPath(config: Record<string, unknown>, path: string): unknown;
89
139
  /** Sets the value at a dotted path, creating intermediate objects. */
@@ -111,6 +161,9 @@ export type ApiFactory = (network?: NetworkOption, overrides?: ConnectionOverrid
111
161
  * | `BTCR2_BTC_RPC_PASS` | `--btc-rpc-pass` |
112
162
  * | `BTCR2_CAS_GATEWAY` | `--cas-gateway` |
113
163
  * | `BTCR2_CAS_RPC_URL` | `--cas-rpc-url` |
164
+ * | `BTCR2_BTC_TIMEOUT` | `--btc-timeout` |
165
+ * | `BTCR2_CAS_TIMEOUT` | `--cas-timeout` |
166
+ * | `BTCR2_FEE_RATE` | `--fee-rate` |
114
167
  */
115
168
  export declare const ENV_VARS: {
116
169
  readonly BTC_REST: "BTCR2_BTC_REST";
@@ -119,6 +172,9 @@ export declare const ENV_VARS: {
119
172
  readonly BTC_RPC_PASS: "BTCR2_BTC_RPC_PASS";
120
173
  readonly CAS_GATEWAY: "BTCR2_CAS_GATEWAY";
121
174
  readonly CAS_RPC_URL: "BTCR2_CAS_RPC_URL";
175
+ readonly BTC_TIMEOUT: "BTCR2_BTC_TIMEOUT";
176
+ readonly CAS_TIMEOUT: "BTCR2_CAS_TIMEOUT";
177
+ readonly FEE_RATE: "BTCR2_FEE_RATE";
122
178
  };
123
179
  /**
124
180
  * Reads {@link ConnectionOverrides} from environment variables.
@@ -126,17 +182,20 @@ export declare const ENV_VARS: {
126
182
  */
127
183
  export declare function readEnvOverrides(): ConnectionOverrides;
128
184
  /**
129
- * Default config file path following the XDG Base Directory Specification.
130
- *
131
- * Resolution order:
132
- * 1. `$XDG_CONFIG_HOME/btcr2/config.json`
133
- * 2. `%APPDATA%/btcr2/config.json` (Windows)
134
- * 3. `~/.config/btcr2/config.json` (fallback)
185
+ * Reads and JSON-parses a config file without applying the schema-version
186
+ * ceiling check. Returns `undefined` only for a genuinely absent file (ENOENT).
187
+ * Any other read failure, and any JSON parse failure, throws a {@link CLIError}
188
+ * that names the file. Used by `config validate`, which reports a newer-than-
189
+ * supported `schemaVersion` as a finding rather than aborting on it.
135
190
  */
136
- export declare function defaultConfigPath(): string;
191
+ export declare function parseConfigFileRaw(path: string): Record<string, unknown> | undefined;
137
192
  /**
138
- * Reads and parses a config file. Returns `undefined` if the file does
139
- * not exist or cannot be parsed.
193
+ * Reads and parses a config file. Returns `undefined` only when the file is
194
+ * genuinely absent (ENOENT), so callers can safely treat "no file" as "use
195
+ * defaults". Any other read failure, and any JSON parse failure, throws a
196
+ * {@link CLIError} that names the file, rather than silently degrading to the
197
+ * public network defaults. A file written by a newer CLI (higher `schemaVersion`)
198
+ * is also refused.
140
199
  */
141
200
  export declare function readConfigFile(path: string): ConfigFile | undefined;
142
201
  /**
@@ -144,15 +203,160 @@ export declare function readConfigFile(path: string): ConfigFile | undefined;
144
203
  * {@link ConfigFile}. Returns an empty object if the profile does not exist.
145
204
  */
146
205
  export declare function profileToOverrides(config: ConfigFile, profileName: string): ConnectionOverrides;
206
+ /**
207
+ * Resolves the active profile name and the network it targets, shared by
208
+ * {@link resolveDefaultNetwork} and {@link resolveConnectionConfig} so the two
209
+ * can never disagree about which profile is active or which network it means.
210
+ *
211
+ * The active profile name is the explicit `--profile` flag, else the config
212
+ * file's `defaults.profile`. The network is the profile's own `network` field
213
+ * when set to a supported value, else the profile name itself when it is a
214
+ * network name (the historical convention). A profile that declares no network
215
+ * and is not named after one yields `network: undefined`.
216
+ */
217
+ export declare function resolveActiveProfile(file: ConfigFile | undefined, overrides?: ConnectionOverrides): {
218
+ name: string | undefined;
219
+ network: NetworkOption | undefined;
220
+ };
147
221
  /**
148
222
  * Resolves the default Bitcoin network for offline identifier creation when no
149
223
  * `--network` flag is given. Resolution order: the config file's
150
- * `defaults.network`, then an active profile named for a network (an explicit
151
- * `--profile` flag or `defaults.profile`), then `regtest` as the development
224
+ * `defaults.network`, then the active profile's network (its explicit `network`
225
+ * field, else its network-derived name), then `regtest` as the development
152
226
  * fallback. Generation itself is offline; this only fixes which network the
153
227
  * identifier encodes.
154
228
  */
155
229
  export declare function resolveDefaultNetwork(overrides?: ConnectionOverrides): NetworkOption;
230
+ /**
231
+ * Reports a coherence conflict between the network a `create` run is about to
232
+ * encode and the network the active profile declares, so the CLI can warn
233
+ * instead of silently minting an identifier on one network while wiring
234
+ * endpoints for another. Returns `undefined` when the active profile declares
235
+ * no network or agrees with the one being encoded.
236
+ */
237
+ export declare function profileNetworkMismatch(network: NetworkOption, overrides?: ConnectionOverrides): {
238
+ profile: string;
239
+ declared: NetworkOption;
240
+ } | undefined;
241
+ /**
242
+ * Resolves the effective output format: the `-o/--output` flag, then the
243
+ * `BTCR2_OUTPUT` environment variable, then the config file's `defaults.output`,
244
+ * then `'text'`. A malformed config never blocks output resolution (the command's
245
+ * own read path surfaces it); output format falls back to `'text'` instead.
246
+ */
247
+ export declare function resolveOutputFormat(options: {
248
+ output?: string;
249
+ config?: string;
250
+ home?: string;
251
+ }): OutputFormat;
252
+ /**
253
+ * Resolves the Bitcoin and CAS connection config for a network by merging,
254
+ * in precedence order, CLI flags, environment variables, and the config-file
255
+ * profile on top of the per-network defaults (handled by `BitcoinConnection`).
256
+ *
257
+ * Returns an empty config when no network is given, since offline operations
258
+ * (create, key management) need no connection.
259
+ *
260
+ * When no `--profile` is given, the network name is used as the profile key
261
+ * (e.g. a regtest DID auto-selects the `"regtest"` profile).
262
+ */
263
+ export declare function resolveConnectionConfig(network?: NetworkOption, overrides?: ConnectionOverrides): {
264
+ btc?: BitcoinApiConfig;
265
+ cas?: CasConfig;
266
+ };
267
+ /**
268
+ * Parses repeatable `Key: Value` header flag values into a header map. Returns
269
+ * `undefined` for an empty list. Throws a {@link CLIError} for an entry missing a
270
+ * colon or with an empty key.
271
+ */
272
+ export declare function parseHeaderList(list?: string[], flagName?: string): Record<string, string> | undefined;
273
+ /** Environment variable naming a file whose contents are the Bitcoin Core RPC password. */
274
+ export declare const ENV_RPC_PASS_FILE = "BTCR2_BTC_RPC_PASS_FILE";
275
+ /**
276
+ * Resolves an RPC-password secret reference to its literal value: `env:<VAR>`
277
+ * reads the named environment variable, `file:<path>` reads the file, and any
278
+ * other value is returned as-is. A trailing newline is trimmed from file/env
279
+ * sources so a secret written by `echo` matches an inline value (ADR 077).
280
+ */
281
+ export declare function resolveSecretRef(value?: string): string | undefined;
282
+ /**
283
+ * Resolves the beacon {@link BroadcastOptions} for an update/deactivate from the
284
+ * fee-rate and change-address knobs, following the CLI precedence chain.
285
+ *
286
+ * - Fee rate: `--fee-rate` flag, then `BTCR2_FEE_RATE`, then profile
287
+ * `btc.feeRate`. A positive sats/vByte value wrapped in a `StaticFeeEstimator`.
288
+ * - Change address: `--change-address` flag, then profile `btc.changeAddress`
289
+ * (no env, since a change address is DID/network-specific). Validated against
290
+ * the DID network by the beacon at broadcast time.
291
+ *
292
+ * Returns `undefined` when neither is set, so the SDK defaults (5 sat/vB, change
293
+ * back to the beacon address) still apply.
294
+ */
295
+ export declare function resolveBroadcastOptions(network: NetworkOption, overrides: ConnectionOverrides | undefined, flags: {
296
+ feeRate?: string;
297
+ changeAddress?: string;
298
+ }): BroadcastOptions | undefined;
299
+ /** Which precedence layer a resolved value came from. */
300
+ export type Provenance = 'flag' | 'env' | 'file' | 'default';
301
+ /** A resolved value paired with the layer it came from. */
302
+ export interface EffectiveEntry {
303
+ value: string | number | undefined;
304
+ source: Provenance;
305
+ }
306
+ /**
307
+ * The resolved connection config with per-value provenance, the shape behind
308
+ * `config effective`. Values are read through the real resolver (the constructed
309
+ * api and {@link resolveConnectionConfig}) so they cannot drift from what a live
310
+ * command would use; the `source` tag names the layer the merge selected.
311
+ */
312
+ export interface EffectiveConfig {
313
+ network: NetworkOption;
314
+ profile: string | undefined;
315
+ btc: {
316
+ rest: EffectiveEntry;
317
+ rpcUrl: EffectiveEntry;
318
+ rpcUser: EffectiveEntry;
319
+ rpcPass: EffectiveEntry;
320
+ rpcWallet: EffectiveEntry;
321
+ timeoutMs: EffectiveEntry;
322
+ };
323
+ cas: {
324
+ gateway: EffectiveEntry;
325
+ rpcUrl: EffectiveEntry;
326
+ timeoutMs: EffectiveEntry;
327
+ };
328
+ }
329
+ /**
330
+ * Resolves the effective connection config with provenance for `config effective`.
331
+ * The btc values are read back from the constructed api (so SDK network defaults
332
+ * are reflected), the cas and timeout values from {@link resolveConnectionConfig},
333
+ * and each `source` is derived by the same precedence order the merge uses.
334
+ */
335
+ export declare function resolveEffectiveConfig(network: NetworkOption, overrides?: ConnectionOverrides): EffectiveConfig;
336
+ /** One endpoint reachability check produced by `config doctor`. */
337
+ export interface DoctorCheck {
338
+ endpoint: 'btc-rest' | 'btc-rpc' | 'cas';
339
+ target: string;
340
+ ok: boolean;
341
+ detail?: string;
342
+ }
343
+ /** Result of `config doctor`: per-endpoint reachability and any coherence warning. */
344
+ export interface DoctorReport {
345
+ checks: DoctorCheck[];
346
+ coherence?: {
347
+ profile: string;
348
+ declared: NetworkOption;
349
+ encoding: NetworkOption;
350
+ };
351
+ }
352
+ /**
353
+ * Probes reachability of the resolved endpoints for `config doctor`: a
354
+ * lightweight REST call against btc-rest, a `getblockchaininfo` against btc-rpc
355
+ * when configured, and a reachability check against the resolved CAS. Also
356
+ * surfaces the profile/network coherence warning. Reads and touches the network;
357
+ * never writes.
358
+ */
359
+ export declare function runDoctor(network: NetworkOption, overrides?: ConnectionOverrides): Promise<DoctorReport>;
156
360
  /**
157
361
  * Default {@link ApiFactory} backed by network defaults from
158
362
  * `@did-btcr2/bitcoin` (mempool.space for public networks, localhost for
@@ -163,6 +367,40 @@ export declare function resolveDefaultNetwork(overrides?: ConnectionOverrides):
163
367
  * CLI flags -> env vars -> config file profile -> network defaults.
164
368
  */
165
369
  export declare function defaultApiFactory(network?: NetworkOption, overrides?: ConnectionOverrides): DidBtcr2Api;
370
+ /**
371
+ * The protection mode of the resolved keystore, read without decrypting or
372
+ * prompting: `encrypted`, `dev` (plaintext), or `absent`. Used by `keystore
373
+ * status`, `config path`, and the mainnet guard.
374
+ */
375
+ export declare function resolveKeystoreProtection(overrides?: ConnectionOverrides): KeystoreProtectionLabel;
376
+ /**
377
+ * Hard-refuses using an unencrypted dev keystore for a mainnet operation (ADR
378
+ * 080). A plaintext key must never sign or seal a `bitcoin` did:btcr2; the check
379
+ * reads only the keystore's protection header, so it never decrypts or prompts.
380
+ * A no-op for every other network and for encrypted/absent keystores.
381
+ */
382
+ export declare function assertKeystoreAllowedForNetwork(network: NetworkOption, overrides?: ConnectionOverrides): void;
383
+ /**
384
+ * Resolves the keystore file path: the `--keystore` flag, else the active
385
+ * profile's `identity.keystore`, else the default `<home>/keystore.json` (ADR
386
+ * 079). The flag always wins over the profile default and never reads the config.
387
+ *
388
+ * A malformed config aborts loudly by default so a keystore-mutating command
389
+ * never silently reads or writes the wrong store. Pass `lenient: true` only for
390
+ * diagnostic/recovery commands (`config path`, `keystore status`) that must still
391
+ * report a path instead of crashing on the very config you ran them to fix; those
392
+ * fall back to the home default when the profile identity cannot be read.
393
+ */
394
+ export declare function resolveKeystorePath(overrides?: ConnectionOverrides, options?: {
395
+ lenient?: boolean;
396
+ }): string;
397
+ /**
398
+ * Resolves the signing-key reference for update/deactivate: the `--signing-key`
399
+ * flag, else the active profile's `identity.default`, else `undefined` (letting
400
+ * the KMS fall back to its active key). The flag always wins over the profile
401
+ * default, consistent with the flag -> profile precedence used elsewhere.
402
+ */
403
+ export declare function resolveSigningKeyRef(overrides?: ConnectionOverrides): string | undefined;
166
404
  /**
167
405
  * Keystore-aware {@link ApiFactory} for commands that need a signing identity
168
406
  * (key management, update, deactivate). Identical to {@link defaultApiFactory}
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8E,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGrK,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAS1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAoC,KAAK,uBAAuB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnI,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,EAAU,MAAM,CAAC;IACzB,SAAS,CAAC,EAAQ,MAAM,CAAC;IACzB,UAAU,CAAC,EAAO,MAAM,CAAC;IACzB,UAAU,CAAC,EAAO,MAAM,CAAC;IACzB,mDAAmD;IACnD,UAAU,CAAC,EAAO,MAAM,CAAC;IACzB,kEAAkE;IAClE,SAAS,CAAC,EAAQ,MAAM,CAAC;IACzB,8EAA8E;IAC9E,UAAU,CAAC,EAAO,MAAM,CAAC;IACzB,+EAA+E;IAC/E,UAAU,CAAC,EAAO,MAAM,CAAC;IACzB,+EAA+E;IAC/E,aAAa,CAAC,EAAI,MAAM,EAAE,CAAC;IAC3B,2DAA2D;IAC3D,YAAY,CAAC,EAAK,MAAM,CAAC;IACzB,mFAAmF;IACnF,YAAY,CAAC,EAAK,MAAM,EAAE,CAAC;IAC3B,oFAAoF;IACpF,IAAI,CAAC,EAAa,MAAM,CAAC;IACzB,MAAM,CAAC,EAAW,MAAM,CAAC;IACzB,OAAO,CAAC,EAAU,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,EAAS,MAAM,CAAC;IACzB,2EAA2E;IAC3E,cAAc,CAAC,EAAG,MAAM,CAAC;IACzB,qFAAqF;IACrF,UAAU,CAAC,EAAO,MAAM,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,aAAa,CAAC;QACxB,MAAM,CAAC,EAAE,YAAY,CAAC;KACvB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QACxB;;;;;WAKG;QACH,OAAO,CAAC,EAAG,aAAa,CAAC;QACzB,GAAG,CAAC,EAAE;YACJ,IAAI,CAAC,EAAY,MAAM,CAAC;YACxB,MAAM,CAAC,EAAU,MAAM,CAAC;YACxB,OAAO,CAAC,EAAS,MAAM,CAAC;YACxB,OAAO,CAAC,EAAS,MAAM,CAAC;YACxB,0EAA0E;YAC1E,OAAO,CAAC,EAAS,MAAM,CAAC;YACxB,8EAA8E;YAC9E,aAAa,CAAC,EAAG,MAAM,CAAC;YACxB,kFAAkF;YAClF,SAAS,CAAC,EAAO,MAAM,CAAC;YACxB,sEAAsE;YACtE,OAAO,CAAC,EAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACxC,uDAAuD;YACvD,MAAM,CAAC,EAAU,MAAM,CAAC;YACxB,uDAAuD;YACvD,UAAU,CAAC,EAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;SACzC,CAAC;QACF,GAAG,CAAC,EAAE;YACJ,mDAAmD;YACnD,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,kEAAkE;YAClE,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,uFAAuF;YACvF,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,gGAAgG;QAChG,QAAQ,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,MAAM,CAAC;YAClB,OAAO,CAAC,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC,CAAC;CACJ,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI,CAMlG;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQzD;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpF;AAYD,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAWjG;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAWnF;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,KAAK,WAAW,CAAC;AAEnG;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;CAUX,CAAC;AAEX;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,mBAAmB,CAUtD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAsBpF;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAKnE;AAsBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAQ,UAAU,EACxB,WAAW,EAAG,MAAM,GACnB,mBAAmB,CAWrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAQ,UAAU,GAAG,SAAS,EAClC,SAAS,CAAC,EAAE,mBAAmB,GAC9B;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,GAAG,SAAS,CAAA;CAAE,CASlE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAWpF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAK,aAAa,EACzB,SAAS,CAAC,EAAE,mBAAmB,GAC9B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAAG,SAAS,CAa1D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAe9G;AA4CD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,CAAC,EAAI,aAAa,EACzB,SAAS,CAAC,EAAE,mBAAmB,GAC9B;IAAE,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,CAyF7C;AAwBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAgB1G;AAeD,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAoB3D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUnE;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAI,aAAa,EACxB,SAAS,EAAE,mBAAmB,GAAG,SAAS,EAC1C,KAAK,EAAM;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,gBAAgB,GAAG,SAAS,CAgB9B;AAeD,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7D,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAI,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,MAAM,EAAG,UAAU,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAG,aAAa,CAAC;IACxB,OAAO,EAAG,MAAM,GAAG,SAAS,CAAC;IAC7B,GAAG,EAAG;QACJ,IAAI,EAAQ,cAAc,CAAC;QAC3B,MAAM,EAAM,cAAc,CAAC;QAC3B,OAAO,EAAK,cAAc,CAAC;QAC3B,OAAO,EAAK,cAAc,CAAC;QAC3B,SAAS,EAAG,cAAc,CAAC;QAC3B,SAAS,EAAG,cAAc,CAAC;KAC5B,CAAC;IACF,GAAG,EAAG;QACJ,OAAO,EAAK,cAAc,CAAC;QAC3B,MAAM,EAAM,cAAc,CAAC;QAC3B,SAAS,EAAG,cAAc,CAAC;KAC5B,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,GAAG,eAAe,CAmD/G;AAED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAG,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IAC1C,MAAM,EAAK,MAAM,CAAC;IAClB,EAAE,EAAS,OAAO,CAAC;IACnB,MAAM,CAAC,EAAI,MAAM,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAO,WAAW,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,aAAa,CAAC;QAAC,QAAQ,EAAE,aAAa,CAAA;KAAE,CAAC;CACpF;AAmCD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CAmC9G;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,GAAG,WAAW,CAEvG;AAmBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,uBAAuB,CAElG;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAW7G;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAa5G;AAoBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAExF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,mBAAmB,GAAG,WAAW,CAKxG;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAUxD"}
@@ -1,33 +1,61 @@
1
1
  import type { KeyEntry, KeyIdentifier, KeyValueStore } from '@did-btcr2/key-manager';
2
+ import type { KeystoreProtectionLabel } from '../types.js';
2
3
  import type { ArgonParams } from './envelope.js';
3
4
  import { type LockOptions } from './lock.js';
4
5
  /** Current on-disk keystore file format version. */
5
6
  export declare const KEYSTORE_VERSION: 1;
7
+ /**
8
+ * How a keystore protects its secrets on disk:
9
+ * - `passphrase`: each secret is sealed in its own argon2id + XChaCha20-Poly1305
10
+ * envelope, all opened by one shared, verifier-checked passphrase.
11
+ * - `none`: a dev keystore; secrets are stored as plaintext bytes. Never prompts;
12
+ * refused for mainnet (ADR 080). For disposable testnet material only.
13
+ */
14
+ export type KeystoreProtection = 'passphrase' | 'none';
6
15
  /** Options for constructing a {@link FileKeyStore}. */
7
16
  export type FileKeyStoreOptions = {
8
17
  /** Keystore file path. Defaults to {@link defaultKeystorePath}. */
9
18
  path?: string;
10
- /** Supplies the passphrase lazily, called only when a secret must be sealed or opened. */
11
- getPassphrase: () => string;
19
+ /**
20
+ * Supplies the passphrase lazily, called only when a secret must be sealed or
21
+ * opened. `confirm` is passed as `true` only while establishing a fresh
22
+ * encrypted keystore's passphrase, so the provider prompts twice and requires
23
+ * a match; it is a no-op for non-interactive sources.
24
+ */
25
+ getPassphrase: (opts?: {
26
+ confirm?: boolean;
27
+ }) => string;
12
28
  /** argon2id cost parameters used when sealing new secrets. Defaults to {@link DEFAULT_ARGON_PARAMS}. */
13
29
  argonParams?: ArgonParams;
14
30
  /** Tuning for the cross-process write lock. Defaults documented on {@link LockOptions}. */
15
31
  lock?: LockOptions;
32
+ /**
33
+ * Protection mode to use when *establishing* a fresh keystore. Defaults to
34
+ * `passphrase` (encrypted). Ignored for an existing keystore, whose on-disk
35
+ * `protection` always wins.
36
+ */
37
+ protection?: KeystoreProtection;
16
38
  };
17
39
  /**
18
- * A Node-only, file-backed {@link KeyValueStore} that encrypts secret keys at
40
+ * A Node-only, file-backed {@link KeyValueStore} that protects secret keys at
19
41
  * rest. It satisfies the synchronous store contract by caching the parsed file
20
42
  * in memory at construction and flushing the whole file atomically on every
21
43
  * mutation.
22
44
  *
45
+ * Encrypted keystores seal each secret in its own argon2id + XChaCha20-Poly1305
46
+ * envelope under one shared passphrase, and store a `verifier` sentinel so a
47
+ * candidate passphrase is checked before it is used (ADR 080): the first
48
+ * passphrase is established with a confirm prompt, and every later use is
49
+ * verified, so a typo is a loud failure rather than a key sealed under an
50
+ * unknown or divergent passphrase. Dev keystores (`protection: 'none'`) store
51
+ * secrets as plaintext and never prompt; they are refused for mainnet by the
52
+ * command layer.
53
+ *
23
54
  * Every mutation runs under an exclusive cross-process lock and, inside that
24
- * lock, reloads the file from disk before applying its change and flushing.
25
- * Caching at construction and flushing the whole file is otherwise a lost-update
26
- * race: two `btcr2` processes that each load, then each write, would have the
27
- * second overwrite the first. The lock serializes the writers and the reload
28
- * merges any change the other made, so concurrent invocations compose instead of
29
- * clobbering. Reads stay lock-free: an atomic rename means a concurrent reader
30
- * always sees a complete file, old or new.
55
+ * lock, reloads the file from disk before applying its change and flushing, so
56
+ * concurrent `btcr2` invocations compose instead of clobbering. Reads stay
57
+ * lock-free: an atomic rename means a concurrent reader always sees a complete
58
+ * file, old or new.
31
59
  *
32
60
  * Secrets are materialized only through {@link FileKeyStore.get}. The
33
61
  * {@link FileKeyStore.list} and {@link FileKeyStore.entries} projections omit
@@ -60,5 +88,53 @@ export declare class FileKeyStore implements KeyValueStore<KeyIdentifier, KeyEnt
60
88
  * clears it. Throws if the identifier is not a known key.
61
89
  */
62
90
  setActive(id: KeyIdentifier | undefined): void;
91
+ /** The keystore's protection mode. */
92
+ get protection(): KeystoreProtection;
93
+ /**
94
+ * Re-seals every sealed secret and the verifier under a new passphrase (ADR
95
+ * 080), returning the number of secrets re-sealed. Verifies the current
96
+ * passphrase against the verifier first. Refused on a dev keystore, which has
97
+ * no passphrase.
98
+ */
99
+ changePassphrase(oldPassphrase: string, newPassphrase: string): number;
63
100
  }
101
+ /** A no-decrypt, no-prompt summary of a keystore file for `keystore status`. */
102
+ export interface KeystoreSummary {
103
+ protection: KeystoreProtectionLabel;
104
+ established: boolean;
105
+ keyCount: number;
106
+ active: string | undefined;
107
+ }
108
+ /**
109
+ * Summarizes a keystore file by structure alone: protection mode, whether a
110
+ * passphrase is established, key count, and active key. Never decrypts, never
111
+ * prompts, and never throws (a missing or unreadable file reports `absent`), so
112
+ * it is safe for `keystore status`, `config path`, and the mainnet dev-keystore
113
+ * guard.
114
+ */
115
+ export declare function keystoreSummary(path: string): KeystoreSummary;
116
+ /** The protection label of a keystore file, without decrypting or prompting. */
117
+ export declare function keystoreProtection(path: string): KeystoreProtectionLabel;
118
+ /** Options for {@link initKeystore}. */
119
+ export interface InitKeystoreOptions {
120
+ protection: KeystoreProtection;
121
+ getPassphrase: (opts?: {
122
+ confirm?: boolean;
123
+ }) => string;
124
+ argonParams?: ArgonParams;
125
+ }
126
+ /**
127
+ * Establishes a fresh keystore file (ADR 080). An encrypted keystore prompts
128
+ * (with confirm) for the passphrase and writes the verifier; a dev keystore
129
+ * writes a plaintext-mode header with no passphrase. The caller is responsible
130
+ * for refusing to overwrite an existing keystore; this always writes the file.
131
+ */
132
+ export declare function initKeystore(path: string, options: InitKeystoreOptions): void;
133
+ /**
134
+ * Re-seals every secret in an encrypted keystore under a new passphrase (ADR
135
+ * 080), returning the count re-sealed. The old and new passphrases are supplied
136
+ * explicitly, so the store's own passphrase provider is never invoked (a wrong
137
+ * current passphrase is caught by the verifier). Refused on a dev keystore.
138
+ */
139
+ export declare function changeKeystorePassphrase(path: string, oldPassphrase: string, newPassphrase: string, argonParams?: ArgonParams): number;
64
140
  //# sourceMappingURL=file-key-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-key-store.d.ts","sourceRoot":"","sources":["../../../../src/keystore/file-key-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAIrF,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG3D,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAwB3C,uDAAuD;AACvD,MAAM,MAAM,mBAAmB,GAAG;IAChC,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,wGAAwG;IACxG,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,2FAA2F;IAC3F,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,YAAa,YAAW,aAAa,CAAC,aAAa,EAAE,QAAQ,CAAC;;gBAS7D,OAAO,EAAE,mBAAmB;IAiHxC,GAAG,CAAC,EAAE,EAAE,aAAa,GAAG,QAAQ,GAAG,SAAS;IA0B5C,GAAG,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO;IAI/B,GAAG,CAAC,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI;IAgB7C,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO;IAWlC,KAAK,IAAI,IAAI;IAOb,iFAAiF;IACjF,IAAI,IAAI,KAAK,CAAC,QAAQ,CAAC;IAIvB;;;;;;OAMG;IACH,OAAO,IAAI,KAAK,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAW3C,KAAK,IAAI,IAAI;IAQb,wEAAwE;IACxE,SAAS,IAAI,MAAM,GAAG,SAAS;IAI/B;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;CAU/C"}
1
+ {"version":3,"file":"file-key-store.d.ts","sourceRoot":"","sources":["../../../../src/keystore/file-key-store.ts"],"names":[],"mappings":"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"}
@@ -8,13 +8,28 @@ export type PassphraseOptions = {
8
8
  prompt?: string;
9
9
  /** When true, prompt twice and require the entries to match (for a new keystore). */
10
10
  confirm?: boolean;
11
+ /**
12
+ * When true, skip the environment variable and passphrase file and require a
13
+ * fresh terminal entry. Used for the *new* passphrase in `change-passphrase`,
14
+ * where the env var / file holds the *current* passphrase and must not silently
15
+ * satisfy the new one (which would make the change a no-op).
16
+ */
17
+ forcePrompt?: boolean;
11
18
  };
12
19
  /**
13
20
  * Acquires a passphrase without ever reading it from a command-line flag value
14
21
  * (which would leak into process listings and shell history). Resolution order:
15
22
  * the {@link ENV_KEYSTORE_PASSPHRASE} environment variable, a passphrase file,
16
23
  * then a non-echoing terminal prompt. Throws if none is available and standard
17
- * input is not a terminal.
24
+ * input is not a terminal. When `forcePrompt` is set, the env var and file are
25
+ * skipped and a terminal entry is required.
18
26
  */
19
27
  export declare function acquirePassphrase(options?: PassphraseOptions): string;
28
+ /**
29
+ * Removes the last whole UTF-8 character from an accumulating byte array in
30
+ * place: pops any trailing continuation bytes (0b10xxxxxx) then the leading
31
+ * byte. Exported for testing; a backspace mid-entry must not strand a fragment
32
+ * that later decodes to U+FFFD.
33
+ */
34
+ export declare function dropLastUtf8Char(bytes: number[]): void;
20
35
  //# sourceMappingURL=passphrase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"passphrase.d.ts","sourceRoot":"","sources":["../../../../src/keystore/passphrase.ts"],"names":[],"mappings":"AAGA,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE,wDAAwD;AACxD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAyBzE"}
1
+ {"version":3,"file":"passphrase.d.ts","sourceRoot":"","sources":["../../../../src/keystore/passphrase.ts"],"names":[],"mappings":"AAGA,qFAAqF;AACrF,eAAO,MAAM,uBAAuB,8BAA8B,CAAC;AAEnE,wDAAwD;AACxD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,wFAAwF;IACxF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CA2BzE;AAuBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAGtD"}
@@ -1,13 +1,9 @@
1
1
  /**
2
- * Default keystore file path, following the XDG Base Directory Specification's
3
- * data directory. Secret key material is data a user accumulates, so it lives
4
- * under the data directory, kept separate from the configuration directory used
5
- * for portable settings.
6
- *
7
- * Resolution order:
8
- * 1. `$XDG_DATA_HOME/btcr2/keystore.json`
9
- * 2. `%LOCALAPPDATA%/btcr2/keystore.json` (Windows)
10
- * 3. `~/.local/share/btcr2/keystore.json` (fallback)
2
+ * The default keystore path now lives alongside the config file under a single
3
+ * CLI home root (`<home>/keystore.json`, ADR 079). The implementation lives in
4
+ * `../paths.ts` (the single source of truth for on-disk state locations); it is
5
+ * re-exported here so existing `./paths.js` importers in the keystore layer keep
6
+ * their import surface.
11
7
  */
12
- export declare function defaultKeystorePath(): string;
8
+ export { defaultKeystorePath } from '../paths.js';
13
9
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../../src/keystore/paths.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../../src/keystore/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -1,4 +1,26 @@
1
1
  import type { CommandResult, GlobalOptions } from './types.js';
2
+ /** Placeholder printed in place of a redacted secret value. */
3
+ export declare const REDACTED = "********";
4
+ /** Whether a config key name looks like a secret (so its scalar value should be redacted). */
5
+ export declare function isSecretKey(key: string): boolean;
6
+ /**
7
+ * Masks the password in a `scheme://user:pass@host` URL, leaving the rest of the
8
+ * value verbatim. A credential embedded in an endpoint URL (e.g. `rpcUrl`) is not
9
+ * caught by key-name matching, so it is scrubbed here regardless of the key.
10
+ */
11
+ export declare function scrubUrlUserinfo(value: string | undefined): string | undefined;
12
+ /**
13
+ * Returns a deep copy of `value` with secret scalar values replaced by
14
+ * {@link REDACTED}, so routine introspection (`config get`/`list`/`effective`)
15
+ * does not print RPC passwords or other secrets into terminal scrollback and CI
16
+ * logs. A secret-named key redacts only a scalar value (an object under such a
17
+ * key, e.g. a profile named `access-token`, is still traversed, not wholesale
18
+ * masked). Passwords embedded in URL values are scrubbed regardless of key name.
19
+ * When `keyName` is a secret name, a directly-passed scalar value is redacted
20
+ * (used when a single leaf value is printed). Display-only: the stored config and
21
+ * the value used to connect are untouched.
22
+ */
23
+ export declare function redactSecrets(value: unknown, keyName?: string): unknown;
2
24
  /**
3
25
  * Formats a CommandResult for console output.
4
26
  * In 'json' mode, the full result is serialized.
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAMlF"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,aAAa,CAAC;AASnC,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG9E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAevE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAMlF"}