polkadot-cli 0.9.0 → 0.11.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 +35 -7
  2. package/dist/cli.mjs +192 -75
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,13 +19,16 @@ This installs the `dot` command globally.
19
19
  ### Manage chains
20
20
 
21
21
  ```bash
22
+ # Show chain help
23
+ dot chain # shows available actions
24
+ dot chains # shorthand, same as above
25
+
22
26
  # Add a chain
23
27
  dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
24
28
  dot chain add westend --light-client
25
29
 
26
30
  # List configured chains
27
- dot chains # shorthand
28
- dot chain list # equivalent
31
+ dot chain list
29
32
 
30
33
  # Re-fetch metadata after a runtime upgrade
31
34
  dot chain update # updates default chain
@@ -42,12 +45,15 @@ dot chain remove westend
42
45
 
43
46
  Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for testnets. Create or import your own accounts for any chain.
44
47
 
45
- > **Security warning:** Account secrets (mnemonics and seeds) are currently stored **unencrypted** in `~/.polkadot/accounts.json`. Do not use this for high-value accounts on mainnet. Encrypted storage is planned for a future release.
48
+ > **Security warning:** Account secrets (mnemonics and seeds) are currently stored **unencrypted** in `~/.polkadot/accounts.json`. Do not use this for high-value accounts on mainnet. Encrypted storage is planned for a future release. Use `--env` to keep secrets off disk entirely.
46
49
 
47
50
  ```bash
51
+ # Show account help
52
+ dot account # shows available actions
53
+ dot accounts # shorthand, same as above
54
+
48
55
  # List all accounts (dev + stored)
49
- dot accounts # shorthand
50
- dot account list # equivalent
56
+ dot account list
51
57
 
52
58
  # Create a new account (generates a mnemonic)
53
59
  dot account create my-validator
@@ -55,10 +61,28 @@ dot account create my-validator
55
61
  # Import from a BIP39 mnemonic
56
62
  dot account import treasury --secret "word1 word2 ... word12"
57
63
 
64
+ # Import an env-var-backed account (secret stays off disk)
65
+ dot account import ci-signer --env MY_SECRET
66
+
67
+ # Use it — the env var is read at signing time
68
+ MY_SECRET="word1 word2 ..." dot tx System.remark 0xdead --from ci-signer
69
+
58
70
  # Remove an account
59
71
  dot account remove my-validator
60
72
  ```
61
73
 
74
+ #### Env-var-backed accounts
75
+
76
+ For CI/CD and security-conscious workflows, store a reference to an environment variable instead of the secret itself:
77
+
78
+ ```bash
79
+ dot account import ci-signer --env MY_SECRET
80
+ ```
81
+
82
+ `--secret` and `--env` are mutually exclusive. `add` is an alias for `import`.
83
+
84
+ The secret is never written to disk. At signing time, the CLI reads `$MY_SECRET` and derives the keypair. If the variable is not set, the CLI errors with a clear message. `account list` shows an `(env: MY_SECRET)` badge and resolves the address live when the variable is available.
85
+
62
86
  **Supported secret formats for import:**
63
87
 
64
88
  | Format | Example | Status |
@@ -80,6 +104,8 @@ dot inspect kusama.System
80
104
  dot inspect kusama.System.Account
81
105
  ```
82
106
 
107
+ Chain names are case-insensitive — `Polkadot.System.Account`, `POLKADOT.System.Account`, and `polkadot.System.Account` all resolve the same way. The same applies to `--chain Polkadot` and `dot chain default Polkadot`.
108
+
83
109
  The `--chain` flag and default chain still work as before. If both a chain prefix and `--chain` flag are provided, the CLI errors.
84
110
 
85
111
  ### Query storage
@@ -298,13 +324,15 @@ After each command, the CLI checks whether a newer version is available on npm a
298
324
  ╰───────────────────────────────────────────────╯
