@did-btcr2/cli 0.12.18 → 0.14.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 +37 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +48 -9
- package/dist/esm/src/cli.js +2 -1
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/deactivate.js +19 -0
- package/dist/esm/src/commands/deactivate.js.map +1 -1
- package/dist/esm/src/commands/update.js +19 -0
- package/dist/esm/src/commands/update.js.map +1 -1
- package/dist/esm/src/config.js +15 -2
- package/dist/esm/src/config.js.map +1 -1
- package/dist/esm/src/types.js.map +1 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/commands/deactivate.d.ts.map +1 -1
- package/dist/types/src/commands/update.d.ts.map +1 -1
- package/dist/types/src/config.d.ts +9 -1
- package/dist/types/src/config.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +5 -3
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/cli.ts +2 -1
- package/src/commands/deactivate.ts +31 -0
- package/src/commands/update.ts +31 -0
- package/src/config.ts +22 -5
- package/src/types.ts +5 -3
package/src/commands/update.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PublishToCasMode } from '@did-btcr2/api';
|
|
1
2
|
import { KeyManagerSigner } from '@did-btcr2/key-manager';
|
|
2
3
|
import type { Command } from 'commander';
|
|
3
4
|
import { deriveNetwork, type ApiFactory } from '../config.js';
|
|
@@ -37,12 +38,20 @@ export function registerUpdateCommand(
|
|
|
37
38
|
'Beacon ID as a JSON string',
|
|
38
39
|
parseJsonArg('--beacon-id'),
|
|
39
40
|
)
|
|
41
|
+
.option(
|
|
42
|
+
'--publish-to-cas <mode>',
|
|
43
|
+
'Publish update artifacts to a writable CAS before broadcast: auto|always|never. '
|
|
44
|
+
+ 'CAS publication is optional; the default distributes the returned artifacts via sidecar.',
|
|
45
|
+
parsePublishToCasMode,
|
|
46
|
+
'never',
|
|
47
|
+
)
|
|
40
48
|
.action(async (options: {
|
|
41
49
|
sourceDocument : unknown;
|
|
42
50
|
sourceVersionId : string;
|
|
43
51
|
patches : unknown;
|
|
44
52
|
verificationMethodId : string;
|
|
45
53
|
beaconId : unknown;
|
|
54
|
+
publishToCas : PublishToCasMode;
|
|
46
55
|
}) => {
|
|
47
56
|
if (!/^\d+$/.test(options.sourceVersionId)) {
|
|
48
57
|
throw new CLIError(
|
|
@@ -70,6 +79,12 @@ export function registerUpdateCommand(
|
|
|
70
79
|
const api = factory(network, globals());
|
|
71
80
|
const keyId = resolveKeyRef(api.kms.kms, globals().signingKey);
|
|
72
81
|
const signer = new KeyManagerSigner(api.kms.kms, keyId);
|
|
82
|
+
// CAS publication is optional and never required: every beacon update can
|
|
83
|
+
// be completed and shared via sidecar alone. It is opt-in and defaults to
|
|
84
|
+
// 'never'; pass --publish-to-cas auto|always to publish the signed update
|
|
85
|
+
// (and, for CAS beacons, the announcement) to a writable CAS configured
|
|
86
|
+
// via --cas-rpc-url. The returned artifacts (txid, announcement, proof)
|
|
87
|
+
// are always printed for sidecar distribution regardless.
|
|
73
88
|
const data = await api.btcr2.update({
|
|
74
89
|
sourceDocument : parsed.sourceDocument,
|
|
75
90
|
patches : parsed.patches,
|
|
@@ -77,11 +92,27 @@ export function registerUpdateCommand(
|
|
|
77
92
|
verificationMethodId : parsed.verificationMethodId,
|
|
78
93
|
beaconId : parsed.beaconId,
|
|
79
94
|
signer,
|
|
95
|
+
publishToCas : options.publishToCas,
|
|
80
96
|
});
|
|
81
97
|
console.log(formatResult({ action: 'update', data }, globals()));
|
|
82
98
|
});
|
|
83
99
|
}
|
|
84
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Commander argParser for `--publish-to-cas`. Validates the value is one of the
|
|
103
|
+
* three {@link PublishToCasMode} policies, erroring at parse time otherwise.
|
|
104
|
+
*/
|
|
105
|
+
function parsePublishToCasMode(value: string): PublishToCasMode {
|
|
106
|
+
if (value !== 'auto' && value !== 'always' && value !== 'never') {
|
|
107
|
+
throw new CLIError(
|
|
108
|
+
'--publish-to-cas must be one of "auto", "always", or "never".',
|
|
109
|
+
'INVALID_ARGUMENT_ERROR',
|
|
110
|
+
{ value },
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
|
|
85
116
|
/**
|
|
86
117
|
* Returns a commander argParser that validates JSON.
|
|
87
118
|
* Errors at parse time with a clear flag reference.
|
package/src/config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createApi, Identifier, type BitcoinApiConfig, type DidBtcr2Api } from '@did-btcr2/api';
|
|
1
|
+
import { createApi, Identifier, type BitcoinApiConfig, type CasConfig, type DidBtcr2Api } from '@did-btcr2/api';
|
|
2
2
|
import type { KeyManager } from '@did-btcr2/key-manager';
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
@@ -23,7 +23,10 @@ export type ConnectionOverrides = {
|
|
|
23
23
|
btcRpcUrl? : string;
|
|
24
24
|
btcRpcUser? : string;
|
|
25
25
|
btcRpcPass? : string;
|
|
26
|
+
/** IPFS HTTP gateway for CAS reads (read-only). */
|
|
26
27
|
casGateway? : string;
|
|
28
|
+
/** IPFS HTTP RPC endpoint for a writable CAS (reads + writes). */
|
|
29
|
+
casRpcUrl? : string;
|
|
27
30
|
config? : string;
|
|
28
31
|
profile? : string;
|
|
29
32
|
/** Keystore file path. Overrides the default `$XDG_DATA_HOME/btcr2/keystore.json`. */
|
|
@@ -49,7 +52,7 @@ export type ConnectionOverrides = {
|
|
|
49
52
|
* },
|
|
50
53
|
* "bitcoin": {
|
|
51
54
|
* "btc": { "rest": "https://my-mempool/api" },
|
|
52
|
-
* "cas": { "gateway": "https://ipfs.io" }
|
|
55
|
+
* "cas": { "gateway": "https://ipfs.io", "rpcUrl": "http://127.0.0.1:5001" }
|
|
53
56
|
* }
|
|
54
57
|
* }
|
|
55
58
|
* }
|
|
@@ -72,7 +75,10 @@ export type ConfigFile = {
|
|
|
72
75
|
rpcPass? : string;
|
|
73
76
|
};
|
|
74
77
|
cas?: {
|
|
78
|
+
/** IPFS HTTP gateway for CAS reads (read-only). */
|
|
75
79
|
gateway?: string;
|
|
80
|
+
/** IPFS HTTP RPC endpoint for a writable CAS (reads + writes). */
|
|
81
|
+
rpcUrl?: string;
|
|
76
82
|
};
|
|
77
83
|
/** Signing identity references. Never embeds key material; the secret lives in the keystore. */
|
|
78
84
|
identity?: {
|
|
@@ -153,6 +159,7 @@ export type ApiFactory = (network?: NetworkOption, overrides?: ConnectionOverrid
|
|
|
153
159
|
* | `BTCR2_BTC_RPC_USER` | `--btc-rpc-user` |
|
|
154
160
|
* | `BTCR2_BTC_RPC_PASS` | `--btc-rpc-pass` |
|
|
155
161
|
* | `BTCR2_CAS_GATEWAY` | `--cas-gateway` |
|
|
162
|
+
* | `BTCR2_CAS_RPC_URL` | `--cas-rpc-url` |
|
|
156
163
|
*/
|
|
157
164
|
export const ENV_VARS = {
|
|
158
165
|
BTC_REST : 'BTCR2_BTC_REST',
|
|
@@ -160,6 +167,7 @@ export const ENV_VARS = {
|
|
|
160
167
|
BTC_RPC_USER : 'BTCR2_BTC_RPC_USER',
|
|
161
168
|
BTC_RPC_PASS : 'BTCR2_BTC_RPC_PASS',
|
|
162
169
|
CAS_GATEWAY : 'BTCR2_CAS_GATEWAY',
|
|
170
|
+
CAS_RPC_URL : 'BTCR2_CAS_RPC_URL',
|
|
163
171
|
} as const;
|
|
164
172
|
|
|
165
173
|
/**
|
|
@@ -174,6 +182,7 @@ export function readEnvOverrides(): ConnectionOverrides {
|
|
|
174
182
|
btcRpcUser : env(ENV_VARS.BTC_RPC_USER),
|
|
175
183
|
btcRpcPass : env(ENV_VARS.BTC_RPC_PASS),
|
|
176
184
|
casGateway : env(ENV_VARS.CAS_GATEWAY),
|
|
185
|
+
casRpcUrl : env(ENV_VARS.CAS_RPC_URL),
|
|
177
186
|
};
|
|
178
187
|
}
|
|
179
188
|
|
|
@@ -221,6 +230,7 @@ export function profileToOverrides(
|
|
|
221
230
|
btcRpcUser : profile.btc?.rpcUser,
|
|
222
231
|
btcRpcPass : profile.btc?.rpcPass,
|
|
223
232
|
casGateway : profile.cas?.gateway,
|
|
233
|
+
casRpcUrl : profile.cas?.rpcUrl,
|
|
224
234
|
};
|
|
225
235
|
}
|
|
226
236
|
|
|
@@ -261,7 +271,7 @@ export function resolveDefaultNetwork(overrides?: ConnectionOverrides): NetworkO
|
|
|
261
271
|
function resolveConnectionConfig(
|
|
262
272
|
network? : NetworkOption,
|
|
263
273
|
overrides?: ConnectionOverrides,
|
|
264
|
-
): { btc?: BitcoinApiConfig; cas?:
|
|
274
|
+
): { btc?: BitcoinApiConfig; cas?: CasConfig } {
|
|
265
275
|
if (!network) return {};
|
|
266
276
|
|
|
267
277
|
// Layer 1: Config file profile (lowest precedence of the three override layers)
|
|
@@ -280,6 +290,7 @@ function resolveConnectionConfig(
|
|
|
280
290
|
btcRpcUser : overrides?.btcRpcUser ?? env.btcRpcUser ?? fileOverrides.btcRpcUser,
|
|
281
291
|
btcRpcPass : overrides?.btcRpcPass ?? env.btcRpcPass ?? fileOverrides.btcRpcPass,
|
|
282
292
|
casGateway : overrides?.casGateway ?? env.casGateway ?? fileOverrides.casGateway,
|
|
293
|
+
casRpcUrl : overrides?.casRpcUrl ?? env.casRpcUrl ?? fileOverrides.casRpcUrl,
|
|
283
294
|
};
|
|
284
295
|
|
|
285
296
|
const btc: BitcoinApiConfig = { network };
|
|
@@ -296,9 +307,15 @@ function resolveConnectionConfig(
|
|
|
296
307
|
};
|
|
297
308
|
}
|
|
298
309
|
|
|
299
|
-
|
|
310
|
+
// A configured RPC endpoint is writable and takes precedence over the
|
|
311
|
+
// read-only gateway (matching the api's CasConfig priority: rpcUrl > gateway).
|
|
312
|
+
// Both may be set; the api selects one executor from them.
|
|
313
|
+
const cas: CasConfig = {};
|
|
314
|
+
if (merged.casGateway) cas.gateway = merged.casGateway;
|
|
315
|
+
if (merged.casRpcUrl) cas.rpcUrl = merged.casRpcUrl;
|
|
316
|
+
const hasCas = merged.casGateway || merged.casRpcUrl;
|
|
300
317
|
|
|
301
|
-
return { btc, ...(
|
|
318
|
+
return { btc, ...(hasCas && { cas }) };
|
|
302
319
|
}
|
|
303
320
|
|
|
304
321
|
/**
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { DidUpdateResult } from '@did-btcr2/api';
|
|
1
2
|
import type { PatchOperation } from '@did-btcr2/common';
|
|
2
|
-
import type { Btcr2DidDocument, ResolutionOptions
|
|
3
|
+
import type { Btcr2DidDocument, ResolutionOptions } from '@did-btcr2/method';
|
|
3
4
|
import type { DidResolutionResult } from '@web5/dids';
|
|
4
5
|
|
|
5
6
|
export type NetworkOption = 'bitcoin' | 'testnet3' | 'testnet4' | 'signet' | 'mutinynet' | 'regtest';
|
|
@@ -25,8 +26,8 @@ export interface UpdateCommandOptions {
|
|
|
25
26
|
export type CommandResult =
|
|
26
27
|
| { action: 'create'; data: string; keyId?: string; publicKey?: string }
|
|
27
28
|
| { action: 'resolve'; data: DidResolutionResult }
|
|
28
|
-
| { action: 'update'; data:
|
|
29
|
-
| { action: 'deactivate'; data:
|
|
29
|
+
| { action: 'update'; data: DidUpdateResult }
|
|
30
|
+
| { action: 'deactivate'; data: DidUpdateResult }
|
|
30
31
|
| { action: 'key-generate'; data: { keyId: string; publicKey: string; active: boolean } }
|
|
31
32
|
| { action: 'key-list'; data: Array<{ keyId: string; fingerprint: string; name?: string; active: boolean }> }
|
|
32
33
|
| { action: 'key-show'; data: { keyId: string; publicKey: string; tags?: Record<string, string> } }
|
|
@@ -55,6 +56,7 @@ export interface GlobalOptions {
|
|
|
55
56
|
btcRpcUser? : string;
|
|
56
57
|
btcRpcPass? : string;
|
|
57
58
|
casGateway? : string;
|
|
59
|
+
casRpcUrl? : string;
|
|
58
60
|
keystore? : string;
|
|
59
61
|
passphraseFile?: string;
|
|
60
62
|
signingKey? : string;
|