@beclab/olaresid 0.1.13 → 0.2.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 (181) hide show
  1. package/CLI-TREE.md +107 -0
  2. package/CLI.md +122 -1340
  3. package/README.md +30 -12
  4. package/SDK-TREE.md +151 -0
  5. package/TAG.md +95 -41
  6. package/config.json +6 -4
  7. package/dist/abi/TerminusDIDQueryABI.d.ts +397 -0
  8. package/dist/abi/TerminusDIDQueryABI.d.ts.map +1 -0
  9. package/dist/abi/TerminusDIDQueryABI.js +519 -0
  10. package/dist/abi/TerminusDIDQueryABI.js.map +1 -0
  11. package/dist/business/index.d.ts.map +1 -1
  12. package/dist/business/index.js +9 -23
  13. package/dist/business/index.js.map +1 -1
  14. package/dist/business/tag-context.d.ts +1 -0
  15. package/dist/business/tag-context.d.ts.map +1 -1
  16. package/dist/business/tag-context.js +13 -7
  17. package/dist/business/tag-context.js.map +1 -1
  18. package/dist/cli.js +177 -76
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config/index.d.ts +16 -4
  21. package/dist/config/index.d.ts.map +1 -1
  22. package/dist/config/index.js +28 -14
  23. package/dist/config/index.js.map +1 -1
  24. package/dist/domain/core.d.ts +65 -0
  25. package/dist/domain/core.d.ts.map +1 -0
  26. package/dist/domain/core.js +317 -0
  27. package/dist/domain/core.js.map +1 -0
  28. package/dist/domain/index.d.ts +104 -57
  29. package/dist/domain/index.d.ts.map +1 -1
  30. package/dist/domain/index.js +188 -428
  31. package/dist/domain/index.js.map +1 -1
  32. package/dist/domain/types.d.ts +56 -0
  33. package/dist/domain/types.d.ts.map +1 -0
  34. package/dist/domain/types.js +3 -0
  35. package/dist/domain/types.js.map +1 -0
  36. package/dist/index.d.ts +80 -23
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +152 -143
  39. package/dist/index.js.map +1 -1
  40. package/dist/utils/crypto-utils.d.ts +110 -0
  41. package/dist/utils/crypto-utils.d.ts.map +1 -1
  42. package/dist/utils/crypto-utils.js +127 -8
  43. package/dist/utils/crypto-utils.js.map +1 -1
  44. package/dist/utils/error-parser.d.ts.map +1 -1
  45. package/dist/utils/error-parser.js +2 -1
  46. package/dist/utils/error-parser.js.map +1 -1
  47. package/dist/utils/event-parser.d.ts +161 -0
  48. package/dist/utils/event-parser.d.ts.map +1 -0
  49. package/dist/utils/event-parser.js +140 -0
  50. package/dist/utils/event-parser.js.map +1 -0
  51. package/dist/utils/tag-type-builder.d.ts +43 -0
  52. package/dist/utils/tag-type-builder.d.ts.map +1 -1
  53. package/dist/utils/tag-type-builder.js +122 -0
  54. package/dist/utils/tag-type-builder.js.map +1 -1
  55. package/dist/utils/tag-type-parser.d.ts +70 -0
  56. package/dist/utils/tag-type-parser.d.ts.map +1 -0
  57. package/dist/utils/tag-type-parser.js +190 -0
  58. package/dist/utils/tag-type-parser.js.map +1 -0
  59. package/examples/create-with-rpc-demo.ts +142 -0
  60. package/examples/fetch-all-flat-demo.ts +159 -0
  61. package/examples/fetch-by-indices-demo.ts +235 -0
  62. package/examples/fetch-domain-demo.ts +137 -0
  63. package/examples/fetch-domains-demo.ts +221 -0
  64. package/examples/frontend-demo/index.html +2 -2
  65. package/examples/frontend-demo/package-lock.json +4 -1
  66. package/examples/index.ts +3 -5
  67. package/jest.config.js +25 -0
  68. package/package.json +6 -2
  69. package/src/abi/TerminusDIDQueryABI.ts +516 -0
  70. package/src/business/index.ts +9 -33
  71. package/src/business/tag-context.ts +35 -7
  72. package/src/cli.ts +253 -90
  73. package/src/config/index.ts +34 -19
  74. package/src/domain/core.ts +382 -0
  75. package/src/domain/index.ts +271 -641
  76. package/src/domain/types.ts +59 -0
  77. package/src/index.ts +221 -207
  78. package/src/utils/crypto-utils.ts +205 -2
  79. package/src/utils/error-parser.ts +2 -1
  80. package/src/utils/event-parser.ts +353 -0
  81. package/src/utils/tag-type-builder.ts +138 -0
  82. package/src/utils/tag-type-parser.ts +246 -0
  83. package/tests/unit/crypto-utils.test.ts +338 -0
  84. package/tests/unit/ed25519-jwk.test.ts +201 -0
  85. package/tests/unit/event-parser.test.ts +690 -0
  86. package/tests/unit/generate-mnemonic.test.ts +268 -0
  87. package/tests/unit/olares-id-format.test.ts +321 -0
  88. package/tests/unit/tag-type-parser.test.ts +802 -0
  89. package/tests/unit/tag-types.test.ts +821 -0
  90. package/tsconfig.json +3 -2
  91. package/dist/abi/ABITypeABI.d.ts +0 -88
  92. package/dist/abi/ABITypeABI.d.ts.map +0 -1
  93. package/dist/abi/ABITypeABI.js +0 -382
  94. package/dist/abi/ABITypeABI.js.map +0 -1
  95. package/dist/abi/RegistryABI.d.ts +0 -77
  96. package/dist/abi/RegistryABI.d.ts.map +0 -1
  97. package/dist/abi/RegistryABI.js +0 -462
  98. package/dist/abi/RegistryABI.js.map +0 -1
  99. package/dist/tag/address.d.ts +0 -11
  100. package/dist/tag/address.d.ts.map +0 -1
  101. package/dist/tag/address.js +0 -44
  102. package/dist/tag/address.js.map +0 -1
  103. package/dist/tag/array.d.ts +0 -14
  104. package/dist/tag/array.d.ts.map +0 -1
  105. package/dist/tag/array.js +0 -72
  106. package/dist/tag/array.js.map +0 -1
  107. package/dist/tag/bool.d.ts +0 -11
  108. package/dist/tag/bool.d.ts.map +0 -1
  109. package/dist/tag/bool.js +0 -43
  110. package/dist/tag/bool.js.map +0 -1
  111. package/dist/tag/bytes.d.ts +0 -11
  112. package/dist/tag/bytes.d.ts.map +0 -1
  113. package/dist/tag/bytes.js +0 -37
  114. package/dist/tag/bytes.js.map +0 -1
  115. package/dist/tag/flarray.d.ts +0 -15
  116. package/dist/tag/flarray.d.ts.map +0 -1
  117. package/dist/tag/flarray.js +0 -81
  118. package/dist/tag/flarray.js.map +0 -1
  119. package/dist/tag/flbytes.d.ts +0 -11
  120. package/dist/tag/flbytes.d.ts.map +0 -1
  121. package/dist/tag/flbytes.js +0 -47
  122. package/dist/tag/flbytes.js.map +0 -1
  123. package/dist/tag/index.d.ts +0 -32
  124. package/dist/tag/index.d.ts.map +0 -1
  125. package/dist/tag/index.js +0 -121
  126. package/dist/tag/index.js.map +0 -1
  127. package/dist/tag/int.d.ts +0 -12
  128. package/dist/tag/int.d.ts.map +0 -1
  129. package/dist/tag/int.js +0 -49
  130. package/dist/tag/int.js.map +0 -1
  131. package/dist/tag/string.d.ts +0 -11
  132. package/dist/tag/string.d.ts.map +0 -1
  133. package/dist/tag/string.js +0 -37
  134. package/dist/tag/string.js.map +0 -1
  135. package/dist/tag/tag.d.ts +0 -67
  136. package/dist/tag/tag.d.ts.map +0 -1
  137. package/dist/tag/tag.js +0 -157
  138. package/dist/tag/tag.js.map +0 -1
  139. package/dist/tag/tuple.d.ts +0 -17
  140. package/dist/tag/tuple.d.ts.map +0 -1
  141. package/dist/tag/tuple.js +0 -162
  142. package/dist/tag/tuple.js.map +0 -1
  143. package/dist/tag/uint.d.ts +0 -12
  144. package/dist/tag/uint.d.ts.map +0 -1
  145. package/dist/tag/uint.js +0 -49
  146. package/dist/tag/uint.js.map +0 -1
  147. package/dist/test/did.d.ts +0 -2
  148. package/dist/test/did.d.ts.map +0 -1
  149. package/dist/test/did.js +0 -177
  150. package/dist/test/did.js.map +0 -1
  151. package/dist/utils/tag-abi-codec.d.ts +0 -69
  152. package/dist/utils/tag-abi-codec.d.ts.map +0 -1
  153. package/dist/utils/tag-abi-codec.js +0 -144
  154. package/dist/utils/tag-abi-codec.js.map +0 -1
  155. package/examples/crypto-utilities.ts +0 -140
  156. package/examples/ed25519-jwk.ts +0 -73
  157. package/examples/generate-mnemonic.ts +0 -149
  158. package/examples/legacy.ts +0 -33
  159. package/examples/olares-id-format.ts +0 -197
  160. package/examples/tag-builder.ts +0 -235
  161. package/examples/tag-nested-tuple.ts +0 -190
  162. package/examples/tag-simple.ts +0 -149
  163. package/examples/tag-tagger.ts +0 -217
  164. package/examples/test-nested-tuple-conversion.ts +0 -143
  165. package/examples/test-type-bytes-parser.ts +0 -70
  166. package/src/abi/ABITypeABI.ts +0 -379
  167. package/src/abi/RegistryABI.ts +0 -459
  168. package/src/tag/address.ts +0 -48
  169. package/src/tag/array.ts +0 -80
  170. package/src/tag/bool.ts +0 -43
  171. package/src/tag/bytes.ts +0 -38
  172. package/src/tag/flarray.ts +0 -99
  173. package/src/tag/flbytes.ts +0 -48
  174. package/src/tag/index.ts +0 -170
  175. package/src/tag/int.ts +0 -51
  176. package/src/tag/string.ts +0 -38
  177. package/src/tag/tag.ts +0 -229
  178. package/src/tag/tuple.ts +0 -193
  179. package/src/tag/uint.ts +0 -51
  180. package/src/test/did.ts +0 -346
  181. package/src/utils/tag-abi-codec.ts +0 -158