299
325
  ```
300
326
 
301
- The version check runs in the background on startup and caches the result for 24 hours in `~/.polkadot/update-check.json`. It never blocks the CLI.
327
+ The version check runs in the background on startup and caches the result for 24 hours in `~/.polkadot/update-check.json`. Before exiting, the CLI waits up to 500ms for the check to finish so the cache file is written — even for fast commands like `--help` and `--version`. Long-running commands (queries, transactions) are unaffected since the check completes well before they finish.
328
+
329
+ If the network is unreachable, the failed check is cached for 1 hour so subsequent runs don't incur the 500ms wait repeatedly.
302
330
 
303
331
  The notification is automatically suppressed when:
304
332
 
305
333
  - `DOT_NO_UPDATE_CHECK=1` is set
306
334
  - `CI` environment variable is set (any value)
307
- - stdout is not a TTY (e.g. piped output)
335
+ - stderr is not a TTY (e.g. piped output)
308
336
 
309
337
  ## Configuration
310
338
 
package/dist/cli.mjs CHANGED
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  // src/cli.ts
6
6
  import cac from "cac";
7
7
  // package.json
8
- var version = "0.9.0";
8
+ var version = "0.11.0";
9
9
 
10
10
  // src/config/accounts-store.ts
11
11
  import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
@@ -20,11 +20,14 @@ import { join } from "node:path";
20
20
  var DEFAULT_CONFIG = {
21
21
  defaultChain: "polkadot",
22
22
  chains: {
23
- polkadot: {
24
- rpc: "wss://rpc.polkadot.io"
25
- }
23
+ polkadot: { rpc: "wss://rpc.polkadot.io" },
24
+ paseo: { rpc: "wss://rpc.ibp.network/paseo" },
25
+ "polkadot-asset-hub": { rpc: "wss://polkadot-asset-hub-rpc.polkadot.io" },
26
+ "paseo-asset-hub": { rpc: "wss://asset-hub-paseo-rpc.dwellir.com" },
27
+ "polkadot-people": { rpc: "wss://polkadot-people-rpc.polkadot.io" }
26
28
  }
27
29
  };
30
+ var BUILTIN_CHAIN_NAMES = new Set(Object.keys(DEFAULT_CONFIG.chains));
28
31
 
29
32
  // src/config/store.ts
30
33
  var DOT_DIR = join(homedir(), ".polkadot");
@@ -53,8 +56,11 @@ async function fileExists(path) {
53
56
  async function loadConfig() {
54
57
  await ensureDir(DOT_DIR);
55
58
  if (await fileExists(CONFIG_PATH)) {
56
- const data = await readFile(CONFIG_PATH, "utf-8");
57
- return JSON.parse(data);
59
+ const saved = JSON.parse(await readFile(CONFIG_PATH, "utf-8"));
60
+ return {
61
+ ...saved,
62
+ chains: { ...DEFAULT_CONFIG.chains, ...saved.chains }
63
+ };
58
64
  }
59
65
  await saveConfig(DEFAULT_CONFIG);
60
66
  return DEFAULT_CONFIG;
@@ -80,14 +86,19 @@ async function removeChainData(chainName) {
80
86
  const dir = getChainDir(chainName);
81
87
  await rm(dir, { recursive: true, force: true });
82
88
  }
89
+ function findChainName(config, input) {
90
+ if (config.chains[input])
91
+ return input;
92
+ return Object.keys(config.chains).find((k) => k.toLowerCase() === input.toLowerCase());
93
+ }
83
94
  function resolveChain(config, chainFlag) {
84
- const name = chainFlag ?? config.defaultChain;
85
- const chain = config.chains[name];
86
- if (!chain) {
95
+ const input = chainFlag ?? config.defaultChain;
96
+ const name = findChainName(config, input);
97
+ if (!name) {
87
98
  const available = Object.keys(config.chains).join(", ");
88
- throw new Error(`Unknown chain "${name}". Available chains: ${available}`);
99
+ throw new Error(`Unknown chain "${input}". Available chains: ${available}`);
89
100
  }
90
- return { name, chain };
101
+ return { name, chain: config.chains[name] };
91
102
  }
92
103
 
93
104
  // src/config/accounts-store.ts
@@ -120,6 +131,11 @@ function findAccount(file, name) {
120
131
  return file.accounts.find((a) => a.name.toLowerCase() === name.toLowerCase());
121
132
  }
122
133
 
134
+ // src/config/accounts-types.ts
135
+ function isEnvSecret(secret) {
136
+ return typeof secret === "object" && secret !== null && "env" in secret;
137
+ }
138
+
123
139
  // src/core/accounts.ts
124
140
  import { sr25519CreateDerive } from "@polkadot-labs/hdkd";
125
141
  import {
@@ -195,6 +211,27 @@ function toSs58(publicKey, prefix = 42) {
195
211
  }
196
212
  return ss58Address(publicKey, prefix);
197
213
  }
214
+ function resolveSecret(secret) {
215
+ if (isEnvSecret(secret)) {
216
+ const value = process.env[secret.env];
217
+ if (!value) {
218
+ throw new Error(`Environment variable "${secret.env}" is not set. Set it before signing.`);
219
+ }
220
+ return value;
221
+ }
222
+ return secret;
223
+ }
224
+ function tryDerivePublicKey(envVarName) {
225
+ const value = process.env[envVarName];
226
+ if (!value)
227
+ return null;
228
+ try {
229
+ const { publicKey } = importAccount(value);
230
+ return publicKeyToHex(publicKey);
231
+ } catch {
232
+ return null;
233
+ }
234
+ }
198
235
  async function resolveAccountSigner(name) {
199
236
  if (isDevAccount(name)) {
200
237
  const keypair2 = getDevKeypair(name);
@@ -206,8 +243,9 @@ async function resolveAccountSigner(name) {
206
243
  const available = [...DEV_NAMES, ...accountsFile.accounts.map((a) => a.name)];
207
244
  throw new Error(`Unknown account "${name}". Available accounts: ${available.join(", ")}`);
208
245
  }
209
- const isHexSeed = /^0x[0-9a-fA-F]{64}$/.test(account.secret);
210
- const keypair = isHexSeed ? deriveFromHexSeed(account.secret, account.derivationPath) : deriveFromMnemonic(account.secret, account.derivationPath);
246
+ const secret = resolveSecret(account.secret);
247
+ const isHexSeed = /^0x[0-9a-fA-F]{64}$/.test(secret);
248
+ const keypair = isHexSeed ? deriveFromHexSeed(secret, account.derivationPath) : deriveFromMnemonic(secret, account.derivationPath);
211
249
  return getPolkadotSigner(keypair.publicKey, "Sr25519", keypair.sign);
212
250
  }
213
251
 
@@ -307,32 +345,39 @@ class Spinner {
307
345
  // src/commands/account.ts
308
346
  var ACCOUNT_HELP = `
