@did-btcr2/cli 0.14.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.
- package/README.md +61 -13
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +637 -54
- package/dist/esm/src/cli.js +23 -2
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/config.js +124 -8
- package/dist/esm/src/commands/config.js.map +1 -1
- package/dist/esm/src/commands/create.js +10 -1
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/commands/deactivate.js +14 -2
- package/dist/esm/src/commands/deactivate.js.map +1 -1
- package/dist/esm/src/commands/profile.js +5 -3
- package/dist/esm/src/commands/profile.js.map +1 -1
- package/dist/esm/src/commands/update.js +14 -2
- package/dist/esm/src/commands/update.js.map +1 -1
- package/dist/esm/src/config-schema.js +149 -0
- package/dist/esm/src/config-schema.js.map +1 -0
- package/dist/esm/src/config.js +506 -39
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/keystore/paths.js +3 -2
- package/dist/esm/src/keystore/paths.js.map +1 -1
- package/dist/esm/src/output.js +49 -0
- package/dist/esm/src/output.js.map +1 -1
- package/dist/esm/src/types.js +11 -0
- package/dist/esm/src/types.js.map +1 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/commands/config.d.ts.map +1 -1
- package/dist/types/src/commands/create.d.ts.map +1 -1
- package/dist/types/src/commands/deactivate.d.ts.map +1 -1
- package/dist/types/src/commands/profile.d.ts.map +1 -1
- package/dist/types/src/commands/update.d.ts.map +1 -1
- package/dist/types/src/config-schema.d.ts +24 -0
- package/dist/types/src/config-schema.d.ts.map +1 -0
- package/dist/types/src/config.d.ts +219 -5
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/keystore/paths.d.ts.map +1 -1
- package/dist/types/src/output.d.ts +22 -0
- package/dist/types/src/output.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +32 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/cli.ts +25 -2
- package/src/commands/config.ts +135 -8
- package/src/commands/create.ts +13 -1
- package/src/commands/deactivate.ts +22 -2
- package/src/commands/profile.ts +5 -3
- package/src/commands/update.ts +22 -2
- package/src/config-schema.ts +178 -0
- package/src/config.ts +676 -43
- package/src/keystore/paths.ts +3 -2
- package/src/output.ts +53 -0
- package/src/types.ts +22 -0
|
@@ -2,9 +2,18 @@ import type { DidUpdateResult } from '@did-btcr2/api';
|
|
|
2
2
|
import type { PatchOperation } from '@did-btcr2/common';
|
|
3
3
|
import type { Btcr2DidDocument, ResolutionOptions } from '@did-btcr2/method';
|
|
4
4
|
import type { DidResolutionResult } from '@web5/dids';
|
|
5
|
+
import type { DoctorReport, EffectiveConfig } from './config.js';
|
|
6
|
+
import type { ConfigIssue } from './config-schema.js';
|
|
5
7
|
export type NetworkOption = 'bitcoin' | 'testnet3' | 'testnet4' | 'signet' | 'mutinynet' | 'regtest';
|
|
6
8
|
export type OutputFormat = 'json' | 'text';
|
|
7
9
|
export declare const SUPPORTED_NETWORKS: NetworkOption[];
|
|
10
|
+
/**
|
|
11
|
+
* Normalizes a blank value (empty or whitespace-only) to `undefined`, so a
|
|
12
|
+
* blank at any precedence layer defers to the next layer instead of masking it.
|
|
13
|
+
* A non-blank value is returned unchanged. This mirrors the `|| undefined`
|
|
14
|
+
* treatment the environment layer already applies in `readEnvOverrides`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function blankToUndef(value: string | undefined): string | undefined;
|
|
8
17
|
export interface ResolveCommandOptions {
|
|
9
18
|
identifier: string;
|
|
10
19
|
options?: ResolutionOptions;
|
|
@@ -100,6 +109,24 @@ export type CommandResult = {
|
|
|
100
109
|
} | {
|
|
101
110
|
action: 'config-list';
|
|
102
111
|
data: unknown;
|
|
112
|
+
} | {
|
|
113
|
+
action: 'config-validate';
|
|
114
|
+
data: {
|
|
115
|
+
ok: boolean;
|
|
116
|
+
issues: ConfigIssue[];
|
|
117
|
+
};
|
|
118
|
+
} | {
|
|
119
|
+
action: 'config-effective';
|
|
120
|
+
data: EffectiveConfig;
|
|
121
|
+
} | {
|
|
122
|
+
action: 'config-path';
|
|
123
|
+
data: {
|
|
124
|
+
config: string;
|
|
125
|
+
keystore: string;
|
|
126
|
+
};
|
|
127
|
+
} | {
|
|
128
|
+
action: 'config-doctor';
|
|
129
|
+
data: DoctorReport;
|
|
103
130
|
} | {
|
|
104
131
|
action: 'profile-add';
|
|
105
132
|
data: {
|
|
@@ -131,6 +158,11 @@ export interface GlobalOptions {
|
|
|
131
158
|
btcRpcPass?: string;
|
|
132
159
|
casGateway?: string;
|
|
133
160
|
casRpcUrl?: string;
|
|
161
|
+
btcTimeout?: string;
|
|
162
|
+
casTimeout?: string;
|
|
163
|
+
btcRestHeader?: string[];
|
|
164
|
+
btcRpcWallet?: string;
|
|
165
|
+
btcRpcHeader?: string[];
|
|
134
166
|
keystore?: string;
|
|
135
167
|
passphraseFile?: string;
|
|
136
168
|
signingKey?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@did-btcr2/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for interacting with did-btcr2-js, the JavaScript/TypeScript reference implementation of the did:btcr2 method. Exposes various parts of multiple packages in the did-btcr2-js monorepo.",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"@scure/base": "^1.2.6",
|
|
62
62
|
"@web5/dids": "^1.2.0",
|
|
63
63
|
"commander": "^13.1.0",
|
|
64
|
-
"@did-btcr2/common": "^9.1.0",
|
|
65
64
|
"@did-btcr2/keypair": "^0.13.1",
|
|
66
|
-
"@did-btcr2/
|
|
67
|
-
"@did-btcr2/
|
|
68
|
-
"@did-btcr2/
|
|
65
|
+
"@did-btcr2/api": "^0.16.1",
|
|
66
|
+
"@did-btcr2/key-manager": "^0.7.0",
|
|
67
|
+
"@did-btcr2/common": "^9.1.0",
|
|
68
|
+
"@did-btcr2/method": "^0.54.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@eslint/js": "^9.21.0",
|
package/src/cli.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
registerResolveCommand,
|
|
11
11
|
registerUpdateCommand,
|
|
12
12
|
} from './commands/index.js';
|
|
13
|
-
import { defaultApiFactory, keystoreApiFactory, type ApiFactory } from './config.js';
|
|
13
|
+
import { defaultApiFactory, keystoreApiFactory, resolveOutputFormat, type ApiFactory } from './config.js';
|
|
14
14
|
import type { GlobalOptions } from './types.js';
|
|
15
15
|
import { VERSION } from './version.js';
|
|
16
16
|
|
|
@@ -41,7 +41,7 @@ export class DidBtcr2Cli {
|
|
|
41
41
|
this.program = new Command('btcr2')
|
|
42
42
|
.version(`btcr2 ${VERSION}`, '-v, --version', 'Output the current version')
|
|
43
43
|
.description('CLI tool for the did:btcr2 method')
|
|
44
|
-
.option('-o, --output <format>', 'Output format <json|text>
|
|
44
|
+
.option('-o, --output <format>', 'Output format <json|text> (default: config defaults.output, else text)')
|
|
45
45
|
.option('--verbose', 'Verbose output', false)
|
|
46
46
|
.option('--quiet', 'Suppress non-essential output', false)
|
|
47
47
|
.option('-c, --config <path>', 'Path to config file (default: $XDG_CONFIG_HOME/btcr2/config.json)')
|
|
@@ -52,12 +52,27 @@ export class DidBtcr2Cli {
|
|
|
52
52
|
.option('--btc-rpc-pass <pass>', 'Bitcoin Core RPC password')
|
|
53
53
|
.option('--cas-gateway <url>', 'IPFS HTTP gateway for CAS reads (read-only)')
|
|
54
54
|
.option('--cas-rpc-url <url>', 'IPFS HTTP RPC endpoint for a writable CAS (reads + writes; enables --publish-to-cas)')
|
|
55
|
+
.option('--btc-timeout <ms>', 'Bitcoin REST/RPC request timeout in milliseconds (default: unbounded)')
|
|
56
|
+
.option('--cas-timeout <ms>', 'CAS request timeout in milliseconds (default: 30000; 0 disables)')
|
|
57
|
+
.option('--btc-rest-header <header>', 'Extra Bitcoin REST header "Key: Value" (repeatable)', collectHeader, [])
|
|
58
|
+
.option('--btc-rpc-wallet <name>', 'Bitcoin Core wallet name for wallet-scoped RPCs')
|
|
59
|
+
.option('--btc-rpc-header <header>', 'Extra Bitcoin Core RPC header "Key: Value" (repeatable)', collectHeader, [])
|
|
55
60
|
.option('--keystore <path>', 'Path to the keystore file (default: $XDG_DATA_HOME/btcr2/keystore.json)')
|
|
56
61
|
.option('--passphrase-file <path>', 'Read the keystore passphrase from a file (unattended use)')
|
|
57
62
|
.option('--signing-key <ref>', 'Key for create/update/deactivate signing: a URN, fingerprint prefix, or name');
|
|
58
63
|
|
|
59
64
|
const globals = (): GlobalOptions => this.program.opts() as GlobalOptions;
|
|
60
65
|
|
|
66
|
+
// Resolve the effective output format (flag -> BTCR2_OUTPUT -> config
|
|
67
|
+
// defaults.output -> 'text') before any command action runs, so a configured
|
|
68
|
+
// default is honored while an explicit flag still wins. The commander option
|
|
69
|
+
// carries no hard default (which would mask defaults.output); the resolved
|
|
70
|
+
// value is written back so every command reads it through globals().output.
|
|
71
|
+
this.program.hook('preAction', () => {
|
|
72
|
+
const opts = this.program.opts() as GlobalOptions;
|
|
73
|
+
opts.output = resolveOutputFormat({ output: opts.output, config: opts.config });
|
|
74
|
+
});
|
|
75
|
+
|
|
61
76
|
registerCreateCommand(this.program, factory, keystoreFactory, globals);
|
|
62
77
|
registerResolveCommand(this.program, factory, globals);
|
|
63
78
|
registerUpdateCommand(this.program, keystoreFactory, globals);
|
|
@@ -84,6 +99,14 @@ export class DidBtcr2Cli {
|
|
|
84
99
|
}
|
|
85
100
|
}
|
|
86
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Commander collector for a repeatable header option: accumulates each
|
|
104
|
+
* `Key: Value` occurrence into an array, preserving order.
|
|
105
|
+
*/
|
|
106
|
+
function collectHeader(value: string, previous: string[]): string[] {
|
|
107
|
+
return [ ...previous, value ];
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
/**
|
|
88
111
|
* Normalizes argv to ensure it has at least two elements.
|
|
89
112
|
* @param {string[]} argv - The original argv array.
|
package/src/commands/config.ts
CHANGED
|
@@ -5,15 +5,21 @@ import {
|
|
|
5
5
|
CONFIG_SCHEMA_VERSION,
|
|
6
6
|
defaultConfigPath,
|
|
7
7
|
getConfigPath,
|
|
8
|
+
parseConfigFileRaw,
|
|
8
9
|
readConfigFile,
|
|
10
|
+
resolveDefaultNetwork,
|
|
11
|
+
resolveEffectiveConfig,
|
|
12
|
+
runDoctor,
|
|
9
13
|
setConfigPath,
|
|
10
14
|
unsetConfigPath,
|
|
11
15
|
writeConfigFile,
|
|
12
16
|
} from '../config.js';
|
|
17
|
+
import { findConfigIssues, validateConfigSet } from '../config-schema.js';
|
|
13
18
|
import { CLIError } from '../error.js';
|
|
14
19
|
import { ensureDir, writeFileAtomic } from '../keystore/atomic.js';
|
|
15
|
-
import {
|
|
16
|
-
import
|
|
20
|
+
import { defaultKeystorePath } from '../keystore/paths.js';
|
|
21
|
+
import { formatResult, REDACTED, redactSecrets, scrubUrlUserinfo } from '../output.js';
|
|
22
|
+
import type { CommandResult, GlobalOptions, NetworkOption } from '../types.js';
|
|
17
23
|
import { SUPPORTED_NETWORKS } from '../types.js';
|
|
18
24
|
|
|
19
25
|
/** Registers the `config` command group for reading and writing CLI configuration. */
|
|
@@ -44,16 +50,26 @@ export function registerConfigCommand(program: Command, globals: () => GlobalOpt
|
|
|
44
50
|
config
|
|
45
51
|
.command('get [path]')
|
|
46
52
|
.description('Print a value at a dotted path, or the whole config.')
|
|
47
|
-
.
|
|
53
|
+
.option('--show-secrets', 'Reveal secret values (RPC password, etc.) instead of redacting them.', false)
|
|
54
|
+
.action((dotted: string | undefined, opts: { showSecrets?: boolean }) => {
|
|
48
55
|
const file = (readConfigFile(path()) ?? {}) as Record<string, unknown>;
|
|
49
|
-
|
|
56
|
+
const raw = (dotted ? getConfigPath(file, dotted) : file) ?? null;
|
|
57
|
+
const leaf = dotted ? dotted.split('.').pop() : undefined;
|
|
58
|
+
print({ action: 'config-get', data: opts.showSecrets ? raw : redactSecrets(raw, leaf) });
|
|
50
59
|
});
|
|
51
60
|
|
|
52
61
|
config
|
|
53
62
|
.command('set <path> <value>')
|
|
54
63
|
.description('Set a value at a dotted path. The value is parsed as JSON when valid, else stored as a string.')
|
|
55
64
|
.action((dotted: string, value: string) => {
|
|
56
|
-
|
|
65
|
+
const parsed = parseValue(dotted, value);
|
|
66
|
+
// Reject an invalid enum value for a known key up-front; warn (but still
|
|
67
|
+
// write) an unknown path so forward-compatible and third-party keys work.
|
|
68
|
+
const { unknownPath } = validateConfigSet(dotted, parsed);
|
|
69
|
+
if (unknownPath && !globals().quiet) {
|
|
70
|
+
console.error(`Warning: "${dotted}" is not a known config path; writing it anyway.`);
|
|
71
|
+
}
|
|
72
|
+
writeConfigFile(path(), raw => setConfigPath(raw, dotted, parsed));
|
|
57
73
|
print({ action: 'config-set', data: { path: dotted } });
|
|
58
74
|
});
|
|
59
75
|
|
|
@@ -69,16 +85,127 @@ export function registerConfigCommand(program: Command, globals: () => GlobalOpt
|
|
|
69
85
|
.command('list')
|
|
70
86
|
.alias('ls')
|
|
71
87
|
.description('Print the entire config file.')
|
|
88
|
+
.option('--show-secrets', 'Reveal secret values (RPC password, etc.) instead of redacting them.', false)
|
|
89
|
+
.action((opts: { showSecrets?: boolean }) => {
|
|
90
|
+
const file = readConfigFile(path()) ?? {};
|
|
91
|
+
print({ action: 'config-list', data: opts.showSecrets ? file : redactSecrets(file) });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
config
|
|
95
|
+
.command('validate')
|
|
96
|
+
.description('Check the config for unknown keys, invalid enum values, and an unsupported schema version.')
|
|
97
|
+
.action(() => {
|
|
98
|
+
// Read raw (bypassing the schema-version ceiling that readConfigFile
|
|
99
|
+
// enforces) so a newer-than-supported version is reported as a finding
|
|
100
|
+
// rather than aborting the very command meant to diagnose it.
|
|
101
|
+
const file = parseConfigFileRaw(path()) ?? {};
|
|
102
|
+
const issues = findConfigIssues(file, CONFIG_SCHEMA_VERSION);
|
|
103
|
+
if (issues.length > 0) process.exitCode ??= 1;
|
|
104
|
+
print({ action: 'config-validate', data: { ok: issues.length === 0, issues } });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
config
|
|
108
|
+
.command('effective')
|
|
109
|
+
.description('Print the resolved connection config with per-value provenance (flag|env|file|default).')
|
|
110
|
+
.option('-n, --network <network>', 'Network to resolve for (default: config default network)')
|
|
111
|
+
.option('--show-secrets', 'Reveal secret values (RPC password) instead of redacting them.', false)
|
|
112
|
+
.action((opts: { network?: string; showSecrets?: boolean }) => {
|
|
113
|
+
const network = resolveIntrospectionNetwork(opts.network, globals());
|
|
114
|
+
const data = resolveEffectiveConfig(network, globals());
|
|
115
|
+
// Redact the resolved RPC password and any password embedded in an endpoint
|
|
116
|
+
// URL by default; provenance still shows where each value came from.
|
|
117
|
+
// --show-secrets reveals them for deliberate debugging.
|
|
118
|
+
if (!opts.showSecrets) {
|
|
119
|
+
if (data.btc.rpcPass.value !== undefined) {
|
|
120
|
+
data.btc.rpcPass = { ...data.btc.rpcPass, value: REDACTED };
|
|
121
|
+
}
|
|
122
|
+
for (const entry of [ data.btc.rest, data.btc.rpcUrl, data.cas.gateway, data.cas.rpcUrl ]) {
|
|
123
|
+
if (typeof entry.value === 'string') entry.value = scrubUrlUserinfo(entry.value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
print({ action: 'config-effective', data });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
config
|
|
130
|
+
.command('path')
|
|
131
|
+
.description('Print the resolved config-file and keystore paths.')
|
|
72
132
|
.action(() => {
|
|
73
|
-
|
|
133
|
+
const data = {
|
|
134
|
+
config : globals().config ?? defaultConfigPath(),
|
|
135
|
+
keystore : globals().keystore ?? defaultKeystorePath(),
|
|
136
|
+
};
|
|
137
|
+
print({ action: 'config-path', data });
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
config
|
|
141
|
+
.command('doctor')
|
|
142
|
+
.description('Probe reachability of the resolved endpoints (read-only; touches the network).')
|
|
143
|
+
.option('-n, --network <network>', 'Network to resolve for (default: config default network)')
|
|
144
|
+
.action(async (opts: { network?: string }) => {
|
|
145
|
+
const network = resolveIntrospectionNetwork(opts.network, globals());
|
|
146
|
+
const report = await runDoctor(network, globals());
|
|
147
|
+
if (report.checks.some(check => !check.ok)) process.exitCode ??= 1;
|
|
148
|
+
print({ action: 'config-doctor', data: report });
|
|
74
149
|
});
|
|
75
150
|
}
|
|
76
151
|
|
|
77
|
-
/**
|
|
78
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Resolves the network an introspection command (`effective`/`doctor`) operates
|
|
154
|
+
* on: an explicit `--network`, validated, else the config's default network.
|
|
155
|
+
*/
|
|
156
|
+
function resolveIntrospectionNetwork(explicit: string | undefined, globals: GlobalOptions): NetworkOption {
|
|
157
|
+
if (explicit) {
|
|
158
|
+
if (!SUPPORTED_NETWORKS.includes(explicit as NetworkOption)) {
|
|
159
|
+
throw new CLIError(
|
|
160
|
+
`Invalid network "${explicit}". Must be one of ${SUPPORTED_NETWORKS.join(', ')}.`,
|
|
161
|
+
'INVALID_ARGUMENT_ERROR',
|
|
162
|
+
{ network: explicit },
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return explicit as NetworkOption;
|
|
166
|
+
}
|
|
167
|
+
return resolveDefaultNetwork(globals);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Parses a `config set` value. Known scalar endpoint, credential, and defaults
|
|
172
|
+
* paths are stored as raw strings so a bare `8080` is not coerced to the number
|
|
173
|
+
* `8080` (which would flow into a host field as a non-string). Every other path
|
|
174
|
+
* is parsed as JSON when valid, else stored as a plain string, so structured
|
|
175
|
+
* values (objects, arrays, booleans, and genuinely numeric fields) still work.
|
|
176
|
+
*/
|
|
177
|
+
function parseValue(dotted: string, value: string): unknown {
|
|
178
|
+
if (isStringScalarPath(dotted)) return value;
|
|
79
179
|
try {
|
|
80
180
|
return JSON.parse(value);
|
|
81
181
|
} catch {
|
|
82
182
|
return value;
|
|
83
183
|
}
|
|
84
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Whether a dotted config path addresses a leaf that must be stored as a string
|
|
188
|
+
* (an endpoint URL, a credential, a network/profile/output name), so JSON
|
|
189
|
+
* coercion never turns it into a non-string.
|
|
190
|
+
*/
|
|
191
|
+
function isStringScalarPath(dotted: string): boolean {
|
|
192
|
+
const segments = dotted.split('.');
|
|
193
|
+
|
|
194
|
+
if (segments.length === 2 && segments[0] === 'defaults') {
|
|
195
|
+
return [ 'profile', 'network', 'output' ].includes(segments[1]);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (segments.length === 3 && segments[0] === 'profiles' && segments[2] === 'network') {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (segments.length === 4 && segments[0] === 'profiles') {
|
|
203
|
+
const group = segments[2];
|
|
204
|
+
const leaf = segments[3];
|
|
205
|
+
if (group === 'btc') return [ 'rest', 'rpcUrl', 'rpcUser', 'rpcPass', 'changeAddress', 'wallet' ].includes(leaf);
|
|
206
|
+
if (group === 'cas') return [ 'gateway', 'rpcUrl' ].includes(leaf);
|
|
207
|
+
if (group === 'identity') return [ 'keystore', 'default' ].includes(leaf);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return false;
|
|
211
|
+
}
|
package/src/commands/create.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
|
|
2
2
|
import type { Command } from 'commander';
|
|
3
3
|
import type { ApiFactory, ConnectionOverrides } from '../config.js';
|
|
4
|
-
import { resolveDefaultNetwork } from '../config.js';
|
|
4
|
+
import { profileNetworkMismatch, resolveDefaultNetwork } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -63,6 +63,18 @@ export function registerCreateCommand(
|
|
|
63
63
|
const network = resolveNetwork(options.network, overrides);
|
|
64
64
|
const signingKey = g.signingKey;
|
|
65
65
|
|
|
66
|
+
// Warn (never block) when the network being encoded disagrees with the
|
|
67
|
+
// active profile's declared network, so a `production` profile holding
|
|
68
|
+
// mainnet endpoints cannot silently mint a regtest DID.
|
|
69
|
+
const mismatch = profileNetworkMismatch(network, overrides);
|
|
70
|
+
if (mismatch && !g.quiet) {
|
|
71
|
+
process.stderr.write(
|
|
72
|
+
`Warning: creating a "${network}" identifier while the active profile `
|
|
73
|
+
+ `"${mismatch.profile}" declares network "${mismatch.declared}". The `
|
|
74
|
+
+ 'identifier\'s network and the profile\'s endpoints may not match.\n'
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
/** Prints the result, plus a stderr provenance line in text mode. */
|
|
67
79
|
const print = (result: CommandResult, note?: string): void => {
|
|
68
80
|
console.log(formatResult(result, g));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PublishToCasMode } from '@did-btcr2/api';
|
|
2
2
|
import { KeyManagerSigner } from '@did-btcr2/key-manager';
|
|
3
3
|
import type { Command } from 'commander';
|
|
4
|
-
import { deriveNetwork, type ApiFactory } from '../config.js';
|
|
4
|
+
import { deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -44,12 +44,24 @@ export function registerDeactivateCommand(
|
|
|
44
44
|
parsePublishToCasMode,
|
|
45
45
|
'never',
|
|
46
46
|
)
|
|
47
|
+
.option(
|
|
48
|
+
'--fee-rate <satsPerVByte>',
|
|
49
|
+
'Fee rate in sats/vByte for the beacon transaction (default: 5). '
|
|
50
|
+
+ 'Raise it under congestion so the transaction confirms.',
|
|
51
|
+
)
|
|
52
|
+
.option(
|
|
53
|
+
'--change-address <address>',
|
|
54
|
+
'Send transaction change to this address instead of the beacon address, '
|
|
55
|
+
+ 'so a DID\'s announcements are not linked on-chain (ADR 044).',
|
|
56
|
+
)
|
|
47
57
|
.action(async (options: {
|
|
48
58
|
sourceDocument : unknown;
|
|
49
59
|
sourceVersionId : string;
|
|
50
60
|
verificationMethodId : string;
|
|
51
61
|
beaconId : unknown;
|
|
52
62
|
publishToCas : PublishToCasMode;
|
|
63
|
+
feeRate? : string;
|
|
64
|
+
changeAddress? : string;
|
|
53
65
|
}) => {
|
|
54
66
|
if (!/^\d+$/.test(options.sourceVersionId)) {
|
|
55
67
|
throw new CLIError(
|
|
@@ -77,8 +89,15 @@ export function registerDeactivateCommand(
|
|
|
77
89
|
// method has no separate deactivate path, so this routes through update.
|
|
78
90
|
const network = deriveNetwork(did);
|
|
79
91
|
const api = factory(network, globals());
|
|
80
|
-
const keyId = resolveKeyRef(api.kms.kms, globals()
|
|
92
|
+
const keyId = resolveKeyRef(api.kms.kms, resolveSigningKeyRef(globals()));
|
|
81
93
|
const signer = new KeyManagerSigner(api.kms.kms, keyId);
|
|
94
|
+
// Resolve fee-rate/change-address through the flag -> env -> profile chain
|
|
95
|
+
// into beacon broadcast options. Undefined when neither is set, so the
|
|
96
|
+
// SDK defaults (5 sat/vB, change back to the beacon address) still apply.
|
|
97
|
+
const broadcastOptions = resolveBroadcastOptions(network, globals(), {
|
|
98
|
+
feeRate : options.feeRate,
|
|
99
|
+
changeAddress : options.changeAddress,
|
|
100
|
+
});
|
|
82
101
|
// CAS publication is optional and never required: every beacon update can
|
|
83
102
|
// be completed and shared via sidecar alone. It is opt-in and defaults to
|
|
84
103
|
// 'never'; pass --publish-to-cas auto|always to publish the signed update
|
|
@@ -93,6 +112,7 @@ export function registerDeactivateCommand(
|
|
|
93
112
|
beaconId : parsed.beaconId,
|
|
94
113
|
signer,
|
|
95
114
|
publishToCas : options.publishToCas,
|
|
115
|
+
...(broadcastOptions ? { broadcastOptions } : {}),
|
|
96
116
|
});
|
|
97
117
|
console.log(formatResult({ action: 'deactivate', data }, globals()));
|
|
98
118
|
});
|
package/src/commands/profile.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
2
|
import { defaultConfigPath, readConfigFile, writeConfigFile } from '../config.js';
|
|
3
3
|
import { CLIError } from '../error.js';
|
|
4
|
-
import { formatResult } from '../output.js';
|
|
4
|
+
import { formatResult, redactSecrets } from '../output.js';
|
|
5
5
|
import type { CommandResult, GlobalOptions } from '../types.js';
|
|
6
6
|
|
|
7
7
|
/** Registers the `profile` command group for managing configuration profiles. */
|
|
@@ -37,7 +37,8 @@ export function registerProfileCommand(program: Command, globals: () => GlobalOp
|
|
|
37
37
|
profile
|
|
38
38
|
.command('show [name]')
|
|
39
39
|
.description('Show a profile (defaults to the active profile).')
|
|
40
|
-
.
|
|
40
|
+
.option('--show-secrets', 'Reveal secret values (RPC password, etc.) instead of redacting them.', false)
|
|
41
|
+
.action((name: string | undefined, opts: { showSecrets?: boolean }) => {
|
|
41
42
|
const file = readConfigFile(path()) ?? {};
|
|
42
43
|
const target = name ?? file.defaults?.profile;
|
|
43
44
|
if (!target) {
|
|
@@ -47,7 +48,8 @@ export function registerProfileCommand(program: Command, globals: () => GlobalOp
|
|
|
47
48
|
if (!data) {
|
|
48
49
|
throw new CLIError(`Profile "${target}" not found.`, 'INVALID_ARGUMENT_ERROR', { profile: target });
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
const payload = { profile: target, ...data };
|
|
52
|
+
print({ action: 'profile-show', data: opts.showSecrets ? payload : redactSecrets(payload) });
|
|
51
53
|
});
|
|
52
54
|
|
|
53
55
|
profile
|
package/src/commands/update.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PublishToCasMode } from '@did-btcr2/api';
|
|
2
2
|
import { KeyManagerSigner } from '@did-btcr2/key-manager';
|
|
3
3
|
import type { Command } from 'commander';
|
|
4
|
-
import { deriveNetwork, type ApiFactory } from '../config.js';
|
|
4
|
+
import { deriveNetwork, resolveBroadcastOptions, resolveSigningKeyRef, type ApiFactory } from '../config.js';
|
|
5
5
|
import { CLIError } from '../error.js';
|
|
6
6
|
import { resolveKeyRef } from '../keystore/resolve-key-ref.js';
|
|
7
7
|
import { formatResult } from '../output.js';
|
|
@@ -45,6 +45,16 @@ export function registerUpdateCommand(
|
|
|
45
45
|
parsePublishToCasMode,
|
|
46
46
|
'never',
|
|
47
47
|
)
|
|
48
|
+
.option(
|
|
49
|
+
'--fee-rate <satsPerVByte>',
|
|
50
|
+
'Fee rate in sats/vByte for the beacon transaction (default: 5). '
|
|
51
|
+
+ 'Raise it under congestion so the transaction confirms.',
|
|
52
|
+
)
|
|
53
|
+
.option(
|
|
54
|
+
'--change-address <address>',
|
|
55
|
+
'Send transaction change to this address instead of the beacon address, '
|
|
56
|
+
+ 'so a DID\'s announcements are not linked on-chain (ADR 044).',
|
|
57
|
+
)
|
|
48
58
|
.action(async (options: {
|
|
49
59
|
sourceDocument : unknown;
|
|
50
60
|
sourceVersionId : string;
|
|
@@ -52,6 +62,8 @@ export function registerUpdateCommand(
|
|
|
52
62
|
verificationMethodId : string;
|
|
53
63
|
beaconId : unknown;
|
|
54
64
|
publishToCas : PublishToCasMode;
|
|
65
|
+
feeRate? : string;
|
|
66
|
+
changeAddress? : string;
|
|
55
67
|
}) => {
|
|
56
68
|
if (!/^\d+$/.test(options.sourceVersionId)) {
|
|
57
69
|
throw new CLIError(
|
|
@@ -77,8 +89,15 @@ export function registerUpdateCommand(
|
|
|
77
89
|
}
|
|
78
90
|
const network = deriveNetwork(did);
|
|
79
91
|
const api = factory(network, globals());
|
|
80
|
-
const keyId = resolveKeyRef(api.kms.kms, globals()
|
|
92
|
+
const keyId = resolveKeyRef(api.kms.kms, resolveSigningKeyRef(globals()));
|
|
81
93
|
const signer = new KeyManagerSigner(api.kms.kms, keyId);
|
|
94
|
+
// Resolve fee-rate/change-address through the flag -> env -> profile chain
|
|
95
|
+
// into beacon broadcast options. Undefined when neither is set, so the
|
|
96
|
+
// SDK defaults (5 sat/vB, change back to the beacon address) still apply.
|
|
97
|
+
const broadcastOptions = resolveBroadcastOptions(network, globals(), {
|
|
98
|
+
feeRate : options.feeRate,
|
|
99
|
+
changeAddress : options.changeAddress,
|
|
100
|
+
});
|
|
82
101
|
// CAS publication is optional and never required: every beacon update can
|
|
83
102
|
// be completed and shared via sidecar alone. It is opt-in and defaults to
|
|
84
103
|
// 'never'; pass --publish-to-cas auto|always to publish the signed update
|
|
@@ -93,6 +112,7 @@ export function registerUpdateCommand(
|
|
|
93
112
|
beaconId : parsed.beaconId,
|
|
94
113
|
signer,
|
|
95
114
|
publishToCas : options.publishToCas,
|
|
115
|
+
...(broadcastOptions ? { broadcastOptions } : {}),
|
|
96
116
|
});
|
|
97
117
|
console.log(formatResult({ action: 'update', data }, globals()));
|
|
98
118
|
});
|