@did-btcr2/cli 0.21.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.
Files changed (75) hide show
  1. package/README.md +29 -2
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cjs/index.js +494 -64
  4. package/dist/esm/src/cli.js +4 -2
  5. package/dist/esm/src/cli.js.map +1 -1
  6. package/dist/esm/src/commands/completion.js +1 -1
  7. package/dist/esm/src/commands/completion.js.map +1 -1
  8. package/dist/esm/src/commands/create.js +33 -41
  9. package/dist/esm/src/commands/create.js.map +1 -1
  10. package/dist/esm/src/commands/genesis.js +119 -0
  11. package/dist/esm/src/commands/genesis.js.map +1 -0
  12. package/dist/esm/src/commands/identifier.js +96 -0
  13. package/dist/esm/src/commands/identifier.js.map +1 -0
  14. package/dist/esm/src/commands/index.js +2 -0
  15. package/dist/esm/src/commands/index.js.map +1 -1
  16. package/dist/esm/src/commands/resolve.js +15 -1
  17. package/dist/esm/src/commands/resolve.js.map +1 -1
  18. package/dist/esm/src/commands/write.js +10 -7
  19. package/dist/esm/src/commands/write.js.map +1 -1
  20. package/dist/esm/src/genesis-document-file.js +26 -0
  21. package/dist/esm/src/genesis-document-file.js.map +1 -0
  22. package/dist/esm/src/genesis-spec.js +93 -0
  23. package/dist/esm/src/genesis-spec.js.map +1 -0
  24. package/dist/esm/src/genesis-wizard.js +132 -0
  25. package/dist/esm/src/genesis-wizard.js.map +1 -0
  26. package/dist/esm/src/hints.js +14 -3
  27. package/dist/esm/src/hints.js.map +1 -1
  28. package/dist/esm/src/network-option.js +39 -0
  29. package/dist/esm/src/network-option.js.map +1 -0
  30. package/dist/esm/src/resolution-options.js +19 -2
  31. package/dist/esm/src/resolution-options.js.map +1 -1
  32. package/dist/types/src/cli.d.ts +1 -1
  33. package/dist/types/src/cli.d.ts.map +1 -1
  34. package/dist/types/src/commands/create.d.ts +5 -4
  35. package/dist/types/src/commands/create.d.ts.map +1 -1
  36. package/dist/types/src/commands/genesis.d.ts +20 -0
  37. package/dist/types/src/commands/genesis.d.ts.map +1 -0
  38. package/dist/types/src/commands/identifier.d.ts +12 -0
  39. package/dist/types/src/commands/identifier.d.ts.map +1 -0
  40. package/dist/types/src/commands/index.d.ts +2 -0
  41. package/dist/types/src/commands/index.d.ts.map +1 -1
  42. package/dist/types/src/commands/resolve.d.ts +7 -0
  43. package/dist/types/src/commands/resolve.d.ts.map +1 -1
  44. package/dist/types/src/commands/write.d.ts +2 -1
  45. package/dist/types/src/commands/write.d.ts.map +1 -1
  46. package/dist/types/src/genesis-document-file.d.ts +11 -0
  47. package/dist/types/src/genesis-document-file.d.ts.map +1 -0
  48. package/dist/types/src/genesis-spec.d.ts +70 -0
  49. package/dist/types/src/genesis-spec.d.ts.map +1 -0
  50. package/dist/types/src/genesis-wizard.d.ts +30 -0
  51. package/dist/types/src/genesis-wizard.d.ts.map +1 -0
  52. package/dist/types/src/hints.d.ts +7 -0
  53. package/dist/types/src/hints.d.ts.map +1 -1
  54. package/dist/types/src/network-option.d.ts +15 -0
  55. package/dist/types/src/network-option.d.ts.map +1 -0
  56. package/dist/types/src/resolution-options.d.ts +6 -2
  57. package/dist/types/src/resolution-options.d.ts.map +1 -1
  58. package/dist/types/src/types.d.ts +38 -1
  59. package/dist/types/src/types.d.ts.map +1 -1
  60. package/package.json +3 -3
  61. package/src/cli.ts +5 -1
  62. package/src/commands/completion.ts +1 -1
  63. package/src/commands/create.ts +39 -55
  64. package/src/commands/genesis.ts +149 -0
  65. package/src/commands/identifier.ts +134 -0
  66. package/src/commands/index.ts +2 -0
  67. package/src/commands/resolve.ts +20 -1
  68. package/src/commands/write.ts +10 -7
  69. package/src/genesis-document-file.ts +35 -0
  70. package/src/genesis-spec.ts +149 -0
  71. package/src/genesis-wizard.ts +163 -0
  72. package/src/hints.ts +13 -2
  73. package/src/network-option.ts +50 -0
  74. package/src/resolution-options.ts +21 -2
  75. package/src/types.ts +34 -2