309
347
  ${BOLD}Usage:${RESET}
310
- $ dot account create <name> Create a new account
311
- $ dot account import <name> --secret <s> Import from BIP39 mnemonic
312
- $ dot account list List all accounts
313
- $ dot account remove <name> Remove a stored account
348
+ $ dot account create|new <name> Create a new account
349
+ $ dot account import|add <name> --secret <s> Import from BIP39 mnemonic
350
+ $ dot account import|add <name> --env <VAR> Import account backed by env variable
351
+ $ dot account list List all accounts
352
+ $ dot account remove|delete <name> Remove a stored account
314
353
 
315
354
  ${BOLD}Examples:${RESET}
316
355
  $ dot account create my-validator
317
356
  $ dot account import treasury --secret "word1 word2 ... word12"
357
+ $ dot account import ci-signer --env MY_SECRET
318
358
  $ dot account list
319
359
  $ dot account remove my-validator
320
360
 
321
361
  ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
362
+ Use --env to keep secrets off disk entirely.
322
363
  Hex seed import (0x...) is not supported via CLI.${RESET}
323
364
  `.trimStart();
324
365
  function registerAccountCommands(cli) {
325
- cli.command("account [action] [name]", "Manage local accounts (create, import, list, remove)").alias("accounts").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").action(async (action, name, opts) => {
366
+ cli.command("account [action] [name]", "Manage local accounts (create, import, list, remove)").alias("accounts").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").option("--env <varName>", "Environment variable name holding the secret").action(async (action, name, opts) => {
326
367
  if (!action) {
327
- return accountList();
368
+ console.log(ACCOUNT_HELP);
369
+ return;
328
370
  }
329
371
  switch (action) {
372
+ case "new":
330
373
  case "create":
331
374
  return accountCreate(name);
332
375
  case "import":
376
+ case "add":
333
377
  return accountImport(name, opts);
334
378
  case "list":
335
379
  return accountList();
380
+ case "delete":
336
381
  case "remove":
337
382
  return accountRemove(name);
338
383
  default:
@@ -382,10 +427,16 @@ async function accountImport(name, opts) {
382
427
  console.error('Usage: dot account import <name> --secret "mnemonic or hex seed"');
383
428
  process.exit(1);
384
429
  }
385
- if (!opts.secret) {
386
- console.error(`--secret is required.
430
+ if (opts.secret && opts.env) {
431
+ console.error(`Use --secret or --env, not both.
432
+ `);
433
+ process.exit(1);
434
+ }
435
+ if (!opts.secret && !opts.env) {
436
+ console.error(`--secret or --env is required.
387
437
  `);
388
438
  console.error('Usage: dot account import <name> --secret "mnemonic or hex seed"');
439
+ console.error(" dot account import <name> --env <VAR>");
389
440
  process.exit(1);
390
441
  }
