polkadot-cli 0.10.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.
- package/README.md +21 -9
- package/dist/cli.mjs +145 -109
- 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
|
|
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
|
|
@@ -45,9 +48,12 @@ Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for t
|
|
|
45
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
|
|
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,8 +61,8 @@ dot account create my-validator
|
|
|
55
61
|
# Import from a BIP39 mnemonic
|
|
56
62
|
dot account import treasury --secret "word1 word2 ... word12"
|
|
57
63
|
|
|
58
|
-
#
|
|
59
|
-
dot account
|
|
64
|
+
# Import an env-var-backed account (secret stays off disk)
|
|
65
|
+
dot account import ci-signer --env MY_SECRET
|
|
60
66
|
|
|
61
67
|
# Use it — the env var is read at signing time
|
|
62
68
|
MY_SECRET="word1 word2 ..." dot tx System.remark 0xdead --from ci-signer
|
|
@@ -70,9 +76,11 @@ dot account remove my-validator
|
|
|
70
76
|
For CI/CD and security-conscious workflows, store a reference to an environment variable instead of the secret itself:
|
|
71
77
|
|
|
72
78
|
```bash
|
|
73
|
-
dot account
|
|
79
|
+
dot account import ci-signer --env MY_SECRET
|
|
74
80
|
```
|
|
75
81
|
|
|
82
|
+
`--secret` and `--env` are mutually exclusive. `add` is an alias for `import`.
|
|
83
|
+
|
|
76
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.
|
|
77
85
|
|
|
78
86
|
**Supported secret formats for import:**
|
|
@@ -96,6 +104,8 @@ dot inspect kusama.System
|
|
|
96
104
|
dot inspect kusama.System.Account
|
|
97
105
|
```
|
|
98
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
|
+
|
|
99
109
|
The `--chain` flag and default chain still work as before. If both a chain prefix and `--chain` flag are provided, the CLI errors.
|
|
100
110
|
|
|
101
111
|
### Query storage
|
|
@@ -314,13 +324,15 @@ After each command, the CLI checks whether a newer version is available on npm a
|
|
|
314
324
|
╰───────────────────────────────────────────────╯
|
|
315
325
|
```
|
|
316
326
|
|
|
317
|
-
The version check runs in the background on startup and caches the result for 24 hours in `~/.polkadot/update-check.json`.
|
|
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.
|
|
318
330
|
|
|
319
331
|
The notification is automatically suppressed when:
|
|
320
332
|
|
|
321
333
|
- `DOT_NO_UPDATE_CHECK=1` is set
|
|
322
334
|
- `CI` environment variable is set (any value)
|
|
323
|
-
-
|
|
335
|
+
- stderr is not a TTY (e.g. piped output)
|
|
324
336
|
|
|
325
337
|
## Configuration
|
|
326
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.
|
|
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
|
-
|
|
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
|
|
57
|
-
return
|
|
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
|
|
85
|
-
const
|
|
86
|
-
if (!
|
|
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 "${
|
|
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
|
|
@@ -334,16 +345,16 @@ class Spinner {
|
|
|
334
345
|
// src/commands/account.ts
|
|
335
346
|
var ACCOUNT_HELP = `
|
|
336
347
|
${BOLD}Usage:${RESET}
|
|
337
|
-
$ dot account create <name>
|
|
338
|
-
$ dot account import <name> --secret <s>
|
|
339
|
-
$ dot account add <name> --env <VAR>
|
|
340
|
-
$ dot account list
|
|
341
|
-
$ dot account remove <name>
|
|
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
|
|
342
353
|
|
|
343
354
|
${BOLD}Examples:${RESET}
|
|
344
355
|
$ dot account create my-validator
|
|
345
356
|
$ dot account import treasury --secret "word1 word2 ... word12"
|
|
346
|
-
$ dot account
|
|
357
|
+
$ dot account import ci-signer --env MY_SECRET
|
|
347
358
|
$ dot account list
|
|
348
359
|
$ dot account remove my-validator
|
|
349
360
|
|
|
@@ -352,19 +363,21 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
|
|
|
352
363
|
Hex seed import (0x...) is not supported via CLI.${RESET}
|
|
353
364
|
`.trimStart();
|
|
354
365
|
function registerAccountCommands(cli) {
|
|
355
|
-
cli.command("account [action] [name]", "Manage local accounts (create, import,
|
|
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) => {
|
|
356
367
|
if (!action) {
|
|
357
|
-
|
|
368
|
+
console.log(ACCOUNT_HELP);
|
|
369
|
+
return;
|
|
358
370
|
}
|
|
359
371
|
switch (action) {
|
|
372
|
+
case "new":
|
|
360
373
|
case "create":
|
|
361
374
|
return accountCreate(name);
|
|
362
375
|
case "import":
|
|
363
|
-
return accountImport(name, opts);
|
|
364
376
|
case "add":
|
|
365
|
-
return
|
|
377
|
+
return accountImport(name, opts);
|
|
366
378
|
case "list":
|
|
367
379
|
return accountList();
|
|
380
|
+
case "delete":
|
|
368
381
|
case "remove":
|
|
369
382
|
return accountRemove(name);
|
|
370
383
|
default:
|
|
@@ -414,45 +427,16 @@ async function accountImport(name, opts) {
|
|
|
414
427
|
console.error('Usage: dot account import <name> --secret "mnemonic or hex seed"');
|
|
415
428
|
process.exit(1);
|
|
416
429
|
}
|
|
417
|
-
if (
|
|
418
|
-
console.error(
|
|
430
|
+
if (opts.secret && opts.env) {
|
|
431
|
+
console.error(`Use --secret or --env, not both.
|
|
419
432
|
`);
|
|
420
|
-
console.error('Usage: dot account import <name> --secret "mnemonic or hex seed"');
|
|
421
433
|
process.exit(1);
|
|
422
434
|
}
|
|
423
|
-
if (
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
const accountsFile = await loadAccounts();
|
|
427
|
-
if (findAccount(accountsFile, name)) {
|
|
428
|
-
throw new Error(`Account "${name}" already exists.`);
|
|
429
|
-
}
|
|
430
|
-
const { publicKey } = importAccount(opts.secret);
|
|
431
|
-
const hexPub = publicKeyToHex(publicKey);
|
|
432
|
-
const address = toSs58(publicKey);
|
|
433
|
-
accountsFile.accounts.push({
|
|
434
|
-
name,
|
|
435
|
-
secret: opts.secret,
|
|
436
|
-
publicKey: hexPub,
|
|
437
|
-
derivationPath: ""
|
|
438
|
-
});
|
|
439
|
-
await saveAccounts(accountsFile);
|
|
440
|
-
printHeading("Account Imported");
|
|
441
|
-
console.log(` ${BOLD}Name:${RESET} ${name}`);
|
|
442
|
-
console.log(` ${BOLD}Address:${RESET} ${address}`);
|
|
443
|
-
console.log();
|
|
444
|
-
}
|
|
445
|
-
async function accountAdd(name, opts) {
|
|
446
|
-
if (!name) {
|
|
447
|
-
console.error(`Account name is required.
|
|
435
|
+
if (!opts.secret && !opts.env) {
|
|
436
|
+
console.error(`--secret or --env is required.
|
|
448
437
|
`);
|
|
449
|
-
console.error(
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
if (!opts.env) {
|
|
453
|
-
console.error(`--env is required.
|
|
454
|
-
`);
|
|
455
|
-
console.error("Usage: dot account add <name> --env <VAR>");
|
|
438
|
+
console.error('Usage: dot account import <name> --secret "mnemonic or hex seed"');
|
|
439
|
+
console.error(" dot account import <name> --env <VAR>");
|
|
456
440
|
process.exit(1);
|
|
457
441
|
}
|
|
458
442
|
if (isDevAccount(name)) {
|
|
@@ -462,23 +446,40 @@ async function accountAdd(name, opts) {
|
|
|
462
446
|
if (findAccount(accountsFile, name)) {
|
|
463
447
|
throw new Error(`Account "${name}" already exists.`);
|
|
464
448
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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();
|
|
478
467
|
} else {
|
|
479
|
-
|
|
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();
|
|
480
482
|
}
|
|
481
|
-
console.log();
|
|
482
483
|
}
|
|
483
484
|
async function accountList() {
|
|
484
485
|
printHeading("Dev Accounts");
|
|
@@ -560,10 +561,13 @@ class MetadataError extends CliError {
|
|
|
560
561
|
|
|
561
562
|
// src/core/client.ts
|
|
562
563
|
var KNOWN_CHAIN_SPECS = {
|
|
563
|
-
polkadot: "polkadot-api/chains/polkadot",
|
|
564
|
-
kusama: "polkadot-api/chains/ksmcc3",
|
|
565
|
-
westend: "polkadot-api/chains/westend2",
|
|
566
|
-
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" }
|
|
567
571
|
};
|
|
568
572
|
function suppressWsNoise() {
|
|
569
573
|
const orig = console.error;
|
|
@@ -607,12 +611,22 @@ async function createChainClient(chainName, chainConfig, rpcOverride) {
|
|
|
607
611
|
async function createSmoldotProvider(chainName) {
|
|
608
612
|
const { start } = await import("polkadot-api/smoldot");
|
|
609
613
|
const { getSmProvider } = await import("polkadot-api/sm-provider");
|
|
610
|
-
const
|
|
611
|
-
if (!
|
|
614
|
+
const entry = KNOWN_CHAIN_SPECS[chainName];
|
|
615
|
+
if (!entry) {
|
|
612
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.`);
|
|
613
617
|
}
|
|
614
|
-
const { chainSpec } = await import(
|
|
618
|
+
const { chainSpec } = await import(entry.spec);
|
|
615
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
|
+
}
|
|
616
630
|
const chain = await smoldot.addChain({ chainSpec });
|
|
617
631
|
return getSmProvider(chain);
|
|
618
632
|
}
|
|
@@ -784,7 +798,8 @@ ${BOLD}Examples:${RESET}
|
|
|
784
798
|
function registerChainCommands(cli) {
|
|
785
799
|
cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").alias("chains").action(async (action, name, opts) => {
|
|
786
800
|
if (!action) {
|
|
787
|
-
|
|
801
|
+
console.log(CHAIN_HELP);
|
|
802
|
+
return;
|
|
788
803
|
}
|
|
789
804
|
switch (action) {
|
|
790
805
|
case "add":
|
|
@@ -843,20 +858,21 @@ async function chainRemove(name) {
|
|
|
843
858
|
process.exit(1);
|
|
844
859
|
}
|
|
845
860
|
const config = await loadConfig();
|
|
846
|
-
|
|
861
|
+
const resolved = findChainName(config, name);
|
|
862
|
+
if (!resolved) {
|
|
847
863
|
throw new Error(`Chain "${name}" not found.`);
|
|
848
864
|
}
|
|
849
|
-
if (
|
|
850
|
-
throw new Error(
|
|
865
|
+
if (BUILTIN_CHAIN_NAMES.has(resolved)) {
|
|
866
|
+
throw new Error(`Cannot remove the built-in "${resolved}" chain.`);
|
|
851
867
|
}
|
|
852
|
-
delete config.chains[
|
|
853
|
-
if (config.defaultChain ===
|
|
868
|
+
delete config.chains[resolved];
|
|
869
|
+
if (config.defaultChain === resolved) {
|
|
854
870
|
config.defaultChain = "polkadot";
|
|
855
871
|
console.log(`Default chain reset to "polkadot".`);
|
|
856
872
|
}
|
|
857
873
|
await saveConfig(config);
|
|
858
|
-
await removeChainData(
|
|
859
|
-
console.log(`Chain "${
|
|
874
|
+
await removeChainData(resolved);
|
|
875
|
+
console.log(`Chain "${resolved}" removed.`);
|
|
860
876
|
}
|
|
861
877
|
async function chainList() {
|
|
862
878
|
const config = await loadConfig();
|
|
@@ -888,13 +904,14 @@ async function chainDefault(name) {
|
|
|
888
904
|
process.exit(1);
|
|
889
905
|
}
|
|
890
906
|
const config = await loadConfig();
|
|
891
|
-
|
|
907
|
+
const resolved = findChainName(config, name);
|
|
908
|
+
if (!resolved) {
|
|
892
909
|
const available = Object.keys(config.chains).join(", ");
|
|
893
910
|
throw new Error(`Chain "${name}" not found. Available: ${available}`);
|
|
894
911
|
}
|
|
895
|
-
config.defaultChain =
|
|
912
|
+
config.defaultChain = resolved;
|
|
896
913
|
await saveConfig(config);
|
|
897
|
-
console.log(`Default chain set to "${
|
|
914
|
+
console.log(`Default chain set to "${resolved}".`);
|
|
898
915
|
}
|
|
899
916
|
|
|
900
917
|
// src/utils/fuzzy-match.ts
|
|
@@ -2339,7 +2356,10 @@ import { join as join3 } from "node:path";
|
|
|
2339
2356
|
var CACHE_FILE = "update-check.json";
|
|
2340
2357
|
var STALE_MS = 24 * 60 * 60 * 1000;
|
|
2341
2358
|
var FETCH_TIMEOUT_MS = 5000;
|
|
2359
|
+
var EXIT_WAIT_TIMEOUT_MS = 500;
|
|
2360
|
+
var RETRY_AFTER_FAILURE_MS = 60 * 60 * 1000;
|
|
2342
2361
|
var REGISTRY_URL = "https://registry.npmjs.org/polkadot-cli/latest";
|
|
2362
|
+
var pendingCheck = null;
|
|
2343
2363
|
function parseSemver(v) {
|
|
2344
2364
|
const clean = v.replace(/^v/, "").split("-")[0] ?? v;
|
|
2345
2365
|
const parts = clean.split(".").map(Number);
|
|
@@ -2405,20 +2425,32 @@ async function writeCache(cache) {
|
|
|
2405
2425
|
`);
|
|
2406
2426
|
} catch {}
|
|
2407
2427
|
}
|
|
2408
|
-
function startBackgroundCheck(
|
|
2428
|
+
function startBackgroundCheck(currentVersion) {
|
|
2409
2429
|
const cache = readCache();
|
|
2410
2430
|
const now = Date.now();
|
|
2411
2431
|
if (cache && now - cache.lastCheck < STALE_MS) {
|
|
2412
2432
|
return;
|
|
2413
2433
|
}
|
|
2414
|
-
fetch(REGISTRY_URL, {
|
|
2434
|
+
pendingCheck = fetch(REGISTRY_URL, {
|
|
2415
2435
|
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
2416
2436
|
}).then((res) => res.json()).then((data) => {
|
|
2417
2437
|
const latestVersion = data.version;
|
|
2418
2438
|
if (typeof latestVersion === "string") {
|
|
2419
|
-
writeCache({ lastCheck: now, latestVersion });
|
|
2439
|
+
return writeCache({ lastCheck: now, latestVersion });
|
|
2420
2440
|
}
|
|
2421
|
-
}).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;
|
|
2422
2454
|
}
|
|
2423
2455
|
function getUpdateNotification(currentVersion) {
|
|
2424
2456
|
if (process.env.DOT_NO_UPDATE_CHECK === "1")
|
|
@@ -2462,14 +2494,15 @@ registerTxCommand(cli);
|
|
|
2462
2494
|
registerHashCommand(cli);
|
|
2463
2495
|
cli.help();
|
|
2464
2496
|
cli.version(version);
|
|
2465
|
-
function showUpdateAndExit(code) {
|
|
2497
|
+
async function showUpdateAndExit(code) {
|
|
2498
|
+
await waitForPendingCheck();
|
|
2466
2499
|
const note = getUpdateNotification(version);
|
|
2467
2500
|
if (note)
|
|
2468
2501
|
process.stderr.write(`${note}
|
|
2469
2502
|
`);
|
|
2470
2503
|
process.exit(code);
|
|
2471
2504
|
}
|
|
2472
|
-
function handleError(err) {
|
|
2505
|
+
async function handleError(err) {
|
|
2473
2506
|
if (err instanceof CliError2) {
|
|
2474
2507
|
console.error(`Error: ${err.message}`);
|
|
2475
2508
|
} else if (err instanceof Error) {
|
|
@@ -2477,21 +2510,24 @@ function handleError(err) {
|
|
|
2477
2510
|
} else {
|
|
2478
2511
|
console.error("An unexpected error occurred:", err);
|
|
2479
2512
|
}
|
|
2480
|
-
showUpdateAndExit(1);
|
|
2513
|
+
return showUpdateAndExit(1);
|
|
2481
2514
|
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
cli.
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
result.then
|
|
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
|
+
}
|
|
2493
2528
|
}
|
|
2529
|
+
} catch (err) {
|
|
2530
|
+
await handleError(err);
|
|
2494
2531
|
}
|
|
2495
|
-
} catch (err) {
|
|
2496
|
-
handleError(err);
|
|
2497
2532
|
}
|
|
2533
|
+
main();
|