@did-btcr2/cli 0.22.0 → 0.23.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 +17 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/cjs/index.js +394 -78
- package/dist/esm/src/cli.js +2 -1
- package/dist/esm/src/cli.js.map +1 -1
- package/dist/esm/src/commands/completion.js +1 -1
- package/dist/esm/src/commands/completion.js.map +1 -1
- package/dist/esm/src/commands/create.js +33 -41
- package/dist/esm/src/commands/create.js.map +1 -1
- package/dist/esm/src/commands/genesis.js +119 -0
- package/dist/esm/src/commands/genesis.js.map +1 -0
- package/dist/esm/src/commands/identifier.js +3 -17
- package/dist/esm/src/commands/identifier.js.map +1 -1
- package/dist/esm/src/commands/index.js +1 -0
- package/dist/esm/src/commands/index.js.map +1 -1
- package/dist/esm/src/commands/resolve.js +15 -1
- package/dist/esm/src/commands/resolve.js.map +1 -1
- package/dist/esm/src/commands/write.js +10 -7
- package/dist/esm/src/commands/write.js.map +1 -1
- package/dist/esm/src/genesis-document-file.js +26 -0
- package/dist/esm/src/genesis-document-file.js.map +1 -0
- package/dist/esm/src/genesis-spec.js +93 -0
- package/dist/esm/src/genesis-spec.js.map +1 -0
- package/dist/esm/src/genesis-wizard.js +132 -0
- package/dist/esm/src/genesis-wizard.js.map +1 -0
- package/dist/esm/src/hints.js +14 -3
- package/dist/esm/src/hints.js.map +1 -1
- package/dist/esm/src/network-option.js +39 -0
- package/dist/esm/src/network-option.js.map +1 -0
- package/dist/esm/src/resolution-options.js +19 -2
- package/dist/esm/src/resolution-options.js.map +1 -1
- package/dist/types/src/cli.d.ts.map +1 -1
- package/dist/types/src/commands/create.d.ts +5 -4
- package/dist/types/src/commands/create.d.ts.map +1 -1
- package/dist/types/src/commands/genesis.d.ts +20 -0
- package/dist/types/src/commands/genesis.d.ts.map +1 -0
- package/dist/types/src/commands/identifier.d.ts.map +1 -1
- package/dist/types/src/commands/index.d.ts +1 -0
- package/dist/types/src/commands/index.d.ts.map +1 -1
- package/dist/types/src/commands/resolve.d.ts +7 -0
- package/dist/types/src/commands/resolve.d.ts.map +1 -1
- package/dist/types/src/commands/write.d.ts +2 -1
- package/dist/types/src/commands/write.d.ts.map +1 -1
- package/dist/types/src/genesis-document-file.d.ts +11 -0
- package/dist/types/src/genesis-document-file.d.ts.map +1 -0
- package/dist/types/src/genesis-spec.d.ts +70 -0
- package/dist/types/src/genesis-spec.d.ts.map +1 -0
- package/dist/types/src/genesis-wizard.d.ts +30 -0
- package/dist/types/src/genesis-wizard.d.ts.map +1 -0
- package/dist/types/src/hints.d.ts +7 -0
- package/dist/types/src/hints.d.ts.map +1 -1
- package/dist/types/src/network-option.d.ts +15 -0
- package/dist/types/src/network-option.d.ts.map +1 -0
- package/dist/types/src/resolution-options.d.ts +6 -2
- package/dist/types/src/resolution-options.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +18 -1
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/cli.ts +2 -0
- package/src/commands/completion.ts +1 -1
- package/src/commands/create.ts +39 -55
- package/src/commands/genesis.ts +149 -0
- package/src/commands/identifier.ts +3 -25
- package/src/commands/index.ts +1 -0
- package/src/commands/resolve.ts +20 -1
- package/src/commands/write.ts +10 -7
- package/src/genesis-document-file.ts +35 -0
- package/src/genesis-spec.ts +149 -0
- package/src/genesis-wizard.ts +163 -0
- package/src/hints.ts +13 -2
- package/src/network-option.ts +50 -0
- package/src/resolution-options.ts +21 -2
- package/src/types.ts +17 -2
package/dist/cjs/index.js
CHANGED
|
@@ -51,6 +51,7 @@ __export(index_exports, {
|
|
|
51
51
|
registerConfigCommand: () => registerConfigCommand,
|
|
52
52
|
registerCreateCommand: () => registerCreateCommand,
|
|
53
53
|
registerDeactivateCommand: () => registerDeactivateCommand,
|
|
54
|
+
registerGenesisCommand: () => registerGenesisCommand,
|
|
54
55
|
registerIdentifierCommand: () => registerIdentifierCommand,
|
|
55
56
|
registerInitCommand: () => registerInitCommand,
|
|
56
57
|
registerKeyCommand: () => registerKeyCommand,
|
|
@@ -2097,13 +2098,35 @@ function printNextSteps(init, unlocked, session, doctor) {
|
|
|
2097
2098
|
// src/commands/create.ts
|
|
2098
2099
|
var import_utils4 = require("@noble/hashes/utils.js");
|
|
2099
2100
|
|
|
2101
|
+
// src/genesis-document-file.ts
|
|
2102
|
+
var import_promises = require("fs/promises");
|
|
2103
|
+
var GENESIS_DOCUMENT_HELP = "Path to the JSON genesis document of an external identifier (x). Fills sidecar.genesisDocument of the resolution options";
|
|
2104
|
+
async function readGenesisDocumentFile(path) {
|
|
2105
|
+
let parsed;
|
|
2106
|
+
try {
|
|
2107
|
+
parsed = JSON.parse(await (0, import_promises.readFile)(path, "utf-8"));
|
|
2108
|
+
} catch {
|
|
2109
|
+
throw new CLIError(
|
|
2110
|
+
"Invalid genesis document path. Must be a valid path to a JSON file.",
|
|
2111
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2112
|
+
{ genesisDocument: path }
|
|
2113
|
+
);
|
|
2114
|
+
}
|
|
2115
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2116
|
+
throw new CLIError(
|
|
2117
|
+
"Invalid genesis document. The file must contain a JSON object.",
|
|
2118
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2119
|
+
{ genesisDocument: path }
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
return parsed;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2100
2125
|
// src/hints.ts
|
|
2101
2126
|
var import_api3 = require("@did-btcr2/api");
|
|
2102
2127
|
var import_method2 = require("@did-btcr2/method");
|
|
2103
2128
|
function printCreateFundingHint(g, network, did) {
|
|
2104
2129
|
if (g.quiet || g.output === "json") return;
|
|
2105
|
-
const faucet = (0, import_api3.faucetUrl)(network);
|
|
2106
|
-
if (!faucet) return;
|
|
2107
2130
|
let beaconAddress;
|
|
2108
2131
|
try {
|
|
2109
2132
|
const { serviceEndpoint } = import_method2.BeaconUtils.createBeaconService(did, "p2wpkh", "SingletonBeacon");
|
|
@@ -2111,6 +2134,12 @@ function printCreateFundingHint(g, network, did) {
|
|
|
2111
2134
|
} catch {
|
|
2112
2135
|
return;
|
|
2113
2136
|
}
|
|
2137
|
+
printBeaconFundingHint(g, network, beaconAddress);
|
|
2138
|
+
}
|
|
2139
|
+
function printBeaconFundingHint(g, network, beaconAddress) {
|
|
2140
|
+
if (g.quiet || g.output === "json") return;
|
|
2141
|
+
const faucet = (0, import_api3.faucetUrl)(network);
|
|
2142
|
+
if (!faucet) return;
|
|
2114
2143
|
const explorer = (0, import_api3.explorerAddressUrl)(network, beaconAddress);
|
|
2115
2144
|
const lines = [
|
|
2116
2145
|
"Fund the initial beacon to anchor updates:",
|
|
@@ -2166,33 +2195,59 @@ function resolveKeyRef(kms, ref) {
|
|
|
2166
2195
|
throw new CLIError(`No key matches reference "${ref}".`, "KEY_NOT_FOUND_ERROR", { ref });
|
|
2167
2196
|
}
|
|
2168
2197
|
|
|
2198
|
+
// src/network-option.ts
|
|
2199
|
+
var NETWORK_OPTION_HELP = "Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest> (default: config defaults.network, else regtest)";
|
|
2200
|
+
function overridesFromGlobals(g) {
|
|
2201
|
+
return {
|
|
2202
|
+
home: g.home,
|
|
2203
|
+
config: g.config,
|
|
2204
|
+
profile: g.profile,
|
|
2205
|
+
keystore: g.keystore,
|
|
2206
|
+
passphraseFile: g.passphraseFile
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
function resolveNetworkOption(explicit, overrides) {
|
|
2210
|
+
if (!explicit) return resolveDefaultNetwork(overrides);
|
|
2211
|
+
if (!SUPPORTED_NETWORKS.includes(explicit)) {
|
|
2212
|
+
throw new CLIError(
|
|
2213
|
+
'Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".',
|
|
2214
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2215
|
+
{ network: explicit }
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
return explicit;
|
|
2219
|
+
}
|
|
2220
|
+
function warnProfileNetworkMismatch(g, network, overrides) {
|
|
2221
|
+
const mismatch = profileNetworkMismatch(network, overrides);
|
|
2222
|
+
if (mismatch && !g.quiet) {
|
|
2223
|
+
process.stderr.write(
|
|
2224
|
+
`Warning: creating a "${network}" identifier while the active profile "${mismatch.profile}" declares network "${mismatch.declared}". The identifier's network and the profile's endpoints may not match.
|
|
2225
|
+
`
|
|
2226
|
+
);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
|
|
2169
2230
|
// src/commands/create.ts
|
|
2170
2231
|
var EXPECTED_BYTES = {
|
|
2171
2232
|
k: { length: 33, label: "secp256k1 compressed public key (33 bytes)" },
|
|
2172
2233
|
x: { length: 32, label: "SHA-256 hash (32 bytes)" }
|
|
2173
2234
|
};
|
|
2174
2235
|
function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
2175
|
-
program.command("create").description("Create an identifier and initial DID document").option("-t, --type <type>", "Identifier type <k|x>", "k").option(
|
|
2176
|
-
"-n, --network <network>",
|
|
2177
|
-
"Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest> (default: config defaults.network, else regtest)"
|
|
2178
|
-
).option(
|
|
2236
|
+
program.command("create").description("Create an identifier and initial DID document").option("-t, --type <type>", "Identifier type <k|x>", "k").option("-n, --network <network>", NETWORK_OPTION_HELP).option(
|
|
2179
2237
|
"-b, --bytes <bytes>",
|
|
2180
2238
|
"Genesis bytes as a hex string. For type=k, a 33-byte secp256k1 public key (omit to generate a key). For type=x, the 32-byte SHA-256 hash of a genesis document."
|
|
2239
|
+
).option(
|
|
2240
|
+
"--document <path>",
|
|
2241
|
+
'For type=x, the path of the JSON genesis document to hash (see "btcr2 genesis build"). Exclusive with --bytes.'
|
|
2181
2242
|
).action(async (options) => {
|
|
2182
2243
|
const g = globals();
|
|
2183
2244
|
if (options.type !== "k" && options.type !== "x") {
|
|
2184
2245
|
throw new CLIError('Invalid type. Must be "k" or "x".', "INVALID_ARGUMENT_ERROR", options);
|
|
2185
2246
|
}
|
|
2186
2247
|
const overrides = overridesFromGlobals(g);
|
|
2187
|
-
const network =
|
|
2248
|
+
const network = resolveNetworkOption(options.network, overrides);
|
|
2188
2249
|
const signingKey = g.signingKey;
|
|
2189
|
-
|
|
2190
|
-
if (mismatch && !g.quiet) {
|
|
2191
|
-
process.stderr.write(
|
|
2192
|
-
`Warning: creating a "${network}" identifier while the active profile "${mismatch.profile}" declares network "${mismatch.declared}". The identifier's network and the profile's endpoints may not match.
|
|
2193
|
-
`
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2250
|
+
warnProfileNetworkMismatch(g, network, overrides);
|
|
2196
2251
|
const print = (result, note) => {
|
|
2197
2252
|
console.log(formatResult(result, g));
|
|
2198
2253
|
if (note && g.output !== "json") process.stderr.write(`${note}
|
|
@@ -2205,9 +2260,21 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
|
2205
2260
|
"INVALID_ARGUMENT_ERROR"
|
|
2206
2261
|
);
|
|
2207
2262
|
}
|
|
2263
|
+
if (options.bytes !== void 0 && options.document !== void 0) {
|
|
2264
|
+
throw new CLIError("Provide at most one of --bytes or --document.", "INVALID_ARGUMENT_ERROR");
|
|
2265
|
+
}
|
|
2266
|
+
if (options.document !== void 0) {
|
|
2267
|
+
const genesisDocument = await readGenesisDocumentFile(options.document);
|
|
2268
|
+
const api2 = factory();
|
|
2269
|
+
const { did: did3, genesisBytes: genesisBytes2, didDocument } = api2.btcr2.createExternalFromDocument(genesisDocument, { network });
|
|
2270
|
+
print({ action: "create", data: did3, genesisBytes: (0, import_utils4.bytesToHex)(genesisBytes2) });
|
|
2271
|
+
const beacons = api2.btcr2.getBeacons(didDocument);
|
|
2272
|
+
if (beacons.length > 0) printBeaconFundingHint(g, network, beacons[0].address);
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2208
2275
|
if (options.bytes === void 0) {
|
|
2209
2276
|
throw new CLIError(
|
|
2210
|
-
"External identifiers (-t x) require --bytes <hex>,
|
|
2277
|
+
"External identifiers (-t x) require --document <path>, the genesis document, or --bytes <hex>, its 32-byte hash. Key generation is only available for -t k.",
|
|
2211
2278
|
"INVALID_ARGUMENT_ERROR"
|
|
2212
2279
|
);
|
|
2213
2280
|
}
|
|
@@ -2216,6 +2283,9 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
|
2216
2283
|
print({ action: "create", data: did2 });
|
|
2217
2284
|
return;
|
|
2218
2285
|
}
|
|
2286
|
+
if (options.document !== void 0) {
|
|
2287
|
+
throw new CLIError("--document applies only to external identifiers (-t x).", "INVALID_ARGUMENT_ERROR");
|
|
2288
|
+
}
|
|
2219
2289
|
if (options.bytes !== void 0 && signingKey) {
|
|
2220
2290
|
throw new CLIError(
|
|
2221
2291
|
"Provide at most one of --bytes or --signing-key.",
|
|
@@ -2252,26 +2322,6 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
|
|
|
2252
2322
|
printCreateFundingHint(g, network, did);
|
|
2253
2323
|
});
|
|
2254
2324
|
}
|
|
2255
|
-
function overridesFromGlobals(g) {
|
|
2256
|
-
return {
|
|
2257
|
-
home: g.home,
|
|
2258
|
-
config: g.config,
|
|
2259
|
-
profile: g.profile,
|
|
2260
|
-
keystore: g.keystore,
|
|
2261
|
-
passphraseFile: g.passphraseFile
|
|
2262
|
-
};
|
|
2263
|
-
}
|
|
2264
|
-
function resolveNetwork(explicit, overrides) {
|
|
2265
|
-
if (!explicit) return resolveDefaultNetwork(overrides);
|
|
2266
|
-
if (!SUPPORTED_NETWORKS.includes(explicit)) {
|
|
2267
|
-
throw new CLIError(
|
|
2268
|
-
'Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".',
|
|
2269
|
-
"INVALID_ARGUMENT_ERROR",
|
|
2270
|
-
{ network: explicit }
|
|
2271
|
-
);
|
|
2272
|
-
}
|
|
2273
|
-
return explicit;
|
|
2274
|
-
}
|
|
2275
2325
|
function parseGenesisBytes(hex, type) {
|
|
2276
2326
|
const expected = EXPECTED_BYTES[type];
|
|
2277
2327
|
let bytes;
|
|
@@ -2299,7 +2349,10 @@ var import_api5 = require("@did-btcr2/api");
|
|
|
2299
2349
|
|
|
2300
2350
|
// src/resolution-options.ts
|
|
2301
2351
|
var import_api4 = require("@did-btcr2/api");
|
|
2302
|
-
var
|
|
2352
|
+
var import_promises2 = require("fs/promises");
|
|
2353
|
+
function hasResolutionFlags(flags) {
|
|
2354
|
+
return flags.resolutionOptions !== void 0 || flags.resolutionOptionsPath !== void 0 || flags.minConf !== void 0 || flags.genesisDocument !== void 0;
|
|
2355
|
+
}
|
|
2303
2356
|
var MIN_CONF_HELP = `Minimum block confirmations a beacon signal needs before resolution applies it (positive integer, default: ${import_api4.DEFAULT_MIN_CONF}). Overrides a minConf inside the JSON resolution options`;
|
|
2304
2357
|
async function readResolutionOptions(flags) {
|
|
2305
2358
|
let resolutionOptions;
|
|
@@ -2315,7 +2368,7 @@ async function readResolutionOptions(flags) {
|
|
|
2315
2368
|
}
|
|
2316
2369
|
} else if (flags.resolutionOptionsPath) {
|
|
2317
2370
|
try {
|
|
2318
|
-
const content = await (0,
|
|
2371
|
+
const content = await (0, import_promises2.readFile)(flags.resolutionOptionsPath, "utf-8");
|
|
2319
2372
|
resolutionOptions = JSON.parse(content);
|
|
2320
2373
|
} catch {
|
|
2321
2374
|
throw new CLIError(
|
|
@@ -2328,6 +2381,13 @@ async function readResolutionOptions(flags) {
|
|
|
2328
2381
|
if (flags.minConf !== void 0) {
|
|
2329
2382
|
resolutionOptions = { ...resolutionOptions ?? {}, minConf: flags.minConf };
|
|
2330
2383
|
}
|
|
2384
|
+
if (flags.genesisDocument !== void 0) {
|
|
2385
|
+
const genesisDocument = await readGenesisDocumentFile(flags.genesisDocument);
|
|
2386
|
+
resolutionOptions = {
|
|
2387
|
+
...resolutionOptions ?? {},
|
|
2388
|
+
sidecar: { ...resolutionOptions?.sidecar ?? {}, genesisDocument }
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2331
2391
|
return resolutionOptions;
|
|
2332
2392
|
}
|
|
2333
2393
|
function parseMinConf(value) {
|
|
@@ -2343,7 +2403,7 @@ function parseMinConf(value) {
|
|
|
2343
2403
|
|
|
2344
2404
|
// src/commands/resolve.ts
|
|
2345
2405
|
function registerResolveCommand(program, factory, globals) {
|
|
2346
|
-
program.command("resolve").alias("read").description("Resolve the DID document of the identifier.").requiredOption("-i, --identifier <identifier>", "did:btcr2 identifier").option("-r, --resolution-options <json>", "JSON string containing resolution options").option("-p, --resolution-options-path <path>", "Path to a JSON file containing resolution options").option("--min-conf <n>", MIN_CONF_HELP, parseMinConf).action(async (options) => {
|
|
2406
|
+
program.command("resolve").alias("read").description("Resolve the DID document of the identifier.").requiredOption("-i, --identifier <identifier>", "did:btcr2 identifier").option("-r, --resolution-options <json>", "JSON string containing resolution options").option("-p, --resolution-options-path <path>", "Path to a JSON file containing resolution options").option("--min-conf <n>", MIN_CONF_HELP, parseMinConf).option("--genesis-document <path>", GENESIS_DOCUMENT_HELP).action(async (options) => {
|
|
2347
2407
|
const parsed = await validateResolveOptions(options);
|
|
2348
2408
|
const network = deriveNetwork(parsed.identifier);
|
|
2349
2409
|
const api = factory(network, globals());
|
|
@@ -2353,13 +2413,24 @@ function registerResolveCommand(program, factory, globals) {
|
|
|
2353
2413
|
});
|
|
2354
2414
|
}
|
|
2355
2415
|
async function validateResolveOptions(options) {
|
|
2356
|
-
import_api5.Identifier.decode(options.identifier);
|
|
2416
|
+
const components = import_api5.Identifier.decode(options.identifier);
|
|
2417
|
+
assertGenesisDocumentApplies(options, components.hrp);
|
|
2357
2418
|
const resolutionOptions = await readResolutionOptions(options);
|
|
2358
2419
|
return { identifier: options.identifier, options: resolutionOptions };
|
|
2359
2420
|
}
|
|
2421
|
+
function assertGenesisDocumentApplies(flags, hrp) {
|
|
2422
|
+
if (flags.genesisDocument !== void 0 && hrp === "k") {
|
|
2423
|
+
throw new CLIError(
|
|
2424
|
+
"--genesis-document applies only to external identifiers (x).",
|
|
2425
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2426
|
+
{ genesisDocument: flags.genesisDocument }
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2360
2430
|
|
|
2361
2431
|
// src/commands/write.ts
|
|
2362
2432
|
var import_key_manager2 = require("@did-btcr2/key-manager");
|
|
2433
|
+
var import_api6 = require("@did-btcr2/api");
|
|
2363
2434
|
function registerWriteOptions(command) {
|
|
2364
2435
|
return command.option(
|
|
2365
2436
|
"-s, --source-document <json>",
|
|
@@ -2381,7 +2452,7 @@ function registerWriteOptions(command) {
|
|
|
2381
2452
|
).option(
|
|
2382
2453
|
"--resolution-options-path <path>",
|
|
2383
2454
|
"Path to a JSON file with resolution options, for the resolution of the source document"
|
|
2384
|
-
).option("--min-conf <n>", MIN_CONF_HELP, parseMinConf).option(
|
|
2455
|
+
).option("--min-conf <n>", MIN_CONF_HELP, parseMinConf).option("--genesis-document <path>", `${GENESIS_DOCUMENT_HELP}, for the resolution of the source document`).option(
|
|
2385
2456
|
"--publish-to-cas <mode>",
|
|
2386
2457
|
"Publish update artifacts to a writable CAS before broadcast: auto|always|never. CAS publication is optional; the default distributes the returned artifacts via sidecar.",
|
|
2387
2458
|
parsePublishToCasMode,
|
|
@@ -2406,14 +2477,14 @@ async function prepareWrite(options, factory, g) {
|
|
|
2406
2477
|
{ did }
|
|
2407
2478
|
);
|
|
2408
2479
|
}
|
|
2409
|
-
|
|
2410
|
-
if (hasDocument && hasResolutionFlags) {
|
|
2480
|
+
if (hasDocument && hasResolutionFlags(options)) {
|
|
2411
2481
|
throw new CLIError(
|
|
2412
|
-
"--resolution-options, --resolution-options-path,
|
|
2482
|
+
"--resolution-options, --resolution-options-path, --min-conf, and --genesis-document apply only when --source-document and --source-version-id are omitted. A supplied source pair skips resolution.",
|
|
2413
2483
|
"INVALID_ARGUMENT_ERROR",
|
|
2414
2484
|
{ did }
|
|
2415
2485
|
);
|
|
2416
2486
|
}
|
|
2487
|
+
assertGenesisDocumentApplies(options, import_api6.Identifier.decode(did).hrp);
|
|
2417
2488
|
assertKeystoreAllowedForNetwork(network, g);
|
|
2418
2489
|
const resolutionOptions = await readResolutionOptions(options);
|
|
2419
2490
|
const api = factory(network, g);
|
|
@@ -2502,9 +2573,8 @@ function registerDeactivateCommand(program, factory, globals) {
|
|
|
2502
2573
|
}
|
|
2503
2574
|
|
|
2504
2575
|
// src/commands/identifier.ts
|
|
2505
|
-
var
|
|
2576
|
+
var import_api7 = require("@did-btcr2/api");
|
|
2506
2577
|
var import_utils5 = require("@noble/hashes/utils.js");
|
|
2507
|
-
var import_promises2 = require("fs/promises");
|
|
2508
2578
|
function registerIdentifierCommand(program, factory, globals) {
|
|
2509
2579
|
const identifier = program.command("identifier").description("Decode and validate did:btcr2 identifiers (offline).");
|
|
2510
2580
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
@@ -2545,7 +2615,7 @@ function registerIdentifierCommand(program, factory, globals) {
|
|
|
2545
2615
|
{ did }
|
|
2546
2616
|
);
|
|
2547
2617
|
}
|
|
2548
|
-
const genesisDocument = options.genesisDocument === void 0 ? void 0 : await
|
|
2618
|
+
const genesisDocument = options.genesisDocument === void 0 ? void 0 : await readGenesisDocumentFile(options.genesisDocument);
|
|
2549
2619
|
data.initialDocument = api.btcr2.getInitialDocument(did, genesisDocument);
|
|
2550
2620
|
}
|
|
2551
2621
|
print({ action: "identifier-decode", data });
|
|
@@ -2560,14 +2630,14 @@ function registerIdentifierCommand(program, factory, globals) {
|
|
|
2560
2630
|
const genesisBytes = options.bytes === void 0 ? void 0 : parseHexBytes(options.bytes);
|
|
2561
2631
|
let genesisDocument;
|
|
2562
2632
|
if (options.genesisDocument !== void 0) {
|
|
2563
|
-
if (
|
|
2633
|
+
if (import_api7.Identifier.isValid(did) && import_api7.Identifier.decode(did).hrp === "k") {
|
|
2564
2634
|
throw new CLIError(
|
|
2565
2635
|
"--genesis-document applies only to external identifiers (x).",
|
|
2566
2636
|
"INVALID_ARGUMENT_ERROR",
|
|
2567
2637
|
{ did }
|
|
2568
2638
|
);
|
|
2569
2639
|
}
|
|
2570
|
-
genesisDocument = await
|
|
2640
|
+
genesisDocument = await readGenesisDocumentFile(options.genesisDocument);
|
|
2571
2641
|
}
|
|
2572
2642
|
const report = factory().did.validate(did, { genesisBytes, genesisDocument });
|
|
2573
2643
|
print({ action: "identifier-validate", data: report });
|
|
@@ -2575,7 +2645,7 @@ function registerIdentifierCommand(program, factory, globals) {
|
|
|
2575
2645
|
});
|
|
2576
2646
|
}
|
|
2577
2647
|
function assertValidIdentifier(did) {
|
|
2578
|
-
const report =
|
|
2648
|
+
const report = import_api7.Identifier.validate(did);
|
|
2579
2649
|
if (report.valid) return;
|
|
2580
2650
|
const failed = report.checks[report.checks.length - 1];
|
|
2581
2651
|
throw new CLIError(
|
|
@@ -2591,31 +2661,275 @@ function parseHexBytes(value) {
|
|
|
2591
2661
|
throw new CLIError("Invalid bytes: not valid hex.", "INVALID_ARGUMENT_ERROR", { bytes: value });
|
|
2592
2662
|
}
|
|
2593
2663
|
}
|
|
2594
|
-
|
|
2664
|
+
|
|
2665
|
+
// src/commands/genesis.ts
|
|
2666
|
+
var import_utils7 = require("@noble/hashes/utils.js");
|
|
2667
|
+
var import_node_fs9 = require("fs");
|
|
2668
|
+
var import_promises3 = require("fs/promises");
|
|
2669
|
+
var import_node_path6 = require("path");
|
|
2670
|
+
var import_promises4 = require("readline/promises");
|
|
2671
|
+
|
|
2672
|
+
// src/genesis-spec.ts
|
|
2673
|
+
var import_utils6 = require("@noble/hashes/utils.js");
|
|
2674
|
+
function parseGenesisSpec(value, source) {
|
|
2675
|
+
const fail = (message) => {
|
|
2676
|
+
throw new CLIError(`Invalid genesis spec: ${message}`, "INVALID_ARGUMENT_ERROR", { spec: source });
|
|
2677
|
+
};
|
|
2678
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2679
|
+
return fail("the file must contain a JSON object.");
|
|
2680
|
+
}
|
|
2681
|
+
const spec = value;
|
|
2682
|
+
if (!Array.isArray(spec.verificationMethods) || spec.verificationMethods.length === 0) {
|
|
2683
|
+
return fail('"verificationMethods" must be a non-empty array.');
|
|
2684
|
+
}
|
|
2685
|
+
spec.verificationMethods.forEach((vm, index) => {
|
|
2686
|
+
if (vm === null || typeof vm !== "object") return fail(`verificationMethods[${index}] must be an object.`);
|
|
2687
|
+
const hasKey = typeof vm.key === "string" && vm.key.length > 0;
|
|
2688
|
+
const hasPublicKey = typeof vm.publicKey === "string" && vm.publicKey.length > 0;
|
|
2689
|
+
if (hasKey === hasPublicKey) {
|
|
2690
|
+
return fail(`verificationMethods[${index}] needs exactly one of "key" (a keystore reference) or "publicKey" (hex).`);
|
|
2691
|
+
}
|
|
2692
|
+
});
|
|
2693
|
+
if (spec.beacons !== void 0) {
|
|
2694
|
+
if (!Array.isArray(spec.beacons)) return fail('"beacons" must be an array.');
|
|
2695
|
+
spec.beacons.forEach((beacon, index) => {
|
|
2696
|
+
if (beacon === null || typeof beacon !== "object") return fail(`beacons[${index}] must be an object.`);
|
|
2697
|
+
const sources = ["key", "publicKey", "address"].filter((name) => beacon[name] !== void 0);
|
|
2698
|
+
if (sources.length > 1) {
|
|
2699
|
+
return fail(`beacons[${index}] names ${sources.join(" and ")}. Give only one of "key", "publicKey", or "address".`);
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
if (spec.services !== void 0 && !Array.isArray(spec.services)) {
|
|
2704
|
+
return fail('"services" must be an array.');
|
|
2705
|
+
}
|
|
2706
|
+
return spec;
|
|
2707
|
+
}
|
|
2708
|
+
function toApiSpec(spec, network, resolvePublicKey) {
|
|
2709
|
+
const keyBytes = (entry, label) => entry.key !== void 0 ? resolvePublicKey(entry.key) : parseHexPublicKey(entry.publicKey, label);
|
|
2710
|
+
const verificationMethods = spec.verificationMethods.map((vm, index) => ({
|
|
2711
|
+
publicKey: keyBytes(vm, `verificationMethods[${index}].publicKey`),
|
|
2712
|
+
relationships: vm.relationships,
|
|
2713
|
+
fragment: vm.fragment
|
|
2714
|
+
}));
|
|
2715
|
+
const beacons = spec.beacons?.map((beacon, index) => ({
|
|
2716
|
+
type: beacon.type,
|
|
2717
|
+
publicKey: beacon.key !== void 0 || beacon.publicKey !== void 0 ? keyBytes(beacon, `beacons[${index}].publicKey`) : void 0,
|
|
2718
|
+
addressType: beacon.addressType,
|
|
2719
|
+
address: beacon.address,
|
|
2720
|
+
fragment: beacon.fragment
|
|
2721
|
+
}));
|
|
2722
|
+
return {
|
|
2723
|
+
network,
|
|
2724
|
+
verificationMethods,
|
|
2725
|
+
beacons,
|
|
2726
|
+
services: spec.services
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
function parseHexPublicKey(hex, label) {
|
|
2730
|
+
try {
|
|
2731
|
+
return (0, import_utils6.hexToBytes)(hex.trim());
|
|
2732
|
+
} catch {
|
|
2733
|
+
throw new CLIError(`Invalid ${label}: not valid hex.`, "INVALID_ARGUMENT_ERROR", { publicKey: hex });
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
// src/genesis-wizard.ts
|
|
2738
|
+
var import_api8 = require("@did-btcr2/api");
|
|
2739
|
+
var PUBLIC_KEY_HEX = /^0[23][0-9a-fA-F]{64}$/;
|
|
2740
|
+
async function collectGenesisSpec(ask, ctx) {
|
|
2741
|
+
const verificationMethods = await collectVerificationMethods(ask, ctx);
|
|
2742
|
+
const beacons = await collectBeacons(ask, ctx, verificationMethods[0]);
|
|
2743
|
+
const services = await collectServices(ask, ctx);
|
|
2744
|
+
return { verificationMethods, beacons, ...services.length > 0 && { services } };
|
|
2745
|
+
}
|
|
2746
|
+
async function collectVerificationMethods(ask, ctx) {
|
|
2747
|
+
if (ctx.keys.length === 0) {
|
|
2748
|
+
ctx.say("The keystore has no keys. Enter each key as a 33-byte compressed public key in hex.");
|
|
2749
|
+
} else {
|
|
2750
|
+
ctx.say("Keys in the keystore:");
|
|
2751
|
+
for (const key of ctx.keys) {
|
|
2752
|
+
ctx.say(` ${key.fingerprint}${key.name ? ` ${key.name}` : ""}${key.active ? " (active)" : ""}`);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
const active = ctx.keys.find((key) => key.active);
|
|
2756
|
+
const methods = [];
|
|
2757
|
+
for (let n = 1; ; n++) {
|
|
2758
|
+
const defaultRef = n === 1 && active ? active.name ?? active.fingerprint : void 0;
|
|
2759
|
+
const source = await askKeySource(ask, ctx, `Verification method ${n}: key reference or public key hex`, defaultRef);
|
|
2760
|
+
const relationships = await askRelationships(ask, ctx, n);
|
|
2761
|
+
methods.push({ ...source, ...relationships && { relationships } });
|
|
2762
|
+
if (!await askYesNo(ask, "Add another verification method?")) break;
|
|
2763
|
+
}
|
|
2764
|
+
return methods;
|
|
2765
|
+
}
|
|
2766
|
+
async function collectBeacons(ask, ctx, firstMethod) {
|
|
2767
|
+
const beacons = [];
|
|
2768
|
+
for (let n = 1; ; n++) {
|
|
2769
|
+
const type = await askChoice(ask, ctx, `Beacon ${n} type`, import_api8.BEACON_TYPES, "SingletonBeacon");
|
|
2770
|
+
const address = (await ask(`Beacon ${n} address (blank: derive the address from the key of method 1): `)).trim();
|
|
2771
|
+
if (address.length === 0) {
|
|
2772
|
+
const addressType = await askChoice(ask, ctx, `Beacon ${n} address type`, import_api8.BEACON_ADDRESS_TYPES, import_api8.DEFAULT_BEACON_ADDRESS_TYPE);
|
|
2773
|
+
const keySource = firstMethod.key !== void 0 ? { key: firstMethod.key } : { publicKey: firstMethod.publicKey };
|
|
2774
|
+
beacons.push({ type, ...keySource, addressType });
|
|
2775
|
+
} else {
|
|
2776
|
+
beacons.push({ type, address });
|
|
2777
|
+
}
|
|
2778
|
+
if (!await askYesNo(ask, "Add another beacon?")) break;
|
|
2779
|
+
}
|
|
2780
|
+
return beacons;
|
|
2781
|
+
}
|
|
2782
|
+
async function collectServices(ask, ctx) {
|
|
2783
|
+
const services = [];
|
|
2784
|
+
while (await askYesNo(ask, "Add a service?")) {
|
|
2785
|
+
const n = services.length + 1;
|
|
2786
|
+
const fragment = (await ask(`Service ${n} id fragment (blank: service-<position>): `)).trim();
|
|
2787
|
+
const type = await askRequired(ask, ctx, `Service ${n} type`);
|
|
2788
|
+
const serviceEndpoint = await askRequired(ask, ctx, `Service ${n} endpoint`);
|
|
2789
|
+
services.push({ ...fragment.length > 0 && { id: `#${fragment.replace(/^#/, "")}` }, type, serviceEndpoint });
|
|
2790
|
+
}
|
|
2791
|
+
return services;
|
|
2792
|
+
}
|
|
2793
|
+
async function askKeySource(ask, ctx, question, defaultRef) {
|
|
2794
|
+
for (; ; ) {
|
|
2795
|
+
const raw = (await ask(`${question}${defaultRef ? ` [${defaultRef}]` : ""}: `)).trim();
|
|
2796
|
+
const answer = raw.length > 0 ? raw : defaultRef;
|
|
2797
|
+
if (answer === void 0) {
|
|
2798
|
+
ctx.say("A key is required.");
|
|
2799
|
+
continue;
|
|
2800
|
+
}
|
|
2801
|
+
if (PUBLIC_KEY_HEX.test(answer)) return { publicKey: answer.toLowerCase() };
|
|
2802
|
+
try {
|
|
2803
|
+
ctx.resolveKey(answer);
|
|
2804
|
+
return { key: answer };
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
ctx.say(error.message);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
async function askRelationships(ask, ctx, n) {
|
|
2811
|
+
const names = import_api8.VERIFICATION_RELATIONSHIPS.join(", ");
|
|
2812
|
+
for (; ; ) {
|
|
2813
|
+
const raw = (await ask(`Relationships of method ${n} (comma-separated: ${names}) [all]: `)).trim();
|
|
2814
|
+
if (raw.length === 0) return void 0;
|
|
2815
|
+
const chosen = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2816
|
+
const unknown = chosen.filter((name) => !import_api8.VERIFICATION_RELATIONSHIPS.includes(name));
|
|
2817
|
+
if (unknown.length === 0) return chosen;
|
|
2818
|
+
ctx.say(`Unknown relationship: ${unknown.join(", ")}. Expected one of ${names}.`);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
async function askChoice(ask, ctx, question, choices, defaultValue) {
|
|
2822
|
+
for (; ; ) {
|
|
2823
|
+
const raw = (await ask(`${question} (${choices.join(", ")}) [${defaultValue}]: `)).trim();
|
|
2824
|
+
if (raw.length === 0) return defaultValue;
|
|
2825
|
+
if (choices.includes(raw)) return raw;
|
|
2826
|
+
ctx.say(`Unknown value "${raw}". Expected one of ${choices.join(", ")}.`);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
async function askRequired(ask, ctx, question) {
|
|
2830
|
+
for (; ; ) {
|
|
2831
|
+
const raw = (await ask(`${question}: `)).trim();
|
|
2832
|
+
if (raw.length > 0) return raw;
|
|
2833
|
+
ctx.say("A value is required.");
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
async function askYesNo(ask, question) {
|
|
2837
|
+
const raw = (await ask(`${question} [y/N]: `)).trim();
|
|
2838
|
+
return /^y(es)?$/i.test(raw);
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
// src/commands/genesis.ts
|
|
2842
|
+
var DEFAULT_GENESIS_PATH = "genesis.json";
|
|
2843
|
+
function registerGenesisCommand(program, factory, keystoreFactory, globals) {
|
|
2844
|
+
const genesis = program.command("genesis").description("Build the genesis document of an external identifier (offline).");
|
|
2845
|
+
const print = (result) => console.log(formatResult(result, globals()));
|
|
2846
|
+
genesis.command("build").description("Build a genesis document, write it to a file, and print the external identifier.").option("-n, --network <network>", NETWORK_OPTION_HELP).option("--spec <path>", "Path to a JSON spec file with the keys, beacons, and services. Runs without prompts.").option("--out <path>", "Path of the genesis document to write.", DEFAULT_GENESIS_PATH).option("--force", "Overwrite an existing --out file.", false).action(async (options) => {
|
|
2847
|
+
const g = globals();
|
|
2848
|
+
const overrides = overridesFromGlobals(g);
|
|
2849
|
+
const network = resolveNetworkOption(options.network, overrides);
|
|
2850
|
+
warnProfileNetworkMismatch(g, network, overrides);
|
|
2851
|
+
const outPath = (0, import_node_path6.resolve)(options.out);
|
|
2852
|
+
if (!options.force && (0, import_node_fs9.existsSync)(outPath)) {
|
|
2853
|
+
throw new CLIError(
|
|
2854
|
+
`The file ${outPath} exists. Pass --force to overwrite it, or --out <path> for another file.`,
|
|
2855
|
+
"INVALID_ARGUMENT_ERROR",
|
|
2856
|
+
{ out: outPath }
|
|
2857
|
+
);
|
|
2858
|
+
}
|
|
2859
|
+
let keystoreApi;
|
|
2860
|
+
const kms = () => (keystoreApi ??= keystoreFactory(void 0, overrides)).kms.kms;
|
|
2861
|
+
const resolvePublicKey = (ref) => kms().getPublicKey(resolveKeyRef(kms(), ref));
|
|
2862
|
+
const spec = options.spec !== void 0 ? await readSpecFile(options.spec) : await runWizard(kms);
|
|
2863
|
+
const api = factory();
|
|
2864
|
+
const document2 = api.btcr2.buildGenesisDocument(toApiSpec(spec, network, resolvePublicKey));
|
|
2865
|
+
const json = `${JSON.stringify(document2, null, 2)}
|
|
2866
|
+
`;
|
|
2867
|
+
const { did, genesisBytes, didDocument } = api.btcr2.createExternalFromDocument(JSON.parse(json), { network });
|
|
2868
|
+
await (0, import_promises3.writeFile)(outPath, json, { encoding: "utf-8", flag: options.force ? "w" : "wx" });
|
|
2869
|
+
const beacons = api.btcr2.getBeacons(didDocument);
|
|
2870
|
+
print({
|
|
2871
|
+
action: "genesis-build",
|
|
2872
|
+
data: { did, network, genesisBytes: (0, import_utils7.bytesToHex)(genesisBytes), path: outPath, beacons }
|
|
2873
|
+
});
|
|
2874
|
+
if (!g.quiet && g.output !== "json") {
|
|
2875
|
+
process.stderr.write(
|
|
2876
|
+
`Wrote the genesis document to ${outPath}. Keep it: the identifier resolves only with it. Pass --genesis-document <path> to resolve, update, and deactivate, or publish it to a CAS.
|
|
2877
|
+
`
|
|
2878
|
+
);
|
|
2879
|
+
if (beacons.length > 0) printBeaconFundingHint(g, network, beacons[0].address);
|
|
2880
|
+
}
|
|
2881
|
+
});
|
|
2882
|
+
}
|
|
2883
|
+
async function readSpecFile(path) {
|
|
2595
2884
|
let parsed;
|
|
2596
2885
|
try {
|
|
2597
|
-
parsed = JSON.parse(await (0,
|
|
2886
|
+
parsed = JSON.parse(await (0, import_promises3.readFile)(path, "utf-8"));
|
|
2598
2887
|
} catch {
|
|
2599
2888
|
throw new CLIError(
|
|
2600
|
-
"Invalid genesis
|
|
2889
|
+
"Invalid genesis spec path. Must be a valid path to a JSON file.",
|
|
2601
2890
|
"INVALID_ARGUMENT_ERROR",
|
|
2602
|
-
{
|
|
2891
|
+
{ spec: path }
|
|
2603
2892
|
);
|
|
2604
2893
|
}
|
|
2605
|
-
|
|
2894
|
+
return parseGenesisSpec(parsed, path);
|
|
2895
|
+
}
|
|
2896
|
+
async function runWizard(kms) {
|
|
2897
|
+
if (!process.stdin.isTTY) {
|
|
2606
2898
|
throw new CLIError(
|
|
2607
|
-
"
|
|
2608
|
-
"INVALID_ARGUMENT_ERROR"
|
|
2609
|
-
{ genesisDocument: path }
|
|
2899
|
+
"No terminal is attached. Pass --spec <path> to build the genesis document without prompts.",
|
|
2900
|
+
"INVALID_ARGUMENT_ERROR"
|
|
2610
2901
|
);
|
|
2611
2902
|
}
|
|
2612
|
-
|
|
2903
|
+
const store = kms();
|
|
2904
|
+
const rl = (0, import_promises4.createInterface)({ input: process.stdin, output: process.stderr });
|
|
2905
|
+
try {
|
|
2906
|
+
return await collectGenesisSpec((question) => rl.question(question), {
|
|
2907
|
+
say: (line) => process.stderr.write(`${line}
|
|
2908
|
+
`),
|
|
2909
|
+
keys: listKeys(store),
|
|
2910
|
+
resolveKey: (ref) => resolveKeyRef(store, ref)
|
|
2911
|
+
});
|
|
2912
|
+
} finally {
|
|
2913
|
+
rl.close();
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
function listKeys(kms) {
|
|
2917
|
+
const active = kms.activeKeyId;
|
|
2918
|
+
return kms.listKeys().map((id) => {
|
|
2919
|
+
const entry = kms.getEntry(id);
|
|
2920
|
+
return {
|
|
2921
|
+
keyId: id,
|
|
2922
|
+
fingerprint: id.split(":").pop() ?? id,
|
|
2923
|
+
...entry.tags?.name && { name: entry.tags.name },
|
|
2924
|
+
active: id === active
|
|
2925
|
+
};
|
|
2926
|
+
});
|
|
2613
2927
|
}
|
|
2614
2928
|
|
|
2615
2929
|
// src/commands/key.ts
|
|
2616
2930
|
var import_keypair = require("@did-btcr2/keypair");
|
|
2617
|
-
var
|
|
2618
|
-
var
|
|
2931
|
+
var import_utils8 = require("@noble/hashes/utils.js");
|
|
2932
|
+
var import_node_fs10 = require("fs");
|
|
2619
2933
|
function registerKeyCommand(program, factory, globals) {
|
|
2620
2934
|
const key = program.command("key").description("Manage keypairs in the encrypted keystore.");
|
|
2621
2935
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
@@ -2624,7 +2938,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
2624
2938
|
assertNameAvailable(api.kms.kms, options.name);
|
|
2625
2939
|
const setActive = options.setActive ?? false;
|
|
2626
2940
|
const id = api.kms.generateKey({ ...options.name && { tags: { name: options.name } }, setActive });
|
|
2627
|
-
print({ action: "key-generate", data: { keyId: id, publicKey: (0,
|
|
2941
|
+
print({ action: "key-generate", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)), active: setActive } });
|
|
2628
2942
|
});
|
|
2629
2943
|
key.command("list").alias("ls").description("List stored keys.").action(() => {
|
|
2630
2944
|
const kms = factory(void 0, globals()).kms.kms;
|
|
@@ -2644,7 +2958,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
2644
2958
|
const kms = factory(void 0, globals()).kms.kms;
|
|
2645
2959
|
const id = resolveKeyRef(kms, ref);
|
|
2646
2960
|
const entry = kms.getEntry(id);
|
|
2647
|
-
print({ action: "key-show", data: { keyId: id, publicKey: (0,
|
|
2961
|
+
print({ action: "key-show", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(entry.publicKey), ...entry.tags && { tags: entry.tags } } });
|
|
2648
2962
|
});
|
|
2649
2963
|
key.command("import").description("Import a key: a secret from a hex file, or a public key as watch-only.").option("--secret-file <path>", "Path to a file containing a 32-byte secret key as hex.").option("--public <hex>", "A 33-byte compressed public key as hex (imported watch-only).").option("--name <name>", "A human-friendly name, stored as a tag.").option("--set-active", "Make this the active key.", false).action((options) => {
|
|
2650
2964
|
if (Boolean(options.secretFile) === Boolean(options.public)) {
|
|
@@ -2655,13 +2969,13 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
2655
2969
|
const keyPair = options.secretFile ? new import_keypair.SchnorrKeyPair({ secretKey: readHexFile(options.secretFile, 32, "--secret-file") }) : new import_keypair.SchnorrKeyPair({ publicKey: parseHex(options.public ?? "", 33, "--public") });
|
|
2656
2970
|
const setActive = options.setActive ?? false;
|
|
2657
2971
|
const id = api.kms.import(keyPair, { ...options.name && { tags: { name: options.name } }, setActive });
|
|
2658
|
-
print({ action: "key-import", data: { keyId: id, publicKey: (0,
|
|
2972
|
+
print({ action: "key-import", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)), watchOnly: !options.secretFile, active: setActive } });
|
|
2659
2973
|
});
|
|
2660
2974
|
key.command("export <ref>").description("Export a key. Public material by default; --secret writes the secret to a file.").option("--secret", "Export the secret key. Requires --out.", false).option("--out <path>", "Write the exported secret to this file (created 0600).").action((ref, options) => {
|
|
2661
2975
|
const api = factory(void 0, globals());
|
|
2662
2976
|
const id = resolveKeyRef(api.kms.kms, ref);
|
|
2663
2977
|
if (!options.secret) {
|
|
2664
|
-
print({ action: "key-export", data: { keyId: id, publicKey: (0,
|
|
2978
|
+
print({ action: "key-export", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)) } });
|
|
2665
2979
|
return;
|
|
2666
2980
|
}
|
|
2667
2981
|
if (!options.out) {
|
|
@@ -2672,7 +2986,7 @@ function registerKeyCommand(program, factory, globals) {
|
|
|
2672
2986
|
throw new CLIError(`Key ${id} is watch-only and has no secret to export.`, "INVALID_ARGUMENT_ERROR", { keyId: id });
|
|
2673
2987
|
}
|
|
2674
2988
|
process.stderr.write("warning: writing an unencrypted secret key to disk. Protect this file and delete it when done.\n");
|
|
2675
|
-
writeSecretFile(options.out, (0,
|
|
2989
|
+
writeSecretFile(options.out, (0, import_utils8.bytesToHex)(keyPair.secretKey.bytes));
|
|
2676
2990
|
print({ action: "key-export", data: { keyId: id, secretWrittenTo: options.out } });
|
|
2677
2991
|
});
|
|
2678
2992
|
key.command("delete <ref>").alias("rm").description("Delete a key from the keystore.").option("--force", "Delete even if it is the active key.", false).action((ref, options) => {
|
|
@@ -2697,7 +3011,7 @@ function assertNameAvailable(kms, name) {
|
|
|
2697
3011
|
function parseHex(hex, expectedBytes, label) {
|
|
2698
3012
|
let bytes;
|
|
2699
3013
|
try {
|
|
2700
|
-
bytes = (0,
|
|
3014
|
+
bytes = (0, import_utils8.hexToBytes)(hex.trim());
|
|
2701
3015
|
} catch {
|
|
2702
3016
|
throw new CLIError(`Invalid hex for ${label}.`, "INVALID_ARGUMENT_ERROR", { label });
|
|
2703
3017
|
}
|
|
@@ -2713,7 +3027,7 @@ function parseHex(hex, expectedBytes, label) {
|
|
|
2713
3027
|
function readHexFile(path, expectedBytes, label) {
|
|
2714
3028
|
let content;
|
|
2715
3029
|
try {
|
|
2716
|
-
content = (0,
|
|
3030
|
+
content = (0, import_node_fs10.readFileSync)(path, "utf-8");
|
|
2717
3031
|
} catch {
|
|
2718
3032
|
throw new CLIError(`Cannot read ${label} at ${path}.`, "INVALID_ARGUMENT_ERROR", { label, path });
|
|
2719
3033
|
}
|
|
@@ -2722,7 +3036,7 @@ function readHexFile(path, expectedBytes, label) {
|
|
|
2722
3036
|
function writeSecretFile(path, contents) {
|
|
2723
3037
|
let fd;
|
|
2724
3038
|
try {
|
|
2725
|
-
fd = (0,
|
|
3039
|
+
fd = (0, import_node_fs10.openSync)(path, "wx", 384);
|
|
2726
3040
|
} catch (error) {
|
|
2727
3041
|
if (error.code === "EEXIST") {
|
|
2728
3042
|
throw new CLIError(`Refusing to overwrite existing file ${path}. Choose a new --out path.`, "INVALID_ARGUMENT_ERROR", { path });
|
|
@@ -2730,14 +3044,14 @@ function writeSecretFile(path, contents) {
|
|
|
2730
3044
|
throw error;
|
|
2731
3045
|
}
|
|
2732
3046
|
try {
|
|
2733
|
-
(0,
|
|
3047
|
+
(0, import_node_fs10.writeFileSync)(fd, contents);
|
|
2734
3048
|
} finally {
|
|
2735
|
-
(0,
|
|
3049
|
+
(0, import_node_fs10.closeSync)(fd);
|
|
2736
3050
|
}
|
|
2737
3051
|
}
|
|
2738
3052
|
|
|
2739
3053
|
// src/commands/config.ts
|
|
2740
|
-
var
|
|
3054
|
+
var import_node_fs11 = require("fs");
|
|
2741
3055
|
|
|
2742
3056
|
// src/config-schema.ts
|
|
2743
3057
|
var CONFIG_SCHEMA = {
|
|
@@ -2874,7 +3188,7 @@ function registerConfigCommand(program, globals) {
|
|
|
2874
3188
|
const print = (result) => console.log(formatResult(result, globals()));
|
|
2875
3189
|
config.command("init").description("Create a default config file with one profile per network.").option("--force", "Overwrite an existing config file.", false).action((options) => {
|
|
2876
3190
|
const p = path();
|
|
2877
|
-
if ((0,
|
|
3191
|
+
if ((0, import_node_fs11.existsSync)(p) && !options.force) {
|
|
2878
3192
|
throw new CLIError(`Config already exists at ${p}. Use --force to overwrite.`, "INVALID_ARGUMENT_ERROR", { path: p });
|
|
2879
3193
|
}
|
|
2880
3194
|
writeDefaultConfigFile(p);
|
|
@@ -3024,7 +3338,7 @@ function registerProfileCommand(program, globals) {
|
|
|
3024
3338
|
}
|
|
3025
3339
|
|
|
3026
3340
|
// src/commands/completion.ts
|
|
3027
|
-
var COMMANDS = "create resolve read update deactivate delete identifier key config profile completion";
|
|
3341
|
+
var COMMANDS = "create resolve read update deactivate delete identifier genesis key config profile completion";
|
|
3028
3342
|
function registerCompletionCommand(program, _globals) {
|
|
3029
3343
|
program.command("completion [shell]").description("Print a shell completion script (bash, zsh, or fish) to stdout.").action((shell = "bash") => {
|
|
3030
3344
|
console.log(completionScript(shell));
|
|
@@ -3055,18 +3369,18 @@ function completionScript(shell) {
|
|
|
3055
3369
|
}
|
|
3056
3370
|
|
|
3057
3371
|
// src/version.ts
|
|
3058
|
-
var
|
|
3059
|
-
var
|
|
3372
|
+
var import_node_fs12 = require("fs");
|
|
3373
|
+
var import_node_path7 = require("path");
|
|
3060
3374
|
var import_node_url = require("url");
|
|
3061
3375
|
function readVersion() {
|
|
3062
|
-
let dir = (0,
|
|
3376
|
+
let dir = (0, import_node_path7.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
3063
3377
|
for (let i = 0; i < 5; i++) {
|
|
3064
3378
|
try {
|
|
3065
|
-
const pkg = JSON.parse((0,
|
|
3379
|
+
const pkg = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path7.join)(dir, "package.json"), "utf-8"));
|
|
3066
3380
|
if (pkg.name === "@did-btcr2/cli") return pkg.version;
|
|
3067
3381
|
} catch {
|
|
3068
3382
|
}
|
|
3069
|
-
dir = (0,
|
|
3383
|
+
dir = (0, import_node_path7.dirname)(dir);
|
|
3070
3384
|
}
|
|
3071
3385
|
return "0.0.0";
|
|
3072
3386
|
}
|
|
@@ -3103,6 +3417,7 @@ var DidBtcr2Cli = class {
|
|
|
3103
3417
|
registerUpdateCommand(this.program, keystoreFactory, globals);
|
|
3104
3418
|
registerDeactivateCommand(this.program, keystoreFactory, globals);
|
|
3105
3419
|
registerIdentifierCommand(this.program, factory, globals);
|
|
3420
|
+
registerGenesisCommand(this.program, factory, keystoreFactory, globals);
|
|
3106
3421
|
registerKeyCommand(this.program, keystoreFactory, globals);
|
|
3107
3422
|
registerKeystoreCommand(this.program, globals);
|
|
3108
3423
|
registerConfigCommand(this.program, globals);
|
|
@@ -3177,6 +3492,7 @@ function handleError(error, verbose) {
|
|
|
3177
3492
|
registerConfigCommand,
|
|
3178
3493
|
registerCreateCommand,
|
|
3179
3494
|
registerDeactivateCommand,
|
|
3495
|
+
registerGenesisCommand,
|
|
3180
3496
|
registerIdentifierCommand,
|
|
3181
3497
|
registerInitCommand,
|
|
3182
3498
|
registerKeyCommand,
|