391
442
  if (isDevAccount(name)) {
@@ -395,20 +446,40 @@ async function accountImport(name, opts) {
395
446
  if (findAccount(accountsFile, name)) {
396
447
  throw new Error(`Account "${name}" already exists.`);
397
448
  }
398
- const { publicKey } = importAccount(opts.secret);
399
- const hexPub = publicKeyToHex(publicKey);
400
- const address = toSs58(publicKey);
401
- accountsFile.accounts.push({
402
- name,
403
- secret: opts.secret,
404
- publicKey: hexPub,
405
- derivationPath: ""
406
- });
407
- await saveAccounts(accountsFile);
408
- printHeading("Account Imported");
409
- console.log(` ${BOLD}Name:${RESET} ${name}`);
410
- console.log(` ${BOLD}Address:${RESET} ${address}`);
411
- console.log();
449
+ if (opts.env) {
450
+ const publicKey = tryDerivePublicKey(opts.env) ?? "";
451
+ accountsFile.accounts.push({
452
+ name,
453
+ secret: { env: opts.env },
454
+ publicKey,
455
+ derivationPath: ""
456
+ });
457
+ await saveAccounts(accountsFile);
458
+ printHeading("Account Imported");
459
+ console.log(` ${BOLD}Name:${RESET} ${name}`);
460
+ console.log(` ${BOLD}Env:${RESET} ${opts.env}`);
461
+ if (publicKey) {
462
+ console.log(` ${BOLD}Address:${RESET} ${toSs58(publicKey)}`);
463
+ } else {
464
+ console.log(` ${YELLOW}Address will resolve when $${opts.env} is set.${RESET}`);
465
+ }
466
+ console.log();
467
+ } else {
468
+ const { publicKey } = importAccount(opts.secret);
469
+ const hexPub = publicKeyToHex(publicKey);
470
+ const address = toSs58(publicKey);
471
+ accountsFile.accounts.push({
472
+ name,
473
+ secret: opts.secret,
474
+ publicKey: hexPub,
475
+ derivationPath: ""
476
+ });
477
+ await saveAccounts(accountsFile);
478
+ printHeading("Account Imported");
479
+ console.log(` ${BOLD}Name:${RESET} ${name}`);
480
+ console.log(` ${BOLD}Address:${RESET} ${address}`);
481
+ console.log();
482
+ }
412
483
  }
413
484
  async function accountList() {
414
485
  printHeading("Dev Accounts");
@@ -421,8 +492,19 @@ async function accountList() {
421
492
  if (accountsFile.accounts.length > 0) {
422
493
  printHeading("Stored Accounts");
423
494
  for (const account of accountsFile.accounts) {
424
- const address = toSs58(account.publicKey);
425
- printItem(account.name, address);
495
+ let displayName = account.name;
496
+ let address;
497
+ if (isEnvSecret(account.secret)) {
498
+ displayName += ` (env: ${account.secret.env})`;
499
+ let pubKey = account.publicKey;
500
+ if (!pubKey) {
501
+ pubKey = tryDerivePublicKey(account.secret.env) ?? "";
502
+ }
503
+ address = pubKey ? toSs58(pubKey) : "n/a";
504
+ } else {
505
+ address = toSs58(account.publicKey);
506
+ }
507
+ printItem(displayName, address);
426
508
  }
427
509
  } else {
428
510
  printHeading("Stored Accounts");
@@ -479,10 +561,13 @@ class MetadataError extends CliError {
479
561
 
480
562
  // src/core/client.ts
481
563
  var KNOWN_CHAIN_SPECS = {
482
- polkadot: "polkadot-api/chains/polkadot",
483
- kusama: "polkadot-api/chains/ksmcc3",
484
- westend: "polkadot-api/chains/westend2",
485
- paseo: "polkadot-api/chains/paseo"
564
+ polkadot: { spec: "polkadot-api/chains/polkadot" },
565
+ kusama: { spec: "polkadot-api/chains/ksmcc3" },
566
+ westend: { spec: "polkadot-api/chains/westend2" },
567
+ paseo: { spec: "polkadot-api/chains/paseo" },
568
+ "polkadot-asset-hub": { spec: "polkadot-api/chains/polkadot_asset_hub", relay: "polkadot" },
569
+ "polkadot-people": { spec: "polkadot-api/chains/polkadot_people", relay: "polkadot" },
570
+ "paseo-asset-hub": { spec: "polkadot-api/chains/paseo_asset_hub", relay: "paseo" }
486
571
  };
487
572
  function suppressWsNoise() {
488
573
  const orig = console.error;
@@ -526,12 +611,22 @@ async function createChainClient(chainName, chainConfig, rpcOverride) {
526
611
  async function createSmoldotProvider(chainName) {
527
612
  const { start } = await import("polkadot-api/smoldot");
528
613
  const { getSmProvider } = await import("polkadot-api/sm-provider");
529
- const specPath = KNOWN_CHAIN_SPECS[chainName];
530
- if (!specPath) {
614
+ const entry = KNOWN_CHAIN_SPECS[chainName];
615
+ if (!entry) {
531
616
  throw new ConnectionError(`Light client is only supported for known chains: ${Object.keys(KNOWN_CHAIN_SPECS).join(", ")}. Use --rpc to connect to "${chainName}" instead.`);
532
617
  }
533
- const { chainSpec } = await import(specPath);
618
+ const { chainSpec } = await import(entry.spec);
534
619
  const smoldot = start();
620
+ if (entry.relay) {
621
+ const relayEntry = KNOWN_CHAIN_SPECS[entry.relay];
622
+ if (!relayEntry) {
623
+ throw new ConnectionError(`Relay chain "${entry.relay}" not found in known chain specs.`);
624
+ }
625
+ const { chainSpec: relaySpec } = await import(relayEntry.spec);
626
+ const relayChain = await smoldot.addChain({ chainSpec: relaySpec, disableJsonRpc: true });
627
+ const chain2 = await smoldot.addChain({ chainSpec, potentialRelayChains: [relayChain] });
628
+ return getSmProvider(chain2);
629
+ }
535
630
  const chain = await smoldot.addChain({ chainSpec });
536
631
  return getSmProvider(chain);
537
632
  }
@@ -703,7 +798,8 @@ ${BOLD}Examples:${RESET}
703
798
  function registerChainCommands(cli) {
704
799
  cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").alias("chains").action(async (action, name, opts) => {
705
800
  if (!action) {
706
- return chainList();
801
+ console.log(CHAIN_HELP);
802
+ return;
707
803
  }
708
804
  switch (action) {
709
805
  case "add":
@@ -762,20 +858,21 @@ async function chainRemove(name) {
762
858
  process.exit(1);
763
859
  }
764
860
  const config = await loadConfig();
765
- if (!config.chains[name]) {
861
+ const resolved = findChainName(config, name);
862
+ if (!resolved) {
766
863
  throw new Error(`Chain "${name}" not found.`);
767
864
  }
768
- if (name === "polkadot") {
769
- throw new Error('Cannot remove the built-in "polkadot" chain.');
865
+ if (BUILTIN_CHAIN_NAMES.has(resolved)) {
866
+ throw new Error(`Cannot remove the built-in "${resolved}" chain.`);
770
867
  }
771
- delete config.chains[name];
772
- if (config.defaultChain === name) {
868
+ delete config.chains[resolved];
869
+ if (config.defaultChain === resolved) {
773
870
  config.defaultChain = "polkadot";
774
871
  console.log(`Default chain reset to "polkadot".`);
775
872
  }
776
873
  await saveConfig(config);
777
- await removeChainData(name);
778
- console.log(`Chain "${name}" removed.`);
874
+ await removeChainData(resolved);
875
+ console.log(`Chain "${resolved}" removed.`);
779
876
  }
780
877
  async function chainList() {
781
878
  const config = await loadConfig();
@@ -807,13 +904,14 @@ async function chainDefault(name) {
807
904
  process.exit(1);
808
905
  }
809
906
  const config = await loadConfig();
810
- if (!config.chains[name]) {
907
+ const resolved = findChainName(config, name);
908
+ if (!resolved) {
811
909
  const available = Object.keys(config.chains).join(", ");
812
910
  throw new Error(`Chain "${name}" not found. Available: ${available}`);
813
911
  }
814
- config.defaultChain = name;
912
+ config.defaultChain = resolved;
815
913
  await saveConfig(config);
816
- console.log(`Default chain set to "${name}".`);
914
+ console.log(`Default chain set to "${resolved}".`);
817
915
  }
818
916
 
819
917
  // src/utils/fuzzy-match.ts
@@ -2258,7 +2356,10 @@ import { join as join3 } from "node:path";
2258
2356
  var CACHE_FILE = "update-check.json";
2259
2357
  var STALE_MS = 24 * 60 * 60 * 1000;
2260
2358
  var FETCH_TIMEOUT_MS = 5000;
2359
+ var EXIT_WAIT_TIMEOUT_MS = 500;
2360
+ var RETRY_AFTER_FAILURE_MS = 60 * 60 * 1000;
2261
2361
  var REGISTRY_URL = "https://registry.npmjs.org/polkadot-cli/latest";
2362
+ var pendingCheck = null;
2262
2363
  function parseSemver(v) {
2263
2364
  const clean = v.replace(/^v/, "").split("-")[0] ?? v;
2264
2365
  const parts = clean.split(".").map(Number);
@@ -2324,20 +2425,32 @@ async function writeCache(cache) {
2324
2425
  `);
2325
2426
  } catch {}
2326
2427
  }
2327
- function startBackgroundCheck(_currentVersion) {
2428
+ function startBackgroundCheck(currentVersion) {
2328
2429
  const cache = readCache();
2329
2430
  const now = Date.now();
2330
2431
  if (cache && now - cache.lastCheck < STALE_MS) {
2331
2432
  return;
2332
2433
  }
2333
- fetch(REGISTRY_URL, {
2434
+ pendingCheck = fetch(REGISTRY_URL, {
2334
2435
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
2335
2436
  }).then((res) => res.json()).then((data) => {
2336
2437
  const latestVersion = data.version;
2337
2438
  if (typeof latestVersion === "string") {
2338
- writeCache({ lastCheck: now, latestVersion });
2439
+ return writeCache({ lastCheck: now, latestVersion });
2339
2440
  }
2340
- }).catch(() => {});
2441
+ }).catch(() => {
2442
+ return writeCache({
2443
+ lastCheck: now - STALE_MS + RETRY_AFTER_FAILURE_MS,
2444
+ latestVersion: currentVersion
2445
+ });
2446
+ });
2447
+ }
2448
+ async function waitForPendingCheck() {
2449
+ if (!pendingCheck)
2450
+ return;
2451
+ const timeout = new Promise((resolve) => setTimeout(resolve, EXIT_WAIT_TIMEOUT_MS));
2452
+ await Promise.race([pendingCheck.catch(() => {}), timeout]);
2453
+ pendingCheck = null;
2341
2454
  }
2342
2455
  function getUpdateNotification(currentVersion) {
2343
2456
  if (process.env.DOT_NO_UPDATE_CHECK === "1")
@@ -2381,14 +2494,15 @@ registerTxCommand(cli);
2381
2494
  registerHashCommand(cli);
2382
2495
  cli.help();
2383
2496
  cli.version(version);
2384
- function showUpdateAndExit(code) {
2497
+ async function showUpdateAndExit(code) {
2498
+ await waitForPendingCheck();
2385
2499
  const note = getUpdateNotification(version);
2386
2500
  if (note)
2387
2501
  process.stderr.write(`${note}
2388
2502
  `);
2389
2503
  process.exit(code);
2390
2504
  }
2391
- function handleError(err) {
2505
+ async function handleError(err) {
2392
2506
  if (err instanceof CliError2) {
2393
2507
  console.error(`Error: ${err.message}`);
2394
2508
  } else if (err instanceof Error) {
@@ -2396,21 +2510,24 @@ function handleError(err) {
2396
2510
  } else {
2397
2511
  console.error("An unexpected error occurred:", err);
2398
2512
  }
2399
- showUpdateAndExit(1);
2513
+ return showUpdateAndExit(1);
2400
2514
  }
2401
- try {
2402
- cli.parse(process.argv, { run: false });
2403
- if (cli.options.version || cli.options.help) {
2404
- showUpdateAndExit(0);
2405
- } else if (!cli.matchedCommandName) {
2406
- cli.outputHelp();
2407
- showUpdateAndExit(0);
2408
- } else {
2409
- const result = cli.runMatchedCommand();
2410
- if (result && typeof result.then === "function") {
2411
- result.then(() => showUpdateAndExit(0), handleError);
2515
+ async function main() {
2516
+ try {
2517
+ cli.parse(process.argv, { run: false });
2518
+ if (cli.options.version || cli.options.help) {
2519
+ await showUpdateAndExit(0);
2520
+ } else if (!cli.matchedCommandName) {
2521
+ cli.outputHelp();
2522
+ await showUpdateAndExit(0);
2523
+ } else {
2524
+ const result = cli.runMatchedCommand();
2525
+ if (result && typeof result.then === "function") {
2526
+ await result.then(() => showUpdateAndExit(0), handleError);
2527
+ }
2412
2528
  }
2529
+ } catch (err) {
2530
+ await handleError(err);
2413
2531
  }
2414
- } catch (err) {
2415
- handleError(err);
2416
2532
  }
2533
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polkadot-cli",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "CLI tool for querying Polkadot-ecosystem on-chain state",
5
5
  "type": "module",
6
6
  "bin": {