package/dist/cjs/index.js CHANGED
@@ -51,6 +51,8 @@ __export(index_exports, {
51
51
  registerConfigCommand: () => registerConfigCommand,
52
52
  registerCreateCommand: () => registerCreateCommand,
53
53
  registerDeactivateCommand: () => registerDeactivateCommand,
54
+ registerGenesisCommand: () => registerGenesisCommand,
55
+ registerIdentifierCommand: () => registerIdentifierCommand,
54
56
  registerInitCommand: () => registerInitCommand,
55
57
  registerKeyCommand: () => registerKeyCommand,
56
58
  registerKeystoreCommand: () => registerKeystoreCommand,
@@ -2096,13 +2098,35 @@ function printNextSteps(init, unlocked, session, doctor) {
2096
2098
  // src/commands/create.ts
2097
2099
  var import_utils4 = require("@noble/hashes/utils.js");
2098
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
+
2099
2125
  // src/hints.ts
2100
2126
  var import_api3 = require("@did-btcr2/api");
2101
2127
  var import_method2 = require("@did-btcr2/method");
2102
2128
  function printCreateFundingHint(g, network, did) {
2103
2129
  if (g.quiet || g.output === "json") return;
2104
- const faucet = (0, import_api3.faucetUrl)(network);
2105
- if (!faucet) return;
2106
2130
  let beaconAddress;
2107
2131
  try {
2108
2132
  const { serviceEndpoint } = import_method2.BeaconUtils.createBeaconService(did, "p2wpkh", "SingletonBeacon");
@@ -2110,6 +2134,12 @@ function printCreateFundingHint(g, network, did) {
2110
2134
  } catch {
2111
2135
  return;
2112
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;
2113
2143
  const explorer = (0, import_api3.explorerAddressUrl)(network, beaconAddress);
2114
2144
  const lines = [
2115
2145
  "Fund the initial beacon to anchor updates:",
@@ -2165,33 +2195,59 @@ function resolveKeyRef(kms, ref) {
2165
2195
  throw new CLIError(`No key matches reference "${ref}".`, "KEY_NOT_FOUND_ERROR", { ref });
2166
2196
  }
2167
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
+
2168
2230
  // src/commands/create.ts
2169
2231
  var EXPECTED_BYTES = {
2170
2232
  k: { length: 33, label: "secp256k1 compressed public key (33 bytes)" },
2171
2233
  x: { length: 32, label: "SHA-256 hash (32 bytes)" }
2172
2234
  };
2173
2235
  function registerCreateCommand(program, factory, keystoreFactory, globals) {
2174
- program.command("create").description("Create an identifier and initial DID document").option("-t, --type <type>", "Identifier type <k|x>", "k").option(
2175
- "-n, --network <network>",
2176
- "Identifier bitcoin network <bitcoin|testnet3|testnet4|signet|mutinynet|regtest> (default: config defaults.network, else regtest)"
2177
- ).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(
2178
2237
  "-b, --bytes <bytes>",
2179
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.'
2180
2242
  ).action(async (options) => {
2181
2243
  const g = globals();
2182
2244
  if (options.type !== "k" && options.type !== "x") {
2183
2245
  throw new CLIError('Invalid type. Must be "k" or "x".', "INVALID_ARGUMENT_ERROR", options);
2184
2246
  }
2185
2247
  const overrides = overridesFromGlobals(g);
2186
- const network = resolveNetwork(options.network, overrides);
2248
+ const network = resolveNetworkOption(options.network, overrides);
2187
2249
  const signingKey = g.signingKey;
2188
- const mismatch = profileNetworkMismatch(network, overrides);
2189
- if (mismatch && !g.quiet) {
2190
- process.stderr.write(
2191
- `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.
2192
- `
2193
- );
2194
- }
2250
+ warnProfileNetworkMismatch(g, network, overrides);
2195
2251
  const print = (result, note) => {
2196
2252
  console.log(formatResult(result, g));
2197
2253
  if (note && g.output !== "json") process.stderr.write(`${note}
@@ -2204,9 +2260,21 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
2204
2260
  "INVALID_ARGUMENT_ERROR"
2205
2261
  );
2206
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
+ }
2207
2275
  if (options.bytes === void 0) {
2208
2276
  throw new CLIError(
2209
- "External identifiers (-t x) require --bytes <hex>, the 32-byte genesis document hash. Key generation is only available for -t k.",
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.",
2210
2278
  "INVALID_ARGUMENT_ERROR"
2211
2279
  );
2212
2280
  }
@@ -2215,6 +2283,9 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
2215
2283
  print({ action: "create", data: did2 });
2216
2284
  return;
2217
2285
  }
2286
+ if (options.document !== void 0) {
2287
+ throw new CLIError("--document applies only to external identifiers (-t x).", "INVALID_ARGUMENT_ERROR");
2288
+ }
2218
2289
  if (options.bytes !== void 0 && signingKey) {
2219
2290
  throw new CLIError(
2220
2291
  "Provide at most one of --bytes or --signing-key.",
@@ -2251,26 +2322,6 @@ function registerCreateCommand(program, factory, keystoreFactory, globals) {
2251
2322
  printCreateFundingHint(g, network, did);
2252
2323
  });
2253
2324
  }
2254
- function overridesFromGlobals(g) {
2255
- return {
2256
- home: g.home,
2257
- config: g.config,
2258
- profile: g.profile,
2259
- keystore: g.keystore,
2260
- passphraseFile: g.passphraseFile
2261
- };
2262
- }
2263
- function resolveNetwork(explicit, overrides) {
2264
- if (!explicit) return resolveDefaultNetwork(overrides);
2265
- if (!SUPPORTED_NETWORKS.includes(explicit)) {
2266
- throw new CLIError(
2267
- 'Invalid network. Must be one of "bitcoin", "testnet3", "testnet4", "signet", "mutinynet", or "regtest".',
2268
- "INVALID_ARGUMENT_ERROR",
2269
- { network: explicit }
2270
- );
2271
- }
2272
- return explicit;
2273
- }
2274
2325
  function parseGenesisBytes(hex, type) {
2275
2326
  const expected = EXPECTED_BYTES[type];
2276
2327
  let bytes;
@@ -2298,7 +2349,10 @@ var import_api5 = require("@did-btcr2/api");
2298
2349
 
2299
2350
  // src/resolution-options.ts
2300
2351
  var import_api4 = require("@did-btcr2/api");
2301
- var import_promises = require("fs/promises");
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
+ }
2302
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`;
2303
2357
  async function readResolutionOptions(flags) {
2304
2358
  let resolutionOptions;
@@ -2314,7 +2368,7 @@ async function readResolutionOptions(flags) {
2314
2368
  }
2315
2369
  } else if (flags.resolutionOptionsPath) {
2316
2370
  try {
2317
- const content = await (0, import_promises.readFile)(flags.resolutionOptionsPath, "utf-8");
2371
+ const content = await (0, import_promises2.readFile)(flags.resolutionOptionsPath, "utf-8");
2318
2372
  resolutionOptions = JSON.parse(content);
2319
2373
  } catch {
2320
2374
  throw new CLIError(
@@ -2327,6 +2381,13 @@ async function readResolutionOptions(flags) {
2327
2381
  if (flags.minConf !== void 0) {
2328
2382
  resolutionOptions = { ...resolutionOptions ?? {}, minConf: flags.minConf };
2329
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
+ }
2330
2391
  return resolutionOptions;
2331
2392
  }
2332
2393
  function parseMinConf(value) {
@@ -2342,7 +2403,7 @@ function parseMinConf(value) {
2342
2403
 
2343
2404
  // src/commands/resolve.ts
2344
2405
  function registerResolveCommand(program, factory, globals) {
2345
- 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) => {
2346
2407
  const parsed = await validateResolveOptions(options);
2347
2408
  const network = deriveNetwork(parsed.identifier);
2348
2409
  const api = factory(network, globals());
@@ -2352,13 +2413,24 @@ function registerResolveCommand(program, factory, globals) {
2352
2413
  });
2353
2414
  }
2354
2415
  async function validateResolveOptions(options) {
2355
- import_api5.Identifier.decode(options.identifier);
2416
+ const components = import_api5.Identifier.decode(options.identifier);
2417
+ assertGenesisDocumentApplies(options, components.hrp);
2356
2418
  const resolutionOptions = await readResolutionOptions(options);
2357
2419
  return { identifier: options.identifier, options: resolutionOptions };
2358
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
+ }
2359
2430
 
2360
2431
  // src/commands/write.ts
2361
2432
  var import_key_manager2 = require("@did-btcr2/key-manager");
2433
+ var import_api6 = require("@did-btcr2/api");
2362
2434
  function registerWriteOptions(command) {
2363
2435
  return command.option(
2364
2436
  "-s, --source-document <json>",
@@ -2380,7 +2452,7 @@ function registerWriteOptions(command) {
2380
2452
  ).option(
2381
2453
  "--resolution-options-path <path>",
2382
2454
  "Path to a JSON file with resolution options, for the resolution of the source document"
2383
- ).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(
2384
2456
  "--publish-to-cas <mode>",
2385
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.",
2386
2458
  parsePublishToCasMode,
@@ -2405,14 +2477,14 @@ async function prepareWrite(options, factory, g) {
2405
2477
  { did }
2406
2478
  );
2407
2479
  }
2408
- const hasResolutionFlags = options.resolutionOptions !== void 0 || options.resolutionOptionsPath !== void 0 || options.minConf !== void 0;
2409
- if (hasDocument && hasResolutionFlags) {
2480
+ if (hasDocument && hasResolutionFlags(options)) {
2410
2481
  throw new CLIError(
2411
- "--resolution-options, --resolution-options-path, and --min-conf apply only when --source-document and --source-version-id are omitted. A supplied source pair skips resolution.",
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.",
2412
2483
  "INVALID_ARGUMENT_ERROR",
2413
2484
  { did }
2414
2485
  );
2415
2486
  }
2487
+ assertGenesisDocumentApplies(options, import_api6.Identifier.decode(did).hrp);
2416
2488
  assertKeystoreAllowedForNetwork(network, g);
2417
2489
  const resolutionOptions = await readResolutionOptions(options);
2418
2490
  const api = factory(network, g);
@@ -2500,10 +2572,364 @@ function registerDeactivateCommand(program, factory, globals) {
2500
2572
  });
2501
2573
  }
2502
2574
 
2503
- // src/commands/key.ts
2504
- var import_keypair = require("@did-btcr2/keypair");
2575
+ // src/commands/identifier.ts
2576
+ var import_api7 = require("@did-btcr2/api");
2505
2577
  var import_utils5 = require("@noble/hashes/utils.js");
2578
+ function registerIdentifierCommand(program, factory, globals) {
2579
+ const identifier = program.command("identifier").description("Decode and validate did:btcr2 identifiers (offline).");
2580
+ const print = (result) => console.log(formatResult(result, globals()));
2581
+ identifier.command("decode <did>").description("Print the components of a did:btcr2 identifier.").option(
2582
+ "--initial-document",
2583
+ "Add the initial DID document. An external identifier (x) needs --genesis-document.",
2584
+ false
2585
+ ).option(
2586
+ "--genesis-document <path>",
2587
+ "Path to the JSON genesis document of an external identifier (x). Requires --initial-document."
2588
+ ).action(async (did, options) => {
2589
+ if (options.genesisDocument !== void 0 && !options.initialDocument) {
2590
+ throw new CLIError("--genesis-document requires --initial-document.", "INVALID_ARGUMENT_ERROR");
2591
+ }
2592
+ assertValidIdentifier(did);
2593
+ const api = factory();
2594
+ const components = api.did.decode(did);
2595
+ if (options.genesisDocument !== void 0 && components.hrp === "k") {
2596
+ throw new CLIError(
2597
+ "--genesis-document applies only to external identifiers (x).",
2598
+ "INVALID_ARGUMENT_ERROR",
2599
+ { did }
2600
+ );
2601
+ }
2602
+ const data = {
2603
+ did,
2604
+ idType: components.idType,
2605
+ hrp: components.hrp,
2606
+ version: components.version,
2607
+ network: components.network,
2608
+ genesisBytes: (0, import_utils5.bytesToHex)(components.genesisBytes)
2609
+ };
2610
+ if (options.initialDocument) {
2611
+ if (components.hrp === "x" && options.genesisDocument === void 0) {
2612
+ throw new CLIError(
2613
+ "An external identifier (x) needs --genesis-document <path> for --initial-document.",
2614
+ "INVALID_ARGUMENT_ERROR",
2615
+ { did }
2616
+ );
2617
+ }
2618
+ const genesisDocument = options.genesisDocument === void 0 ? void 0 : await readGenesisDocumentFile(options.genesisDocument);
2619
+ data.initialDocument = api.btcr2.getInitialDocument(did, genesisDocument);
2620
+ }
2621
+ print({ action: "identifier-decode", data });
2622
+ });
2623
+ identifier.command("validate <did>").description("Check that a did:btcr2 identifier conforms to the specification. Exit code 1 if it does not.").option(
2624
+ "-b, --bytes <hex>",
2625
+ "Genesis bytes as a hex string that the identifier must encode: the 33-byte public key (k) or the 32-byte genesis document hash (x). Adds the genesisBytesMatch check."
2626
+ ).option(
2627
+ "--genesis-document <path>",
2628
+ "Path to the JSON genesis document of an external identifier (x). Adds the genesisDocument check."
2629
+ ).action(async (did, options) => {
2630
+ const genesisBytes = options.bytes === void 0 ? void 0 : parseHexBytes(options.bytes);
2631
+ let genesisDocument;
2632
+ if (options.genesisDocument !== void 0) {
2633
+ if (import_api7.Identifier.isValid(did) && import_api7.Identifier.decode(did).hrp === "k") {
2634
+ throw new CLIError(
2635
+ "--genesis-document applies only to external identifiers (x).",
2636
+ "INVALID_ARGUMENT_ERROR",
2637
+ { did }
2638
+ );
2639
+ }
2640
+ genesisDocument = await readGenesisDocumentFile(options.genesisDocument);
2641
+ }
2642
+ const report = factory().did.validate(did, { genesisBytes, genesisDocument });
2643
+ print({ action: "identifier-validate", data: report });
2644
+ if (!report.valid) process.exitCode = 1;
2645
+ });
2646
+ }
2647
+ function assertValidIdentifier(did) {
2648
+ const report = import_api7.Identifier.validate(did);
2649
+ if (report.valid) return;
2650
+ const failed = report.checks[report.checks.length - 1];
2651
+ throw new CLIError(
2652
+ `Invalid identifier (${failed.name} check): ${failed.detail ?? "failed"}`,
2653
+ "INVALID_ARGUMENT_ERROR",
2654
+ { did, check: failed.name }
2655
+ );
2656
+ }
2657
+ function parseHexBytes(value) {
2658
+ try {
2659
+ return (0, import_utils5.hexToBytes)(value.trim());
2660
+ } catch {
2661
+ throw new CLIError("Invalid bytes: not valid hex.", "INVALID_ARGUMENT_ERROR", { bytes: value });
2662
+ }
2663
+ }
2664
+
2665
+ // src/commands/genesis.ts
2666
+ var import_utils7 = require("@noble/hashes/utils.js");
2506
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) {
2884
+ let parsed;
2885
+ try {
2886
+ parsed = JSON.parse(await (0, import_promises3.readFile)(path, "utf-8"));
2887
+ } catch {
2888
+ throw new CLIError(
2889
+ "Invalid genesis spec path. Must be a valid path to a JSON file.",
2890
+ "INVALID_ARGUMENT_ERROR",
2891
+ { spec: path }
2892
+ );
2893
+ }
2894
+ return parseGenesisSpec(parsed, path);
2895
+ }
2896
+ async function runWizard(kms) {
2897
+ if (!process.stdin.isTTY) {
2898
+ throw new CLIError(
2899
+ "No terminal is attached. Pass --spec <path> to build the genesis document without prompts.",
2900
+ "INVALID_ARGUMENT_ERROR"
2901
+ );
2902
+ }
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
+ });
2927
+ }
2928
+
2929
+ // src/commands/key.ts
2930
+ var import_keypair = require("@did-btcr2/keypair");
2931
+ var import_utils8 = require("@noble/hashes/utils.js");
2932
+ var import_node_fs10 = require("fs");
2507
2933
  function registerKeyCommand(program, factory, globals) {
2508
2934
  const key = program.command("key").description("Manage keypairs in the encrypted keystore.");
2509
2935
  const print = (result) => console.log(formatResult(result, globals()));
@@ -2512,7 +2938,7 @@ function registerKeyCommand(program, factory, globals) {
2512
2938
  assertNameAvailable(api.kms.kms, options.name);
2513
2939
  const setActive = options.setActive ?? false;
2514
2940
  const id = api.kms.generateKey({ ...options.name && { tags: { name: options.name } }, setActive });
2515
- print({ action: "key-generate", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)), active: setActive } });
2941
+ print({ action: "key-generate", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)), active: setActive } });
2516
2942
  });
2517
2943
  key.command("list").alias("ls").description("List stored keys.").action(() => {
2518
2944
  const kms = factory(void 0, globals()).kms.kms;
@@ -2532,7 +2958,7 @@ function registerKeyCommand(program, factory, globals) {
2532
2958
  const kms = factory(void 0, globals()).kms.kms;
2533
2959
  const id = resolveKeyRef(kms, ref);
2534
2960
  const entry = kms.getEntry(id);
2535
- print({ action: "key-show", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(entry.publicKey), ...entry.tags && { tags: entry.tags } } });
2961
+ print({ action: "key-show", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(entry.publicKey), ...entry.tags && { tags: entry.tags } } });
2536
2962
  });
2537
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) => {
2538
2964
  if (Boolean(options.secretFile) === Boolean(options.public)) {
@@ -2543,13 +2969,13 @@ function registerKeyCommand(program, factory, globals) {
2543
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") });
2544
2970
  const setActive = options.setActive ?? false;
2545
2971
  const id = api.kms.import(keyPair, { ...options.name && { tags: { name: options.name } }, setActive });
2546
- print({ action: "key-import", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)), watchOnly: !options.secretFile, active: setActive } });
2972
+ print({ action: "key-import", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)), watchOnly: !options.secretFile, active: setActive } });
2547
2973
  });
2548
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) => {
2549
2975
  const api = factory(void 0, globals());
2550
2976
  const id = resolveKeyRef(api.kms.kms, ref);
2551
2977
  if (!options.secret) {
2552
- print({ action: "key-export", data: { keyId: id, publicKey: (0, import_utils5.bytesToHex)(api.kms.getPublicKey(id)) } });
2978
+ print({ action: "key-export", data: { keyId: id, publicKey: (0, import_utils8.bytesToHex)(api.kms.getPublicKey(id)) } });
2553
2979
  return;
2554
2980
  }
2555
2981
  if (!options.out) {
@@ -2560,7 +2986,7 @@ function registerKeyCommand(program, factory, globals) {
2560
2986
  throw new CLIError(`Key ${id} is watch-only and has no secret to export.`, "INVALID_ARGUMENT_ERROR", { keyId: id });
2561
2987
  }
2562
2988
  process.stderr.write("warning: writing an unencrypted secret key to disk. Protect this file and delete it when done.\n");
2563
- writeSecretFile(options.out, (0, import_utils5.bytesToHex)(keyPair.secretKey.bytes));
2989
+ writeSecretFile(options.out, (0, import_utils8.bytesToHex)(keyPair.secretKey.bytes));
2564
2990
  print({ action: "key-export", data: { keyId: id, secretWrittenTo: options.out } });
2565
2991
  });
