polkadot-cli 1.3.0 → 1.5.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 (3) hide show
  1. package/README.md +38 -3
  2. package/dist/cli.mjs +101 -36
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -251,11 +251,17 @@ dot query System.Number
251
251
  # Map entry by key
252
252
  dot query System.Account 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
253
253
 
254
- # All map entries (default limit: 100)
255
- dot query System.Account --limit 10
254
+ # Map without key — shows help/usage (use --dump to fetch all entries)
255
+ dot query System.Account
256
+
257
+ # Dump all map entries (requires --dump, default limit: 100)
258
+ dot query System.Account --dump --limit 10
259
+
260
+ # Enum variant as map key (case-insensitive)
261
+ dot query people-preview.ChunksManager.Chunks R2e9 1
256
262
 
257
263
  # Pipe-safe — stdout is clean data, progress messages go to stderr
258
- dot query System.Account --limit 5 | jq '.[0].value.data.free'
264
+ dot query System.Account --dump --limit 5 | jq '.[0].value.data.free'
259
265
  dot query System.Number --output json | jq '.+1'
260
266
 
261
267
  # Query a specific chain using chain prefix
@@ -315,6 +321,8 @@ dot inspect kusama.System
315
321
  dot inspect kusama.System.Account
316
322
  ```
317
323
 
324
+ All listings — pallets, storage items, constants, calls, events, and errors — are sorted alphabetically, making it easy to find a specific item at a glance.
325
+
318
326
  The pallet listing view shows type information inline so you can understand item shapes at a glance:
319
327
 
320
328
  - **Storage**: key/value types with `[map]` tag for map items (e.g. `Account: AccountId32 → { nonce: u32, ... } [map]`)
@@ -451,6 +459,31 @@ dot tx Balances.transferKeepAlive 5GrwvaEF... abc --encode
451
459
 
452
460
  For struct-based calls, the error identifies the specific field that failed. For tuple-based calls, it shows the argument index. The original parse error is preserved as the `cause` for programmatic access.
453
461
 
462
+ #### Wait level
463
+
464
+ By default, `dot tx` waits for finalization (~30s on Polkadot). Use `--wait` / `-w` to return earlier:
465
+
466
+ ```bash
467
+ # Return as soon as the tx is broadcast (fastest)
468
+ dot tx System.remark 0xdead --from alice --wait broadcast
469
+
470
+ # Return when included in a best block
471
+ dot tx System.remark 0xdead --from alice -w best-block
472
+ dot tx System.remark 0xdead --from alice -w best # alias
473
+
474
+ # Wait for finalization (default, unchanged)
475
+ dot tx System.remark 0xdead --from alice --wait finalized
476
+ dot tx System.remark 0xdead --from alice # same
477
+ ```
478
+
479
+ | Level | Resolves when | Events shown | Explorer links |
480
+ |-------|---------------|:---:|:---:|
481
+ | `broadcast` | Tx is broadcast to the network | — | — |
482
+ | `best-block` / `best` | Tx is included in a best block | yes | yes |
483
+ | `finalized` (default) | Tx is finalized | yes | yes |
484
+
485
+ The `--wait` flag is silently ignored when combined with `--dry-run` or `--encode` (both return before submission).
486
+
454
487
  #### Custom signed extensions
455
488
 
456
489
  Chains with non-standard signed extensions (e.g. `people-preview`) are auto-handled:
@@ -526,7 +559,9 @@ dot tx.System.remark 0xdead # shows call help (no error)
526
559
  | `--rpc <url>` | Override RPC endpoint(s) for this call (repeat for fallback) |
527
560
  | `--light-client` | Use Smoldot light client |
528
561
  | `--output json` | Raw JSON output (default: pretty) |
562
+ | `--dump` | Dump all entries of a storage map (required for keyless map queries) |
529
563
  | `--limit <n>` | Max entries for map queries (0 = unlimited, default: 100) |
564
+ | `-w, --wait <level>` | Tx wait level: `broadcast`, `best-block` / `best`, `finalized` (default) |
530
565
 
531
566
  ### Pipe-safe output
532
567
 
package/dist/cli.mjs CHANGED
@@ -447,26 +447,27 @@ async function getOrFetchMetadata(chainName, clientHandle) {
447
447
  return parseMetadata(raw);
448
448
  }
449
449
  function listPallets(meta) {
450
- return meta.unified.pallets.map((p) => ({
450
+ const sortByName = (arr) => arr.sort((a, b) => a.name.localeCompare(b.name));
451
+ return sortByName(meta.unified.pallets.map((p) => ({
451
452
  name: p.name,
452
453
  index: p.index,
453
454
  docs: p.docs ?? [],
454
- storage: (p.storage?.items ?? []).map((s) => ({
455
+ storage: sortByName((p.storage?.items ?? []).map((s) => ({
455
456
  name: s.name,
456
457
  docs: s.docs ?? [],
457
458
  type: s.type.tag,
458
459
  keyTypeId: s.type.tag === "map" ? s.type.value.key : null,
459
460
  valueTypeId: s.type.tag === "plain" ? s.type.value : s.type.value.value
460
- })),
461
- constants: (p.constants ?? []).map((c) => ({
461
+ }))),
462
+ constants: sortByName((p.constants ?? []).map((c) => ({
462
463
  name: c.name,
463
464
  docs: c.docs ?? [],
464
465
  typeId: c.type
465
- })),
466
- calls: extractEnumVariants(meta, p.calls),
467
- events: extractEnumVariants(meta, p.events),
468
- errors: extractEnumVariants(meta, p.errors).map(({ name, docs }) => ({ name, docs }))
469
- }));
466
+ }))),
467
+ calls: sortByName(extractEnumVariants(meta, p.calls)),
468
+ events: sortByName(extractEnumVariants(meta, p.events)),
469
+ errors: sortByName(extractEnumVariants(meta, p.errors).map(({ name, docs }) => ({ name, docs })))
470
+ })));
470
471
  }
471
472
  function extractEnumVariants(meta, ref) {
472
473
  if (!ref)
@@ -505,7 +506,7 @@ function getSignedExtensions(meta) {
505
506
  return byVersion[Number(versionKeys[0])] ?? [];
506
507
  }
507
508
  function getPalletNames(meta) {
508
- return meta.unified.pallets.map((p) => p.name);
509
+ return meta.unified.pallets.map((p) => p.name).sort((a, b) => a.localeCompare(b));
509
510
  }
510
511
  function describeType(lookup, typeId) {
511
512
  try {
@@ -766,6 +767,9 @@ async function generateCompletions(currentWord, precedingWords) {
766
767
  const names = [...DEV_NAMES, ...accounts.accounts.map((a) => a.name)];
767
768
  return filterPrefix(names, currentWord);
768
769
  }
770
+ if (prevWord === "--wait" || prevWord === "-w") {
771
+ return filterPrefix(["broadcast", "best-block", "best", "finalized"], currentWord);
772
+ }
769
773
  if (currentWord.startsWith("--")) {
770
774
  const activeCategory = detectCategory(precedingWords, knownChains);
771
775
  const options = [...GLOBAL_OPTIONS];
@@ -807,7 +811,11 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
807
811
  const partial = endsWithDot ? "" : parts[parts.length - 1] ?? "";
808
812
  const numComplete = completeSegments.length;
809
813
  if (numComplete === 0 && !endsWithDot) {
810
- const candidates = [...CATEGORIES.map(String), ...knownChains, ...NAMED_COMMANDS];
814
+ const candidates = [
815
+ ...CATEGORIES.map((c) => `${c}.`),
816
+ ...knownChains.map((c) => `${c}.`),
817
+ ...NAMED_COMMANDS
818
+ ];
811
819
  return filterPrefix(candidates, partial);
812
820
  }
813
821
  const first = completeSegments[0] ?? "";
@@ -822,7 +830,7 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
822
830
  if (!pallets)
823
831
  return [];
824
832
  const filtered = filterPallets(pallets, category);
825
- const candidates = filtered.map((p) => `${first}.${p.name}`);
833
+ const candidates = filtered.map((p) => `${first}.${p.name}.`);
826
834
  return filterPrefix(candidates, currentWord.slice(0, -1));
827
835
  }
828
836
  if (numComplete === 1 && !endsWithDot) {
@@ -831,7 +839,7 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
831
839
  if (!pallets)
832
840
  return [];
833
841
  const filtered = filterPallets(pallets, category);
834
- const candidates = filtered.map((p) => `${first}.${p.name}`);
842
+ const candidates = filtered.map((p) => `${first}.${p.name}.`);
835
843
  return filterPrefix(candidates, currentWord);
836
844
  }
837
845
  if (numComplete === 2) {
@@ -852,11 +860,11 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
852
860
  if (firstIsChain) {
853
861
  const chainName = first;
854
862
  if (numComplete === 1 && endsWithDot) {
855
- const candidates = CATEGORIES.map((c) => `${first}.${c}`);
863
+ const candidates = CATEGORIES.map((c) => `${first}.${c}.`);
856
864
  return filterPrefix(candidates, currentWord.slice(0, -1));
857
865
  }
858
866
  if (numComplete === 1 && !endsWithDot) {
859
- const candidates = CATEGORIES.map((c) => `${first}.${c}`);
867
+ const candidates = CATEGORIES.map((c) => `${first}.${c}.`);
860
868
  return filterPrefix(candidates, currentWord);
861
869
  }
862
870
  if (numComplete === 2) {
@@ -868,7 +876,7 @@ async function completeDotpath(currentWord, config, knownChains, precedingWords)
868
876
  return [];
869
877
  const filtered = filterPallets(pallets, category);
870
878
  const prefix = `${first}.${completeSegments[1]}`;
871
- const candidates = filtered.map((p) => `${prefix}.${p.name}`);
879
+ const candidates = filtered.map((p) => `${prefix}.${p.name}.`);
872
880
  return filterPrefix(candidates, endsWithDot ? currentWord.slice(0, -1) : currentWord);
873
881
  }
874
882
  if (numComplete === 3) {
@@ -924,14 +932,14 @@ var init_complete = __esm(() => {
924
932
  "inspect"
925
933
  ];
926
934
  GLOBAL_OPTIONS = ["--chain", "--rpc", "--light-client", "--output", "--help", "--version"];
927
- TX_OPTIONS = ["--from", "--dry-run", "--encode", "--ext"];
935
+ TX_OPTIONS = ["--from", "--dry-run", "--encode", "--ext", "--wait"];
928
936
  QUERY_OPTIONS = ["--limit"];
929
937
  });
930
938
 
931
939
  // src/cli.ts
932
940
  import cac from "cac";
933
941
  // package.json
934
- var version = "1.3.0";
942
+ var version = "1.5.0";
935
943
 
936
944
  // src/commands/account.ts
937
945
  init_accounts_store();
@@ -1700,9 +1708,10 @@ async function chainDefault(name) {
1700
1708
 
1701
1709
  // src/commands/completions.ts
1702
1710
  var ZSH_SCRIPT = `_dot_completions() {
1711
+ emulate -L zsh
1703
1712
  local -a completions
1704
1713
  local current_word="\${words[CURRENT]}"
1705
- local preceding=("\${words[@]:1:CURRENT-2}")
1714
+ local preceding=("\${words[2,CURRENT-1]}")
1706
1715
 
1707
1716
  # Build args: -- <current_word> <preceding_words...>
1708
1717
  local args=("__complete" "--" "\${current_word}")
@@ -2132,13 +2141,14 @@ async function showItemHelp(category, target, opts) {
2132
2141
  if (storageItem.keyTypeId != null) {
2133
2142
  console.log(`${BOLD}Usage:${RESET}`);
2134
2143
  console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
2135
- console.log(` dot query.${pallet.name}.${storageItem.name} # all entries`);
2144
+ console.log(` dot query.${pallet.name}.${storageItem.name} --dump # all entries`);
2136
2145
  } else {
2137
2146
  console.log(`${BOLD}Usage:${RESET}`);
2138
2147
  console.log(` dot query.${pallet.name}.${storageItem.name}`);
2139
2148
  }
2140
2149
  console.log();
2141
2150
  console.log(`${BOLD}Options:${RESET}`);
2151
+ console.log(` --dump Dump all entries of a map (required for keyless map queries)`);
2142
2152
  console.log(` --limit <n> Max entries for map queries (0 = unlimited, default: 100)`);
2143
2153
  console.log();
2144
2154
  return;
@@ -2576,13 +2586,14 @@ async function showItemHelp2(category, target, opts) {
2576
2586
  if (storageItem.keyTypeId != null) {
2577
2587
  console.log(`${BOLD}Usage:${RESET}`);
2578
2588
  console.log(` dot query.${pallet.name}.${storageItem.name} <key>`);
2579
- console.log(` dot query.${pallet.name}.${storageItem.name} # all entries`);
2589
+ console.log(` dot query.${pallet.name}.${storageItem.name} --dump # all entries`);
2580
2590
  } else {
2581
2591
  console.log(`${BOLD}Usage:${RESET}`);
2582
2592
  console.log(` dot query.${pallet.name}.${storageItem.name}`);
2583
2593
  }
2584
2594
  console.log();
2585
2595
  console.log(`${BOLD}Options:${RESET}`);
2596
+ console.log(` --dump Dump all entries of a map (required for keyless map queries)`);
2586
2597
  console.log(` --limit <n> Max entries for map queries (0 = unlimited, default: 100)`);
2587
2598
  console.log();
2588
2599
  return;
@@ -3256,7 +3267,8 @@ async function parseTypedArg(meta, entry, arg) {
3256
3267
  const matched = variants.find((v) => v.toLowerCase() === arg.toLowerCase());
3257
3268
  if (matched) {
3258
3269
  const variant = entry.value[matched];
3259
- if (variant.type === "void") {
3270
+ const resolved = variant.type === "lookupEntry" ? variant.value : variant;
3271
+ if (resolved.type === "void") {
3260
3272
  return { type: matched };
3261
3273
  }
3262
3274
  }
@@ -3404,6 +3416,12 @@ async function handleQuery(target, keys, opts) {
3404
3416
  const parsedKeys = await parseStorageKeys(meta, palletInfo.name, storageItem, keys);
3405
3417
  const format = opts.output ?? "pretty";
3406
3418
  if (storageItem.type === "map" && parsedKeys.length === 0) {
3419
+ if (!opts.dump) {
3420
+ clientHandle.destroy();
3421
+ await showItemHelp("query", target, { chain: opts.chain, rpc: opts.rpc });
3422
+ console.log(`${DIM}Hint: use --dump to fetch all entries${RESET}`);
3423
+ return;
3424
+ }
3407
3425
  const entries = await storageApi.getEntries();
3408
3426
  const limit = Number(opts.limit);
3409
3427
  const truncated = limit > 0 && entries.length > limit;
@@ -3472,6 +3490,20 @@ import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
3472
3490
  import { Binary as Binary3 } from "polkadot-api";
3473
3491
  init_metadata();
3474
3492
  init_errors();
3493
+ function parseWaitLevel(raw) {
3494
+ switch (raw) {
3495
+ case "broadcast":
3496
+ return "broadcast";
3497
+ case "best-block":
3498
+ case "best":
3499
+ return "best-block";
3500
+ case "finalized":
3501
+ case undefined:
3502
+ return "finalized";
3503
+ default:
3504
+ throw new CliError(`Invalid --wait value "${raw}". Valid: broadcast, best-block, best, finalized`);
3505
+ }
3506
+ }
3475
3507
  async function handleTx(target, args, opts) {
3476
3508
  if (!target) {
3477
3509
  const config2 = await loadConfig();
@@ -3605,15 +3637,23 @@ async function handleTx(target, args, opts) {
3605
3637
  }
3606
3638
  return;
3607
3639
  }
3608
- const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions));
3640
+ const waitLevel = parseWaitLevel(opts.wait);
3641
+ const result = await watchTransaction(tx.signSubmitAndWatch(signer, txOptions), waitLevel);
3609
3642
  console.log();
3610
3643
  console.log(` ${BOLD}Chain:${RESET} ${chainName}`);
3611
3644
  console.log(` ${BOLD}Call:${RESET} ${callHex}`);
3612
3645
  console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
3613
3646
  console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
3647
+ if (result.type === "broadcasted") {
3648
+ console.log(` ${BOLD}Status:${RESET} ${GREEN}broadcasted${RESET}`);
3649
+ console.log(` ${DIM}Note: tx was broadcast but not yet included in a block${RESET}`);
3650
+ console.log();
3651
+ return;
3652
+ }
3614
3653
  let dispatchErrorMsg;
3615
3654
  if (result.ok) {
3616
- console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
3655
+ const hint = result.type === "txBestBlocksState" ? ` ${DIM}(best block, not yet finalized)${RESET}` : "";
3656
+ console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}${hint}`);
3617
3657
  } else {
3618
3658
  dispatchErrorMsg = formatDispatchError(result.dispatchError);
3619
3659
  console.log(` ${BOLD}Status:${RESET} ${RED}dispatch error${RESET}`);
@@ -4089,7 +4129,8 @@ async function parseTypedArg2(meta, entry, arg) {
4089
4129
  const matched = variants.find((v) => v.toLowerCase() === arg.toLowerCase());
4090
4130
  if (matched) {
4091
4131
  const variant = entry.value[matched];
4092
- if (variant.type === "void") {
4132
+ const resolved = variant.type === "lookupEntry" ? variant.value : variant;
4133
+ if (resolved.type === "void") {
4093
4134
  return { type: matched };
4094
4135
  }
4095
4136
  }
@@ -4222,12 +4263,15 @@ function autoDefaultForType(entry) {
4222
4263
  }
4223
4264
  return NO_DEFAULT2;
4224
4265
  }
4225
- function watchTransaction(observable) {
4266
+ function watchTransaction(observable, level) {
4226
4267
  const spinner = new Spinner;
4227
4268
  return new Promise((resolve, reject) => {
4269
+ let settled = false;
4228
4270
  spinner.start("Signing...");
4229
- observable.subscribe({
4271
+ const subscription = observable.subscribe({
4230
4272
  next(event) {
4273
+ if (settled)
4274
+ return;
4231
4275
  switch (event.type) {
4232
4276
  case "signed":
4233
4277
  spinner.succeed("Signed");
@@ -4235,24 +4279,41 @@ function watchTransaction(observable) {
4235
4279
  spinner.start("Broadcasting...");
4236
4280
  break;
4237
4281
  case "broadcasted":
4238
- spinner.succeed("Broadcasted");
4239
- spinner.start("In best block...");
4282
+ if (level === "broadcast") {
4283
+ spinner.succeed("Broadcasted");
4284
+ settled = true;
4285
+ subscription.unsubscribe();
4286
+ resolve(event);
4287
+ } else {
4288
+ spinner.succeed("Broadcasted");
4289
+ spinner.start("In best block...");
4290
+ }
4240
4291
  break;
4241
4292
  case "txBestBlocksState":
4242
4293
  if (event.found) {
4243
- spinner.succeed(`In best block #${event.block.number}`);
4244
- spinner.start("Finalizing...");
4294
+ if (level === "best-block") {
4295
+ spinner.succeed(`In best block #${event.block.number}`);
4296
+ settled = true;
4297
+ subscription.unsubscribe();
4298
+ resolve(event);
4299
+ } else {
4300
+ spinner.succeed(`In best block #${event.block.number}`);
4301
+ spinner.start("Finalizing...");
4302
+ }
4245
4303
  } else {
4246
4304
  spinner.start("In best block...");
4247
4305
  }
4248
4306
  break;
4249
4307
  case "finalized":
4250
4308
  spinner.succeed(`Finalized in block #${event.block.number}`);
4309
+ settled = true;
4251
4310
  resolve(event);
4252
4311
  break;
4253
4312
  }
4254
4313
  },
4255
4314
  error(err) {
4315
+ if (settled)
4316
+ return;
4256
4317
  spinner.stop();
4257
4318
  reject(err);
4258
4319
  }
@@ -4555,9 +4616,11 @@ if (process.argv[2] === "__complete") {
4555
4616
  registerAccountCommands(cli);
4556
4617
  registerHashCommand(cli);
4557
4618
  registerCompletionsCommand(cli);
4558
- cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
4619
+ cli.command("[dotpath] [...args]").option("--from <name>", "Account to sign with (for tx)").option("--dry-run", "Estimate fees without submitting (for tx)").option("--encode", "Encode call to hex without signing (for tx)").option("--ext <json>", "Custom signed extension values as JSON (for tx)").option("-w, --wait <level>", "Resolve at: broadcast, best-block (or best), finalized (for tx)", {
4620
+ default: "finalized"
4621
+ }).option("--limit <n>", "Max entries to return for map queries (0 = unlimited)", {
4559
4622
  default: 100
4560
- }).action(async (dotpath, args, opts) => {
4623
+ }).option("--dump", "Dump all entries of a storage map (without specifying a key)").action(async (dotpath, args, opts) => {
4561
4624
  if (!dotpath) {
4562
4625
  printHelp();
4563
4626
  return;
@@ -4582,7 +4645,7 @@ if (process.argv[2] === "__complete") {
4582
4645
  }
4583
4646
  switch (parsed.category) {
4584
4647
  case "query":
4585
- await handleQuery(target, args, { ...handlerOpts, limit: opts.limit });
4648
+ await handleQuery(target, args, { ...handlerOpts, limit: opts.limit, dump: opts.dump });
4586
4649
  break;
4587
4650
  case "tx":
4588
4651
  if (parsed.pallet && /^0x[0-9a-fA-F]+$/.test(parsed.pallet)) {
@@ -4591,7 +4654,8 @@ if (process.argv[2] === "__complete") {
4591
4654
  from: opts.from,
4592
4655
  dryRun: opts.dryRun,
4593
4656
  encode: opts.encode,
4594
- ext: opts.ext
4657
+ ext: opts.ext,
4658
+ wait: opts.wait
4595
4659
  });
4596
4660
  } else {
4597
4661
  await handleTx(target, args, {
@@ -4599,7 +4663,8 @@ if (process.argv[2] === "__complete") {
4599
4663
  from: opts.from,
4600
4664
  dryRun: opts.dryRun,
4601
4665
  encode: opts.encode,
4602
- ext: opts.ext
4666
+ ext: opts.ext,
4667
+ wait: opts.wait
4603
4668
  });
4604
4669
  }
4605
4670
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polkadot-cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "CLI tool for querying Polkadot-ecosystem on-chain state",
5
5
  "type": "module",
6
6
  "bin": {