package/src/cli.ts CHANGED
@@ -39,6 +39,7 @@ const CLI_VERSION = packageJson.version;
39
39
 
40
40
  interface CliOptions {
41
41
  network: string;
42
+ from?: string;
42
43
  rpc?: string;
43
44
  contractDid?: string;
44
45
  contractResolver?: string;
@@ -85,7 +86,8 @@ function parseArgs(): {
85
86
  'is-owner',
86
87
  'transfer',
87
88
  'fetch',
88
- 'fetch-domain'
89
+ 'fetch-domain',
90
+ 'fetch-all'
89
91
  ];
90
92
 
91
93
  for (let i = 0; i < args.length; i++) {
@@ -98,6 +100,8 @@ function parseArgs(): {
98
100
  process.exit(0);
99
101
  } else if (arg === '--network' || arg === '-n') {
100
102
  options.network = args[++i] || 'mainnet';
103
+ } else if (arg === '--from') {
104
+ options.from = args[++i];
101
105
  } else if (arg === '--rpc') {
102
106
  options.rpc = args[++i];
103
107
  } else if (arg === '--contract-did') {
@@ -144,6 +148,26 @@ function parseArgs(): {
144
148
  return { command, subCommand, domain, value, options };
145
149
  }
146
150
 
151
+ function normalizeTagFromDomain(
152
+ from: string | undefined,
153
+ toDomain: string
154
+ ): string {
155
+ if (!from) {
156
+ return toDomain;
157
+ }
158
+
159
+ const normalized = from.trim().toLowerCase();
160
+ if (
161
+ normalized === 'root' ||
162
+ normalized === ':root' ||
163
+ normalized === '""'
164
+ ) {
165
+ return '';
166
+ }
167
+
168
+ return normalizeToDomain(from);
169
+ }
170
+
147
171
  function showHelp(): void {
148
172
  console.log(`
149
173
  DID CLI Tool v${CLI_VERSION}
@@ -197,15 +221,18 @@ COMMANDS:
197
221
  Define a new tag type (requires PRIVATE_KEY_OR_MNEMONIC)
198
222
  Supported types: string, uint8, uint256, int8, int256, bool, address, bytes, bytes32
199
223
  Array types: string[], uint8[], etc.
200
- tag set <domain> <tag-name> <value>
224
+ tag set <domain> <tag-name> <value> [--from <domain|root>]
201
225
  Set tag value (requires PRIVATE_KEY_OR_MNEMONIC)
202
- Value can be a string or JSON for arrays/objects
203
- tag get <domain> <tag-name>
226
+ Value can be a string or JSON for arrays/objects
227
+ --from specifies where tag type is defined (default: same as <domain>)
228
+ tag get <domain> <tag-name> [--from <domain|root>]
204
229
  Get tag value (read-only)
205
- tag remove <domain> <tag-name>
230
+ tag remove <domain> <tag-name> [--from <domain|root>]
206
231
  Remove tag value (requires PRIVATE_KEY_OR_MNEMONIC)
207
- tag list <domain> List all tags with values for domain (read-only)
208
- tag list-defined <domain> List all defined tag types for domain (read-only)
232
+ tag list <domain> [--from <domain|root>]
233
+ List all tags with values for domain (read-only)
234
+ tag list-defined [domain] List all tag types defined by the domain (read-only)
235
+ Omit domain to query tag types defined by root
209
236
  tag set-tagger <domain> <tag-name> <address>
210
237
  Set tagger address for a tag (requires PRIVATE_KEY_OR_MNEMONIC)
211
238
  tag get-tagger <domain> <tag-name>
@@ -228,7 +255,8 @@ COMMANDS:
228
255
  config set <key> <value> [--network <network>]
229
256
  Set configuration value (default network: mainnet)
230
257
  Keys: rpc, contractDid, contractRootResolver,
231
- contractAbiType, contractRootResolver2, supportSvcUrl
258
+ contractAbiType, contractRootResolver2,
259
+ supportSvcUrl, queryContract
232
260
 
233
261
  Crypto Utility Commands:
234
262
  crypto generate Generate a new mnemonic phrase (--words option)
@@ -248,12 +276,13 @@ COMMANDS:
248
276
 
249
277
  Legacy Commands:
250
278
  fetch <domain> Fetch domain information (alias: fetch-domain)
251
- fetch-all Fetch all domains from contract
252
- config Show network configurations
279
+ fetch-all Fetch all domains from contract and save to JSON file
280
+ Use --output to specify file path (default: domains-<network>-<date>.json)
253
281
  help Show this help message
254
282
 
255
283
  OPTIONS:
256
284
  -n, --network <network> Network to use (sepolia|mainnet) [default: mainnet]
285
+ --from <domain|root> Tag source domain for tag set/get/remove/list (default: target domain)
257
286
  --rpc <url> Custom RPC endpoint URL
258
287
  --contract-did <address> Custom DID contract address
259
288
  --contract-resolver <address> Custom RootResolver contract address
@@ -299,7 +328,6 @@ EXAMPLES:
299
328
  # Subdomain management (auto-generate mnemonic for subdomain owner)
300
329
  export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
301
330
  did-cli subdomain register parent.com child
302
- did-cli subdomain register parent.com child --words 24
303
331
 
304
332
  # Subdomain management (use existing mnemonic for subdomain owner)
305
333
  export SUBDOMAIN_OWNER_MNEMONIC="your twelve word mnemonic here"
@@ -311,7 +339,6 @@ EXAMPLES:
311
339
  # Transfer domain ownership (auto-generate mnemonic for new owner)
312
340
  export PRIVATE_KEY_OR_MNEMONIC=0xYOUR_PRIVATE_KEY
313
341
  did-cli transfer example.com
314
- did-cli transfer example.com --words 24
315
342
 
316
343
  # Transfer domain ownership (use existing mnemonic for new owner)
317
344
  export TO_MNEMONIC="your twelve word mnemonic here"
@@ -319,7 +346,7 @@ EXAMPLES:
319
346
 
320
347
  # Crypto utilities
321
348
  did-cli crypto generate --words 12
322
- did-cli crypto generate --words 24 --output ./custom-path.txt
349
+ did-cli crypto generate --output ./custom-path.txt
323
350
  export PRIVATE_KEY_OR_MNEMONIC="your twelve word mnemonic here"
324
351
  did-cli crypto address
325
352
  did-cli crypto did
@@ -390,8 +417,15 @@ EXAMPLES:
390
417
  did-cli config list # List all networks
391
418
  did-cli config set rpc https://optimism.llamarpc.com # Set mainnet RPC
392
419
  did-cli config set contractDid 0x1234... --network sepolia # Set sepolia contract
420
+ did-cli config set queryContract 0x637197... --network sepolia # Set query contract
393
421
  did-cli config set rpc https://my-rpc.com --network custom_net # Create new network
394
422
 
423
+ # Fetch all domains
424
+ did-cli fetch-all # Fetch all mainnet domains (auto-named file)
425
+ did-cli fetch-all --network sepolia # Fetch all sepolia domains
426
+ did-cli fetch-all --output ./my-domains.json # Custom output file path
427
+ did-cli fetch-all --network sepolia --verbose # With progress details
428
+
395
429
  # Utilities
396
430
  did-cli convert pem-to-der ./public-key.pem
397
431
  did-cli convert ip-to-bytes 192.168.1.1
@@ -421,39 +455,13 @@ async function fetchDomain(domain: string, options: CliOptions): Promise<void> {
421
455
  debug.setLevel(options.debugLevel as any);
422
456
  }
423
457
 
424
- // Get network configuration
425
- const config = getNetworkConfig(options.network);
426
- if (!config) {
427
- console.error(`❌ Unknown network: ${options.network}`);
428
- console.error(
429
- 'Available networks:',
430
- getAvailableNetworks().join(', ')
431
- );
432
- process.exit(1);
433
- }
434
-
435
- // Command line parameters take priority
436
- const finalConfig = {
437
- rpc: options.rpc || config.rpc,
438
- contractDid: options.contractDid || config.contractDid,
439
- contractRootResolver:
440
- options.contractResolver || config.contractRootResolver,
441
- contractAbiType: options.contractAbi || config.contractAbiType
442
- };
443
-
444
458
  if (debug.isEnabled()) {
445
459
  debug.info(`🔍 Fetching domain: ${domain}`);
446
460
  debug.info(`🌐 Network: ${options.network}`);
447
- debug.info('Using configuration:', finalConfig);
448
461
  }
449
462
 
450
- // Create DID console instance
451
- const olaresId = OlaresID.createConsole(
452
- finalConfig.rpc,
453
- finalConfig.contractDid,
454
- finalConfig.contractRootResolver,
455
- finalConfig.contractAbiType
456
- );
463
+ // Use getConsole helper to create console instance
464
+ const olaresId = getConsole(options);
457
465
 
458
466
  // Fetch domain data
459
467
  const domainData = await olaresId.fetchDomain(domain);
@@ -476,6 +484,93 @@ async function fetchDomain(domain: string, options: CliOptions): Promise<void> {
476
484
  }
477
485
  }
478
486
 
487
+ async function fetchAll(options: CliOptions): Promise<void> {
488
+ try {
489
+ // Set debug options
490
+ if (options.verbose || options.debug) {
491
+ debug.enable();
492
+ debug.setLevel(options.debugLevel as any);
493
+ }
494
+
495
+ if (debug.isEnabled()) {
496
+ debug.info('🔍 Fetching all domains');
497
+ debug.info(`🌐 Network: ${options.network}`);
498
+ }
499
+
500
+ // Use getConsole helper to create console instance
501
+ const olaresId = getConsole(options);
502
+
503
+ // Check if query contract is configured
504
+ if (!olaresId.queryContractAddress) {
505
+ console.error(
506
+ '❌ Query contract address not configured for this network'
507
+ );
508
+ console.error(
509
+ ` Use: did-cli config set queryContract <address> --network ${options.network}`
510
+ );
511
+ process.exit(1);
512
+ }
513
+
514
+ console.log('📡 Fetching all domains from contract...');
515
+ console.log(` Network: ${options.network}`);
516
+ console.log(` Query Contract: ${olaresId.queryContractAddress}`);
517
+ console.log();
518
+
519
+ let totalDomains = 0;
520
+ const startTime = Date.now();
521
+
522
+ // Fetch all domains with progress
523
+ const domains = await olaresId.fetchAllFlat({
524
+ batchSize: 100,
525
+ onProgress: (current, total) => {
526
+ totalDomains = total;
527
+ const percent = ((current / total) * 100).toFixed(1);
528
+ process.stdout.write(
529
+ `\r⏳ Progress: ${current}/${total} (${percent}%)`
530
+ );
531
+ }
532
+ });
533
+
534
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
535
+ process.stdout.write('\r' + ' '.repeat(50) + '\r'); // Clear progress line
536
+ console.log(`✅ Fetched ${totalDomains} domains in ${elapsed}s`);
537
+ console.log();
538
+
539
+ // Determine output file path
540
+ const timestamp = new Date()
541
+ .toISOString()
542
+ .replace(/[:.]/g, '-')
543
+ .split('T')[0];
544
+ const defaultFilename = `domains-${options.network}-${timestamp}.json`;
545
+ const outputPath =
546
+ options.output || path.join(process.cwd(), defaultFilename);
547
+
548
+ // Save to file
549
+ const jsonContent = JSON.stringify(domains, null, 2);
550
+ fs.writeFileSync(outputPath, jsonContent, 'utf-8');
551
+
552
+ console.log(`💾 Saved to: ${outputPath}`);
553
+ console.log(
554
+ ` File size: ${(jsonContent.length / 1024).toFixed(2)} KB`
555
+ );
556
+ console.log(` Total domains: ${domains.length}`);
557
+
558
+ if (debug.isEnabled()) {
559
+ debug.info('Fetch all completed successfully');
560
+ debug.info(`Output file: ${outputPath}`);
561
+ }
562
+ } catch (error) {
563
+ console.error(
564
+ '❌ Error fetching all domains:',
565
+ error instanceof Error ? error.message : String(error)
566
+ );
567
+ if (debug.isEnabled()) {
568
+ debug.error('Full error details:', error);
569
+ }
570
+ process.exit(1);
571
+ }
572
+ }
573
+
479
574
  // ============================================================================
480
575
  // Helper Functions
481
576
  // ============================================================================
@@ -502,7 +597,8 @@ function getConsole(options: CliOptions) {
502
597
  contractRootResolver2:
503
598
  options.contractRootResolver2 ||
504
599
  networkConfig.contractRootResolver2,
505
- supportSvcUrl: options.supportSvcUrl || networkConfig.supportSvcUrl
600
+ supportSvcUrl: options.supportSvcUrl || networkConfig.supportSvcUrl,
601
+ queryContract: networkConfig.queryContract
506
602
  };
507
603
 
508
604
  return OlaresID.createConsole(
@@ -511,7 +607,8 @@ function getConsole(options: CliOptions) {
511
607
  config.contractRootResolver,
512
608
  config.contractAbiType,
513
609
  config.contractRootResolver2,
514
- config.supportSvcUrl
610
+ config.supportSvcUrl,
611
+ config.queryContract
515
612
  );
516
613
  }
517
614
 
@@ -1996,6 +2093,11 @@ async function configShow(options: CliOptions): Promise<void> {
1996
2093
  console.log(
1997
2094
  ` Support Service URL: ${networkConfig.supportSvcUrl}`
1998
2095
  );
2096
+ console.log(
2097
+ ` Query Contract: ${
2098
+ networkConfig.queryContract || '(not set)'
2099
+ }`
2100
+ );
1999
2101
  console.log(`\n📄 Configuration file: ${getConfigFilePath()}`);
2000
2102
  }
2001
2103
  } catch (error) {
@@ -2064,7 +2166,8 @@ async function configSet(
2064
2166
  'contractRootResolver',
2065
2167
  'contractAbiType',
2066
2168
  'contractRootResolver2',
2067
- 'supportSvcUrl'
2169
+ 'supportSvcUrl',
2170
+ 'queryContract'
2068
2171
  ];
2069
2172
  if (!validKeys.includes(key)) {
2070
2173
  console.error(`❌ Invalid config key: ${key}`);
@@ -2218,7 +2321,8 @@ async function tagDefine(
2218
2321
  * Set tag value
2219
2322
  */
2220
2323
  async function tagSet(
2221
- domain: string,
2324
+ toDomain: string,
2325
+ fromDomain: string,
2222
2326
  tagName: string,
2223
2327
  valueStr: string,
2224
2328
  options: CliOptions
@@ -2228,10 +2332,13 @@ async function tagSet(
2228
2332
  const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
2229
2333
  await didConsole.setSigner(privateKeyOrMnemonic);
2230
2334
 
2231
- const domainContext = didConsole.domain(domain);
2335
+ const domainContext = didConsole.domain(fromDomain);
2232
2336
  const tagCtx = domainContext.tag();
2233
2337
 
2234
- console.log(`\n📝 Setting tag "${tagName}" for domain: ${domain}`);
2338
+ const fromLabel = fromDomain === '' ? '(root)' : fromDomain;
2339
+ console.log(`\n📝 Setting tag "${tagName}"`);
2340
+ console.log(` From: ${fromLabel}`);
2341
+ console.log(` To: ${toDomain}`);
2235
2342
  console.log(` Value: ${valueStr}`);
2236
2343
 
2237
2344
  // Try to parse value as JSON, otherwise use as string
@@ -2242,7 +2349,7 @@ async function tagSet(
2242
2349
  value = valueStr;
2243
2350
  }
2244
2351
 
2245
- const result = await tagCtx.setTag(domain, tagName, value);
2352
+ const result = await tagCtx.setTag(toDomain, tagName, value);
2246
2353
 
2247
2354
  if (result.success) {
2248
2355
  if (options.json) {
@@ -2250,7 +2357,8 @@ async function tagSet(
2250
2357
  JSON.stringify(
2251
2358
  {
2252
2359
  success: true,
2253
- domain,
2360
+ from: fromDomain,
2361
+ to: toDomain,
2254
2362
  tagName,
2255
2363
  value,
2256
2364
  transactionHash: result.transactionHash,
@@ -2286,18 +2394,22 @@ async function tagSet(
2286
2394
  * Get tag value
2287
2395
  */
2288
2396
  async function tagGet(
2289
- domain: string,
2397
+ toDomain: string,
2398
+ fromDomain: string,
2290
2399
  tagName: string,
2291
2400
  options: CliOptions
2292
2401
  ): Promise<void> {
2293
2402
  try {
2294
2403
  const didConsole = getConsole(options);
2295
- const domainContext = didConsole.domain(domain);
2404
+ const domainContext = didConsole.domain(fromDomain);
2296
2405
  const tagCtx = domainContext.tag();
2406
+ const fromLabel = fromDomain === '' ? '(root)' : fromDomain;
2297
2407
 
2298
- console.log(`\n📖 Getting tag "${tagName}" for domain: ${domain}`);
2408
+ console.log(`\n📖 Getting tag "${tagName}"`);
2409
+ console.log(` From: ${fromLabel}`);
2410
+ console.log(` To: ${toDomain}`);
2299
2411
 
2300
- const value = await tagCtx.getTag(domain, tagName);
2412
+ const value = await tagCtx.getTag(toDomain, tagName);
2301
2413
 
2302
2414
  if (value !== null && value !== undefined) {
2303
2415
  if (options.json) {
@@ -2305,7 +2417,8 @@ async function tagGet(
2305
2417
  JSON.stringify(
2306
2418
  {
2307
2419
  success: true,
2308
- domain,
2420
+ from: fromDomain,
2421
+ to: toDomain,
2309
2422
  tagName,
2310
2423
  value
2311
2424
  },
@@ -2333,7 +2446,8 @@ async function tagGet(
2333
2446
  console.log(
2334
2447
  JSON.stringify({
2335
2448
  success: true,
2336
- domain,
2449
+ from: fromDomain,
2450
+ to: toDomain,
2337
2451
  tagName,
2338
2452
  value: null
2339
2453
  })
@@ -2357,7 +2471,8 @@ async function tagGet(
2357
2471
  * Remove tag value
2358
2472
  */
2359
2473
  async function tagRemove(
2360
- domain: string,
2474
+ toDomain: string,
2475
+ fromDomain: string,
2361
2476
  tagName: string,
2362
2477
  options: CliOptions
2363
2478
  ): Promise<void> {
@@ -2366,12 +2481,15 @@ async function tagRemove(
2366
2481
  const privateKeyOrMnemonic = getPrivateKeyOrMnemonic();
2367
2482
  await didConsole.setSigner(privateKeyOrMnemonic);
2368
2483
 
2369
- const domainContext = didConsole.domain(domain);
2484
+ const domainContext = didConsole.domain(fromDomain);
2370
2485
  const tagCtx = domainContext.tag();
2486
+ const fromLabel = fromDomain === '' ? '(root)' : fromDomain;
2371
2487
 
2372
- console.log(`\n🗑️ Removing tag "${tagName}" for domain: ${domain}`);
2488
+ console.log(`\n🗑️ Removing tag "${tagName}"`);
2489
+ console.log(` From: ${fromLabel}`);
2490
+ console.log(` To: ${toDomain}`);
2373
2491
 
2374
- const result = await tagCtx.removeTag(domain, tagName);
2492
+ const result = await tagCtx.removeTag(toDomain, tagName);
2375
2493
 
2376
2494
  if (result.success) {
2377
2495
  if (options.json) {
@@ -2379,7 +2497,8 @@ async function tagRemove(
2379
2497
  JSON.stringify(
2380
2498
  {
2381
2499
  success: true,
2382
- domain,
2500
+ from: fromDomain,
2501
+ to: toDomain,
2383
2502
  tagName,
2384
2503
  transactionHash: result.transactionHash,
2385
2504
  gasUsed: result.gasUsed?.toString(),
@@ -2413,21 +2532,30 @@ async function tagRemove(
2413
2532
  /**
2414
2533
  * List all tags for a domain
2415
2534
  */
2416
- async function tagList(domain: string, options: CliOptions): Promise<void> {
2535
+ async function tagList(
2536
+ toDomain: string,
2537
+ fromDomain: string,
2538
+ options: CliOptions
2539
+ ): Promise<void> {
2417
2540
  try {
2418
2541
  const didConsole = getConsole(options);
2419
- const domainContext = didConsole.domain(domain);
2542
+ const domainContext = didConsole.domain(fromDomain);
2543
+ const tagCtx = domainContext.tag();
2544
+ const fromLabel = fromDomain === '' ? '(root)' : fromDomain;
2420
2545
 
2421
- console.log(`\n📋 Listing all tags for domain: ${domain}`);
2546
+ console.log(`\n📋 Listing all tags`);
2547
+ console.log(` From: ${fromLabel}`);
2548
+ console.log(` To: ${toDomain}`);
2422
2549
 
2423
- const tags = await domainContext.getAllTags();
2550
+ const tags = await tagCtx.getAllTags(toDomain);
2424
2551
 
2425
2552
  if (options.json) {
2426
2553
  console.log(
2427
2554
  JSON.stringify(
2428
2555
  {
2429
2556
  success: true,
2430
- domain,
2557
+ from: fromDomain,
2558
+ to: toDomain,
2431
2559
  count: tags.length,
2432
2560
  tags
2433
2561
  },
@@ -2470,7 +2598,8 @@ async function tagListDefined(
2470
2598
  const didConsole = getConsole(options);
2471
2599
  const domainContext = didConsole.domain(domain);
2472
2600
 
2473
- console.log(`\n📋 Listing defined tag types for domain: ${domain}`);
2601
+ const domainLabel = domain === '' ? '(root)' : domain;
2602
+ console.log(`\n📋 Listing tag types defined by: ${domainLabel}`);
2474
2603
 
2475
2604
  const tags = await domainContext.getDefinedTags();
2476
2605
 
@@ -2908,11 +3037,14 @@ async function main(): Promise<void> {
2908
3037
  '❌ Error: Usage: did-cli config set <key> <value> [--network <network>]'
2909
3038
  );
2910
3039
  console.error(
2911
- ' Valid keys: rpc, contractDid, contractRootResolver, contractAbiType, contractRootResolver2, supportSvcUrl'
3040
+ ' Valid keys: rpc, contractDid, contractRootResolver, contractAbiType, contractRootResolver2, supportSvcUrl, queryContract'
2912
3041
  );
2913
3042
  console.error(
2914
3043
  '\n Example: did-cli config set rpc https://optimism.llamarpc.com --network mainnet'
2915
3044
  );
3045
+ console.error(
3046
+ ' Example: did-cli config set queryContract 0xAf0430AB9f2450c52E7401846C7CA702D53eCFC2 --network sepolia'
3047
+ );
2916
3048
  process.exit(1);
2917
3049
  }
2918
3050
  break;
@@ -3122,7 +3254,7 @@ async function main(): Promise<void> {
3122
3254
  '❌ Error: tag set requires <domain>, <tag-name> and <value>'
3123
3255
  );
3124
3256
  console.error(
3125
- 'Usage: did-cli tag set <domain> <tag-name> <value>'
3257
+ 'Usage: did-cli tag set <domain> <tag-name> <value> [--from <domain|root>]'
3126
3258
  );
3127
3259
  console.error(
3128
3260
  ' Value can be a string or JSON (e.g., \'["item1","item2"]\' for arrays)'
@@ -3136,11 +3268,18 @@ async function main(): Promise<void> {
3136
3268
  const args = process.argv.slice(2);
3137
3269
  const setIdx = args.indexOf('set');
3138
3270
  if (setIdx >= 0 && args.length > setIdx + 3) {
3139
- const actualDomain = args[setIdx + 1];
3271
+ const actualDomain = normalizeToDomain(
3272
+ args[setIdx + 1]
3273
+ );
3274
+ const fromDomain = normalizeTagFromDomain(
3275
+ options.from,
3276
+ actualDomain
3277
+ );
3140
3278
  const tagName = args[setIdx + 2];
3141
3279
  const valueStr = args[setIdx + 3];
3142
3280
  await tagSet(
3143
3281
  actualDomain,
3282
+ fromDomain,
3144
3283
  tagName,
3145
3284
  valueStr,
3146
3285
  options
@@ -3150,7 +3289,7 @@ async function main(): Promise<void> {
3150
3289
  '❌ Error: Missing arguments for tag set'
3151
3290
  );
3152
3291
  console.error(
3153
- 'Usage: did-cli tag set <domain> <tag-name> <value>'
3292
+ 'Usage: did-cli tag set <domain> <tag-name> <value> [--from <domain|root>]'
3154
3293
  );
3155
3294
  process.exit(1);
3156
3295
  }
@@ -3163,7 +3302,7 @@ async function main(): Promise<void> {
3163
3302
  '❌ Error: tag get requires <domain> and <tag-name>'
3164
3303
  );
3165
3304
  console.error(
3166
- 'Usage: did-cli tag get <domain> <tag-name>'
3305
+ 'Usage: did-cli tag get <domain> <tag-name> [--from <domain|root>]'
3167
3306
  );
3168
3307
  process.exit(1);
3169
3308
  }
@@ -3171,15 +3310,26 @@ async function main(): Promise<void> {
3171
3310
  const args = process.argv.slice(2);
3172
3311
  const getIdx = args.indexOf('get');
3173
3312
  if (getIdx >= 0 && args.length > getIdx + 2) {
3174
- const actualDomain = args[getIdx + 1];
3313
+ const actualDomain = normalizeToDomain(
3314
+ args[getIdx + 1]
3315
+ );
3316
+ const fromDomain = normalizeTagFromDomain(
3317
+ options.from,
3318
+ actualDomain
3319
+ );
3175
3320
  const tagName = args[getIdx + 2];
3176
- await tagGet(actualDomain, tagName, options);
3321
+ await tagGet(
3322
+ actualDomain,
3323
+ fromDomain,
3324
+ tagName,
3325
+ options
3326
+ );
3177
3327
  } else {
3178
3328
  console.error(
3179
3329
  '❌ Error: Missing arguments for tag get'
3180
3330
  );
3181
3331
  console.error(
3182
- 'Usage: did-cli tag get <domain> <tag-name>'
3332
+ 'Usage: did-cli tag get <domain> <tag-name> [--from <domain|root>]'
3183
3333
  );
3184
3334
  process.exit(1);
3185
3335
  }
@@ -3192,7 +3342,7 @@ async function main(): Promise<void> {
3192
3342
  '❌ Error: tag remove requires <domain> and <tag-name>'
3193
3343
  );
3194
3344
  console.error(
3195
- 'Usage: did-cli tag remove <domain> <tag-name>'
3345
+ 'Usage: did-cli tag remove <domain> <tag-name> [--from <domain|root>]'
3196
3346
  );
3197
3347
  console.error(
3198
3348
  '\nNote: Set PRIVATE_KEY_OR_MNEMONIC environment variable first'
@@ -3203,15 +3353,26 @@ async function main(): Promise<void> {
3203
3353
  const args = process.argv.slice(2);
3204
3354
  const removeIdx = args.indexOf('remove');
3205
3355
  if (removeIdx >= 0 && args.length > removeIdx + 2) {
3206
- const actualDomain = args[removeIdx + 1];
3356
+ const actualDomain = normalizeToDomain(
3357
+ args[removeIdx + 1]
3358
+ );
3359
+ const fromDomain = normalizeTagFromDomain(
3360
+ options.from,
3361
+ actualDomain
3362
+ );
3207
3363
  const tagName = args[removeIdx + 2];
3208
- await tagRemove(actualDomain, tagName, options);
3364
+ await tagRemove(
3365
+ actualDomain,
3366
+ fromDomain,
3367
+ tagName,
3368
+ options
3369
+ );
3209
3370
  } else {
3210
3371
  console.error(
3211
3372
  '❌ Error: Missing arguments for tag remove'
3212
3373
  );
3213
3374
  console.error(
3214
- 'Usage: did-cli tag remove <domain> <tag-name>'
3375
+ 'Usage: did-cli tag remove <domain> <tag-name> [--from <domain|root>]'
3215
3376
  );
3216
3377
  process.exit(1);
3217
3378
  }
@@ -3223,23 +3384,21 @@ async function main(): Promise<void> {
3223
3384
  console.error(
3224
3385
  '❌ Error: Domain argument is required'
3225
3386
  );
3226
- console.error('Usage: did-cli tag list <domain>');
3387
+ console.error(
3388
+ 'Usage: did-cli tag list <domain> [--from <domain|root>]'
3389
+ );
3227
3390
  process.exit(1);
3228
3391
  }
3229
- await tagList(domain, options);
3392
+ const fromDomain = normalizeTagFromDomain(
3393
+ options.from,
3394
+ domain
3395
+ );
3396
+ await tagList(domain, fromDomain, options);
3230
3397
  break;
3231
3398
 
3232
3399
  case 'list-defined':
3233
- if (!domain) {
3234
- console.error(
3235
- '❌ Error: Domain argument is required'
3236
- );
3237
- console.error(
3238
- 'Usage: did-cli tag list-defined <domain>'
3239
- );
3240
- process.exit(1);
3241
- }
3242
- await tagListDefined(domain, options);
3400
+ // domain defaults to "" (root) when not provided
3401
+ await tagListDefined(domain ?? '', options);
3243
3402
  break;
3244
3403
 
3245
3404
  case 'set-tagger':
@@ -3341,6 +3500,10 @@ async function main(): Promise<void> {
3341
3500
  await fetchDomain(domain, options);
3342
3501
  break;
3343
3502
 
3503
+ case 'fetch-all':
3504
+ await fetchAll(options);
3505
+ break;
3506
+
3344
3507
  default:
3345
3508
  console.error(`❌ Unknown command: ${command}`);
3346
3509
  console.error('Run "did-cli help" for usage information');