2566
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) => {
@@ -2585,7 +3011,7 @@ function assertNameAvailable(kms, name) {
2585
3011
  function parseHex(hex, expectedBytes, label) {
2586
3012
  let bytes;
2587
3013
  try {
2588
- bytes = (0, import_utils5.hexToBytes)(hex.trim());
3014
+ bytes = (0, import_utils8.hexToBytes)(hex.trim());
2589
3015
  } catch {
2590
3016
  throw new CLIError(`Invalid hex for ${label}.`, "INVALID_ARGUMENT_ERROR", { label });
2591
3017
  }
@@ -2601,7 +3027,7 @@ function parseHex(hex, expectedBytes, label) {
2601
3027
  function readHexFile(path, expectedBytes, label) {
2602
3028
  let content;
2603
3029
  try {
2604
- content = (0, import_node_fs9.readFileSync)(path, "utf-8");
3030
+ content = (0, import_node_fs10.readFileSync)(path, "utf-8");
2605
3031
  } catch {
2606
3032
  throw new CLIError(`Cannot read ${label} at ${path}.`, "INVALID_ARGUMENT_ERROR", { label, path });
2607
3033
  }
@@ -2610,7 +3036,7 @@ function readHexFile(path, expectedBytes, label) {
2610
3036
  function writeSecretFile(path, contents) {
2611
3037
  let fd;
2612
3038
  try {
2613
- fd = (0, import_node_fs9.openSync)(path, "wx", 384);
3039
+ fd = (0, import_node_fs10.openSync)(path, "wx", 384);
2614
3040
  } catch (error) {
2615
3041
  if (error.code === "EEXIST") {
2616
3042
  throw new CLIError(`Refusing to overwrite existing file ${path}. Choose a new --out path.`, "INVALID_ARGUMENT_ERROR", { path });
@@ -2618,14 +3044,14 @@ function writeSecretFile(path, contents) {
2618
3044
  throw error;
2619
3045
  }
2620
3046
  try {
2621
- (0, import_node_fs9.writeFileSync)(fd, contents);
3047
+ (0, import_node_fs10.writeFileSync)(fd, contents);
2622
3048
  } finally {
2623
- (0, import_node_fs9.closeSync)(fd);
3049
+ (0, import_node_fs10.closeSync)(fd);
2624
3050
  }
2625
3051
  }
2626
3052
 
2627
3053
  // src/commands/config.ts
2628
- var import_node_fs10 = require("fs");
3054
+ var import_node_fs11 = require("fs");
2629
3055
 
2630
3056
  // src/config-schema.ts
2631
3057
  var CONFIG_SCHEMA = {
@@ -2762,7 +3188,7 @@ function registerConfigCommand(program, globals) {
2762
3188
  const print = (result) => console.log(formatResult(result, globals()));
2763
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) => {
2764
3190
  const p = path();
2765
- if ((0, import_node_fs10.existsSync)(p) && !options.force) {
3191
+ if ((0, import_node_fs11.existsSync)(p) && !options.force) {
2766
3192
  throw new CLIError(`Config already exists at ${p}. Use --force to overwrite.`, "INVALID_ARGUMENT_ERROR", { path: p });
2767
3193
  }
2768
3194
  writeDefaultConfigFile(p);
@@ -2912,7 +3338,7 @@ function registerProfileCommand(program, globals) {
2912
3338
  }
2913
3339
 
2914
3340
  // src/commands/completion.ts
2915
- var COMMANDS = "create resolve read update deactivate delete key config profile completion";
3341
+ var COMMANDS = "create resolve read update deactivate delete identifier genesis key config profile completion";
2916
3342
  function registerCompletionCommand(program, _globals) {
2917
3343
  program.command("completion [shell]").description("Print a shell completion script (bash, zsh, or fish) to stdout.").action((shell = "bash") => {
2918
3344
  console.log(completionScript(shell));
@@ -2943,18 +3369,18 @@ function completionScript(shell) {
2943
3369
  }
2944
3370
 
2945
3371
  // src/version.ts
2946
- var import_node_fs11 = require("fs");
2947
- var import_node_path6 = require("path");
3372
+ var import_node_fs12 = require("fs");
3373
+ var import_node_path7 = require("path");
2948
3374
  var import_node_url = require("url");
2949
3375
  function readVersion() {
2950
- let dir = (0, import_node_path6.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
3376
+ let dir = (0, import_node_path7.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
2951
3377
  for (let i = 0; i < 5; i++) {
2952
3378
  try {
2953
- const pkg = JSON.parse((0, import_node_fs11.readFileSync)((0, import_node_path6.join)(dir, "package.json"), "utf-8"));
3379
+ const pkg = JSON.parse((0, import_node_fs12.readFileSync)((0, import_node_path7.join)(dir, "package.json"), "utf-8"));
2954
3380
  if (pkg.name === "@did-btcr2/cli") return pkg.version;
2955
3381
  } catch {
2956
3382
  }
2957
- dir = (0, import_node_path6.dirname)(dir);
3383
+ dir = (0, import_node_path7.dirname)(dir);
2958
3384
  }
2959
3385
  return "0.0.0";
2960
3386
  }
@@ -2972,7 +3398,7 @@ var DidBtcr2Cli = class {
2972
3398
  * for known networks and localhost Polar for regtest.
2973
3399
  *
2974
3400
  * @param factory - Optional API factory for keystore-free commands (create,
2975
- * resolve). Defaults to {@link defaultApiFactory}.
3401
+ * resolve, identifier). Defaults to {@link defaultApiFactory}.
2976
3402
  * @param keystoreFactory - Optional keystore-aware API factory for commands
2977
3403
  * that need a signing identity (key, update, deactivate). Defaults to
2978
3404
  * {@link keystoreApiFactory}.
@@ -2990,6 +3416,8 @@ var DidBtcr2Cli = class {
2990
3416
  registerResolveCommand(this.program, factory, globals);
2991
3417
  registerUpdateCommand(this.program, keystoreFactory, globals);
2992
3418
  registerDeactivateCommand(this.program, keystoreFactory, globals);
3419
+ registerIdentifierCommand(this.program, factory, globals);
3420
+ registerGenesisCommand(this.program, factory, keystoreFactory, globals);
2993
3421
  registerKeyCommand(this.program, keystoreFactory, globals);
2994
3422
  registerKeystoreCommand(this.program, globals);
2995
3423
  registerConfigCommand(this.program, globals);
@@ -3064,6 +3492,8 @@ function handleError(error, verbose) {
3064
3492
  registerConfigCommand,
3065
3493
  registerCreateCommand,
3066
3494
  registerDeactivateCommand,
3495
+ registerGenesisCommand,
3496
+ registerIdentifierCommand,
3067
3497
  registerInitCommand,
3068
3498
  registerKeyCommand,
3069
3499
  registerKeystoreCommand,