polkadot-cli 0.6.1 → 0.7.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 +37 -3
- package/dist/cli.mjs +478 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,8 @@ dot chain add kusama --rpc wss://kusama-rpc.polkadot.io
|
|
|
22
22
|
dot chain add westend --light-client
|
|
23
23
|
|
|
24
24
|
# List configured chains
|
|
25
|
-
dot
|
|
25
|
+
dot chains # shorthand
|
|
26
|
+
dot chain list # equivalent
|
|
26
27
|
|
|
27
28
|
# Re-fetch metadata after a runtime upgrade
|
|
28
29
|
dot chain update # updates default chain
|
|
@@ -43,7 +44,8 @@ Dev accounts (Alice, Bob, Charlie, Dave, Eve, Ferdie) are always available for t
|
|
|
43
44
|
|
|
44
45
|
```bash
|
|
45
46
|
# List all accounts (dev + stored)
|
|
46
|
-
dot
|
|
47
|
+
dot accounts # shorthand
|
|
48
|
+
dot account list # equivalent
|
|
47
49
|
|
|
48
50
|
# Create a new account (generates a mnemonic)
|
|
49
51
|
dot account create my-validator
|
|
@@ -144,10 +146,20 @@ Both dry-run and submission display the encoded call hex and a decoded human-rea
|
|
|
144
146
|
Call: 0x0001076465616462656566
|
|
145
147
|
Decode: System.remark(remark: 0xdeadbeef)
|
|
146
148
|
Tx: 0xabc123...
|
|
147
|
-
Block: #12345678 (0xdef...)
|
|
148
149
|
Status: ok
|
|
149
150
|
```
|
|
150
151
|
|
|
152
|
+
#### Exit codes
|
|
153
|
+
|
|
154
|
+
The CLI exits with code **1** when a finalized transaction has a dispatch error (e.g. insufficient balance, bad origin). The full transaction output (events, explorer links) is still printed before the error so you can debug the failure. Module errors are formatted as `PalletName.ErrorVariant` (e.g. `Balances.InsufficientBalance`).
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
dot tx Balances.transferKeepAlive 5FHneW46... 999999999999999999 --from alice
|
|
158
|
+
# ... events and explorer links ...
|
|
159
|
+
# Error: Transaction dispatch error: Balances.InsufficientBalance
|
|
160
|
+
echo $? # 1
|
|
161
|
+
```
|
|
162
|
+
|
|
151
163
|
#### Custom signed extensions
|
|
152
164
|
|
|
153
165
|
Chains with non-standard signed extensions (e.g. `people-preview`) are auto-handled:
|
|
@@ -210,6 +222,27 @@ polkadot-cli aims to be the single tool for day-to-day chain interaction: storag
|
|
|
210
222
|
|
|
211
223
|
Outside Polkadot, the closest comparable in terms of interactive UX is [near-cli-rs](https://github.com/near/near-cli-rs) (NEAR).
|
|
212
224
|
|
|
225
|
+
## Update notifications
|
|
226
|
+
|
|
227
|
+
After each command, the CLI checks whether a newer version is available on npm and displays a notification:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
╭───────────────────────────────────────────────╮
|
|
231
|
+
│ │
|
|
232
|
+
│ Update available! 0.6.2 → 0.7.0 │
|
|
233
|
+
│ Run npm i -g polkadot-cli to update │
|
|
234
|
+
│ │
|
|
235
|
+
╰───────────────────────────────────────────────╯
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
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.
|
|
239
|
+
|
|
240
|
+
The notification is automatically suppressed when:
|
|
241
|
+
|
|
242
|
+
- `DOT_NO_UPDATE_CHECK=1` is set
|
|
243
|
+
- `CI` environment variable is set (any value)
|
|
244
|
+
- stdout is not a TTY (e.g. piped output)
|
|
245
|
+
|
|
213
246
|
## Configuration
|
|
214
247
|
|
|
215
248
|
Config and metadata caches live in `~/.polkadot/`:
|
|
@@ -218,6 +251,7 @@ Config and metadata caches live in `~/.polkadot/`:
|
|
|
218
251
|
~/.polkadot/
|
|
219
252
|
├── config.json # chains and default chain
|
|
220
253
|
├── accounts.json # stored accounts (⚠️ secrets are NOT encrypted — see below)
|
|
254
|
+
├── update-check.json # cached update check result
|
|
221
255
|
└── chains/
|
|
222
256
|
└── polkadot/
|
|
223
257
|
└── metadata.bin # cached SCALE-encoded metadata
|
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.7.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";
|
|
@@ -216,6 +216,7 @@ var isTTY = process.stdout.isTTY ?? false;
|
|
|
216
216
|
var RESET = isTTY ? "\x1B[0m" : "";
|
|
217
217
|
var CYAN = isTTY ? "\x1B[36m" : "";
|
|
218
218
|
var GREEN = isTTY ? "\x1B[32m" : "";
|
|
219
|
+
var RED = isTTY ? "\x1B[31m" : "";
|
|
219
220
|
var YELLOW = isTTY ? "\x1B[33m" : "";
|
|
220
221
|
var MAGENTA = isTTY ? "\x1B[35m" : "";
|
|
221
222
|
var DIM = isTTY ? "\x1B[2m" : "";
|
|
@@ -316,10 +317,9 @@ ${YELLOW}Note: Secrets are stored unencrypted in ~/.polkadot/accounts.json.
|
|
|
316
317
|
Hex seed import (0x...) is not supported via CLI.${RESET}
|
|
317
318
|
`.trimStart();
|
|
318
319
|
function registerAccountCommands(cli) {
|
|
319
|
-
cli.command("account [action] [name]", "Manage local accounts (create, import, list, remove)").option("--secret <value>", "Secret key (mnemonic or hex seed) for import").action(async (action, name, opts) => {
|
|
320
|
+
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) => {
|
|
320
321
|
if (!action) {
|
|
321
|
-
|
|
322
|
-
return;
|
|
322
|
+
return accountList();
|
|
323
323
|
}
|
|
324
324
|
switch (action) {
|
|
325
325
|
case "create":
|
|
@@ -696,10 +696,9 @@ ${BOLD}Examples:${RESET}
|
|
|
696
696
|
$ dot chain remove kusama
|
|
697
697
|
`.trimStart();
|
|
698
698
|
function registerChainCommands(cli) {
|
|
699
|
-
cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").action(async (action, name, opts) => {
|
|
699
|
+
cli.command("chain [action] [name]", "Manage chains (add, remove, update, list, default)").alias("chains").action(async (action, name, opts) => {
|
|
700
700
|
if (!action) {
|
|
701
|
-
|
|
702
|
-
return;
|
|
701
|
+
return chainList();
|
|
703
702
|
}
|
|
704
703
|
switch (action) {
|
|
705
704
|
case "add":
|
|
@@ -1145,6 +1144,254 @@ function parseValue(arg) {
|
|
|
1145
1144
|
return arg;
|
|
1146
1145
|
}
|
|
1147
1146
|
|
|
1147
|
+
// src/commands/tx.ts
|
|
1148
|
+
import { getViewBuilder } from "@polkadot-api/view-builder";
|
|
1149
|
+
import { Binary } from "polkadot-api";
|
|
1150
|
+
|
|
1151
|
+
// src/core/explorers.ts
|
|
1152
|
+
var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
|
|
1153
|
+
var papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
|
|
1154
|
+
|
|
1155
|
+
// src/commands/tx.ts
|
|
1156
|
+
function parseStructArgs(meta, fields, args, callLabel) {
|
|
1157
|
+
const fieldNames = Object.keys(fields);
|
|
1158
|
+
if (args.length !== fieldNames.length) {
|
|
1159
|
+
const expected = fieldNames.map((name) => `${name}: ${describeType(meta.lookup, fields[name].id)}`).join(", ");
|
|
1160
|
+
throw new Error(`${callLabel} takes ${fieldNames.length} argument(s): ${expected}
|
|
1161
|
+
` + ` Got ${args.length} argument(s).`);
|
|
1162
|
+
}
|
|
1163
|
+
const result = {};
|
|
1164
|
+
for (let i = 0;i < fieldNames.length; i++) {
|
|
1165
|
+
const name = fieldNames[i];
|
|
1166
|
+
const entry = fields[name];
|
|
1167
|
+
result[name] = parseTypedArg(meta, entry, args[i]);
|
|
1168
|
+
}
|
|
1169
|
+
return result;
|
|
1170
|
+
}
|
|
1171
|
+
function normalizeValue(lookup, entry, value) {
|
|
1172
|
+
let resolved = entry;
|
|
1173
|
+
while (resolved.type === "lookupEntry") {
|
|
1174
|
+
resolved = resolved.value;
|
|
1175
|
+
}
|
|
1176
|
+
switch (resolved.type) {
|
|
1177
|
+
case "enum": {
|
|
1178
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && "type" in value) {
|
|
1179
|
+
const enumValue = value;
|
|
1180
|
+
const variant = resolved.value[enumValue.type];
|
|
1181
|
+
if (variant) {
|
|
1182
|
+
let innerEntry = variant;
|
|
1183
|
+
while (innerEntry.type === "lookupEntry") {
|
|
1184
|
+
innerEntry = innerEntry.value;
|
|
1185
|
+
}
|
|
1186
|
+
let normalizedInner = enumValue.value;
|
|
1187
|
+
if (innerEntry.type !== "array" && innerEntry.type !== "sequence" && innerEntry.type !== "void" && Array.isArray(normalizedInner) && normalizedInner.length === 1) {
|
|
1188
|
+
normalizedInner = normalizedInner[0];
|
|
1189
|
+
}
|
|
1190
|
+
if (normalizedInner !== undefined && innerEntry.type !== "void") {
|
|
1191
|
+
normalizedInner = normalizeValue(lookup, innerEntry, normalizedInner);
|
|
1192
|
+
}
|
|
1193
|
+
return { type: enumValue.type, value: normalizedInner };
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return value;
|
|
1197
|
+
}
|
|
1198
|
+
case "struct": {
|
|
1199
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
1200
|
+
const fields = resolved.value;
|
|
1201
|
+
const result = {};
|
|
1202
|
+
for (const [key, val] of Object.entries(value)) {
|
|
1203
|
+
if (key in fields) {
|
|
1204
|
+
result[key] = normalizeValue(lookup, fields[key], val);
|
|
1205
|
+
} else {
|
|
1206
|
+
result[key] = val;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return result;
|
|
1210
|
+
}
|
|
1211
|
+
return value;
|
|
1212
|
+
}
|
|
1213
|
+
case "array":
|
|
1214
|
+
case "sequence": {
|
|
1215
|
+
let innerResolved = resolved.value;
|
|
1216
|
+
while (innerResolved.type === "lookupEntry") {
|
|
1217
|
+
innerResolved = innerResolved.value;
|
|
1218
|
+
}
|
|
1219
|
+
if (innerResolved.type === "primitive" && innerResolved.value === "u8" && typeof value === "string") {
|
|
1220
|
+
if (/^0x[0-9a-fA-F]*$/.test(value))
|
|
1221
|
+
return Binary.fromHex(value);
|
|
1222
|
+
return Binary.fromText(value);
|
|
1223
|
+
}
|
|
1224
|
+
if (Array.isArray(value)) {
|
|
1225
|
+
const innerEntry = resolved.value;
|
|
1226
|
+
return value.map((item) => normalizeValue(lookup, innerEntry, item));
|
|
1227
|
+
}
|
|
1228
|
+
return value;
|
|
1229
|
+
}
|
|
1230
|
+
case "tuple": {
|
|
1231
|
+
if (Array.isArray(value)) {
|
|
1232
|
+
const entries = resolved.value;
|
|
1233
|
+
return value.map((item, i) => i < entries.length ? normalizeValue(lookup, entries[i], item) : item);
|
|
1234
|
+
}
|
|
1235
|
+
return value;
|
|
1236
|
+
}
|
|
1237
|
+
case "option": {
|
|
1238
|
+
if (value !== null && value !== undefined) {
|
|
1239
|
+
return normalizeValue(lookup, resolved.value, value);
|
|
1240
|
+
}
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
case "primitive": {
|
|
1244
|
+
if (typeof value === "string") {
|
|
1245
|
+
const prim = resolved.value;
|
|
1246
|
+
switch (prim) {
|
|
1247
|
+
case "bool":
|
|
1248
|
+
return value === "true";
|
|
1249
|
+
case "u64":
|
|
1250
|
+
case "u128":
|
|
1251
|
+
case "u256":
|
|
1252
|
+
case "i64":
|
|
1253
|
+
case "i128":
|
|
1254
|
+
case "i256":
|
|
1255
|
+
return BigInt(value);
|
|
1256
|
+
case "u8":
|
|
1257
|
+
case "u16":
|
|
1258
|
+
case "u32":
|
|
1259
|
+
case "i8":
|
|
1260
|
+
case "i16":
|
|
1261
|
+
case "i32":
|
|
1262
|
+
return parseInt(value, 10);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return value;
|
|
1266
|
+
}
|
|
1267
|
+
case "compact": {
|
|
1268
|
+
if (typeof value === "string") {
|
|
1269
|
+
return resolved.isBig ? BigInt(value) : parseInt(value, 10);
|
|
1270
|
+
}
|
|
1271
|
+
return value;
|
|
1272
|
+
}
|
|
1273
|
+
default:
|
|
1274
|
+
return value;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
function parseTypedArg(meta, entry, arg) {
|
|
1278
|
+
switch (entry.type) {
|
|
1279
|
+
case "primitive":
|
|
1280
|
+
return parsePrimitive(entry.value, arg);
|
|
1281
|
+
case "compact":
|
|
1282
|
+
return entry.isBig ? BigInt(arg) : parseInt(arg, 10);
|
|
1283
|
+
case "AccountId32":
|
|
1284
|
+
case "AccountId20":
|
|
1285
|
+
return arg;
|
|
1286
|
+
case "option": {
|
|
1287
|
+
if (arg === "null" || arg === "undefined" || arg === "none") {
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
return parseTypedArg(meta, entry.value, arg);
|
|
1291
|
+
}
|
|
1292
|
+
case "enum": {
|
|
1293
|
+
if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
|
|
1294
|
+
const callCodec = meta.builder.buildDefinition(meta.lookup.call);
|
|
1295
|
+
return callCodec.dec(Binary.fromHex(arg).asBytes());
|
|
1296
|
+
}
|
|
1297
|
+
if (arg.startsWith("{")) {
|
|
1298
|
+
try {
|
|
1299
|
+
return normalizeValue(meta.lookup, entry, JSON.parse(arg));
|
|
1300
|
+
} catch {}
|
|
1301
|
+
}
|
|
1302
|
+
const variants = Object.keys(entry.value);
|
|
1303
|
+
if (variants.includes("Id")) {
|
|
1304
|
+
const idVariant = entry.value.Id;
|
|
1305
|
+
const innerType = idVariant.type === "lookupEntry" ? idVariant.value : idVariant;
|
|
1306
|
+
if (innerType.type === "AccountId32" && !arg.startsWith("{")) {
|
|
1307
|
+
return { type: "Id", value: arg };
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
const matched = variants.find((v) => v.toLowerCase() === arg.toLowerCase());
|
|
1311
|
+
if (matched) {
|
|
1312
|
+
const variant = entry.value[matched];
|
|
1313
|
+
if (variant.type === "void") {
|
|
1314
|
+
return { type: matched };
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return parseValue(arg);
|
|
1318
|
+
}
|
|
1319
|
+
case "sequence":
|
|
1320
|
+
case "array": {
|
|
1321
|
+
const inner = entry.value;
|
|
1322
|
+
if (inner.type === "primitive" && inner.value === "u8") {
|
|
1323
|
+
if (/^0x[0-9a-fA-F]*$/.test(arg))
|
|
1324
|
+
return Binary.fromHex(arg);
|
|
1325
|
+
return Binary.fromText(arg);
|
|
1326
|
+
}
|
|
1327
|
+
if (arg.startsWith("[")) {
|
|
1328
|
+
try {
|
|
1329
|
+
return normalizeValue(meta.lookup, entry, JSON.parse(arg));
|
|
1330
|
+
} catch {}
|
|
1331
|
+
}
|
|
1332
|
+
if (/^0x[0-9a-fA-F]*$/.test(arg))
|
|
1333
|
+
return Binary.fromHex(arg);
|
|
1334
|
+
return parseValue(arg);
|
|
1335
|
+
}
|
|
1336
|
+
case "struct":
|
|
1337
|
+
if (arg.startsWith("{")) {
|
|
1338
|
+
try {
|
|
1339
|
+
return normalizeValue(meta.lookup, entry, JSON.parse(arg));
|
|
1340
|
+
} catch {}
|
|
1341
|
+
}
|
|
1342
|
+
return parseValue(arg);
|
|
1343
|
+
case "tuple":
|
|
1344
|
+
if (arg.startsWith("[")) {
|
|
1345
|
+
try {
|
|
1346
|
+
return normalizeValue(meta.lookup, entry, JSON.parse(arg));
|
|
1347
|
+
} catch {}
|
|
1348
|
+
}
|
|
1349
|
+
return parseValue(arg);
|
|
1350
|
+
default:
|
|
1351
|
+
return parseValue(arg);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function parsePrimitive(prim, arg) {
|
|
1355
|
+
switch (prim) {
|
|
1356
|
+
case "bool":
|
|
1357
|
+
return arg === "true";
|
|
1358
|
+
case "char":
|
|
1359
|
+
case "str":
|
|
1360
|
+
return arg;
|
|
1361
|
+
case "u8":
|
|
1362
|
+
case "u16":
|
|
1363
|
+
case "u32":
|
|
1364
|
+
case "i8":
|
|
1365
|
+
case "i16":
|
|
1366
|
+
case "i32":
|
|
1367
|
+
return parseInt(arg, 10);
|
|
1368
|
+
case "u64":
|
|
1369
|
+
case "u128":
|
|
1370
|
+
case "u256":
|
|
1371
|
+
case "i64":
|
|
1372
|
+
case "i128":
|
|
1373
|
+
case "i256":
|
|
1374
|
+
return BigInt(arg);
|
|
1375
|
+
default:
|
|
1376
|
+
return parseValue(arg);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
var PAPI_BUILTIN_EXTENSIONS = new Set([
|
|
1380
|
+
"CheckNonZeroSender",
|
|
1381
|
+
"CheckSpecVersion",
|
|
1382
|
+
"CheckTxVersion",
|
|
1383
|
+
"CheckGenesis",
|
|
1384
|
+
"CheckMortality",
|
|
1385
|
+
"CheckNonce",
|
|
1386
|
+
"CheckWeight",
|
|
1387
|
+
"ChargeTransactionPayment",
|
|
1388
|
+
"ChargeAssetTxPayment",
|
|
1389
|
+
"CheckMetadataHash",
|
|
1390
|
+
"StorageWeightReclaim",
|
|
1391
|
+
"PrevalidateAttests"
|
|
1392
|
+
]);
|
|
1393
|
+
var NO_DEFAULT = Symbol("no-default");
|
|
1394
|
+
|
|
1148
1395
|
// src/commands/query.ts
|
|
1149
1396
|
var DEFAULT_LIMIT = 100;
|
|
1150
1397
|
function registerQueryCommand(cli) {
|
|
@@ -1181,8 +1428,14 @@ function registerQueryCommand(cli) {
|
|
|
1181
1428
|
}
|
|
1182
1429
|
const unsafeApi = clientHandle.client.getUnsafeApi();
|
|
1183
1430
|
const storageApi = unsafeApi.query[palletInfo.name][storageItem.name];
|
|
1184
|
-
const parsedKeys = keys
|
|
1431
|
+
const parsedKeys = parseStorageKeys(meta, palletInfo.name, storageItem, keys);
|
|
1185
1432
|
const format = opts.output ?? "pretty";
|
|
1433
|
+
if (format === "json") {
|
|
1434
|
+
console.error(`chain: ${chainName}`);
|
|
1435
|
+
} else {
|
|
1436
|
+
console.log(`${DIM}chain: ${chainName}${RESET}
|
|
1437
|
+
`);
|
|
1438
|
+
}
|
|
1186
1439
|
if (storageItem.type === "map" && parsedKeys.length === 0) {
|
|
1187
1440
|
const entries = await storageApi.getEntries();
|
|
1188
1441
|
const limit = Number(opts.limit);
|
|
@@ -1205,16 +1458,46 @@ ${DIM}Showing ${limit} of ${entries.length} entries. Use --limit 0 for all.${RES
|
|
|
1205
1458
|
}
|
|
1206
1459
|
});
|
|
1207
1460
|
}
|
|
1461
|
+
function parseStorageKeys(meta, palletName, storageItem, args) {
|
|
1462
|
+
if (storageItem.type === "plain" || storageItem.keyTypeId == null) {
|
|
1463
|
+
return args.map(parseValue);
|
|
1464
|
+
}
|
|
1465
|
+
if (args.length === 0)
|
|
1466
|
+
return [];
|
|
1467
|
+
const storageEntry = meta.builder.buildStorage(palletName, storageItem.name);
|
|
1468
|
+
const len = storageEntry.len;
|
|
1469
|
+
const keyEntry = meta.lookup(storageItem.keyTypeId);
|
|
1470
|
+
if (len === 1) {
|
|
1471
|
+
if (args.length === 1) {
|
|
1472
|
+
return [parseTypedArg(meta, keyEntry, args[0])];
|
|
1473
|
+
}
|
|
1474
|
+
if (keyEntry.type === "struct") {
|
|
1475
|
+
const label = `${palletName}.${storageItem.name} key`;
|
|
1476
|
+
return [parseStructArgs(meta, keyEntry.value, args, label)];
|
|
1477
|
+
}
|
|
1478
|
+
const typeDesc = describeType(meta.lookup, storageItem.keyTypeId);
|
|
1479
|
+
throw new Error(`${palletName}.${storageItem.name} key expects ${typeDesc}
|
|
1480
|
+
` + ` Pass 1 argument. Got ${args.length}.`);
|
|
1481
|
+
}
|
|
1482
|
+
if (args.length !== len) {
|
|
1483
|
+
let typeDesc;
|
|
1484
|
+
if (keyEntry.type === "tuple") {
|
|
1485
|
+
typeDesc = keyEntry.value.map((e) => describeType(meta.lookup, e.id)).join(", ");
|
|
1486
|
+
} else {
|
|
1487
|
+
typeDesc = describeType(meta.lookup, storageItem.keyTypeId);
|
|
1488
|
+
}
|
|
1489
|
+
throw new Error(`${palletName}.${storageItem.name} expects ${len} key arg(s): (${typeDesc}). Got ${args.length}.`);
|
|
1490
|
+
}
|
|
1491
|
+
if (keyEntry.type === "tuple") {
|
|
1492
|
+
const entries = keyEntry.value;
|
|
1493
|
+
return entries.map((entry, i) => parseTypedArg(meta, entry, args[i]));
|
|
1494
|
+
}
|
|
1495
|
+
return args.map((arg) => parseTypedArg(meta, keyEntry, arg));
|
|
1496
|
+
}
|
|
1208
1497
|
|
|
1209
1498
|
// src/commands/tx.ts
|
|
1210
|
-
import { getViewBuilder } from "@polkadot-api/view-builder";
|
|
1211
|
-
import { Binary } from "polkadot-api";
|
|
1212
|
-
|
|
1213
|
-
// src/core/explorers.ts
|
|
1214
|
-
var pjsAppsLink = (rpc, hash) => `https://polkadot.js.org/apps/?rpc=${encodeURIComponent(rpc)}#/explorer/query/${hash}`;
|
|
1215
|
-
var papiLink = (rpc, hash) => `https://dev.papi.how/explorer/${hash}#networkId=custom&endpoint=${encodeURIComponent(rpc)}`;
|
|
1216
|
-
|
|
1217
|
-
// src/commands/tx.ts
|
|
1499
|
+
import { getViewBuilder as getViewBuilder2 } from "@polkadot-api/view-builder";
|
|
1500
|
+
import { Binary as Binary2 } from "polkadot-api";
|
|
1218
1501
|
function registerTxCommand(cli) {
|
|
1219
1502
|
cli.command("tx [target] [...args]", "Submit an extrinsic (e.g. Balances.transferKeepAlive <dest> <amount>)").option("--from <name>", "Account to sign with (required)").option("--dry-run", "Estimate fees without submitting").option("--encode", "Encode call to hex without signing or submitting").option("--ext <json>", `Custom signed extension values as JSON, e.g. '{"ExtName":{"value":...}}'`).action(async (target, args, opts) => {
|
|
1220
1503
|
if (!target) {
|
|
@@ -1271,7 +1554,7 @@ function registerTxCommand(cli) {
|
|
|
1271
1554
|
throw new Error(`Extra arguments are not allowed when submitting a raw call hex.
|
|
1272
1555
|
` + "Usage: dot tx 0x<call_hex> --from <account>");
|
|
1273
1556
|
}
|
|
1274
|
-
const callBinary =
|
|
1557
|
+
const callBinary = Binary2.fromHex(target);
|
|
1275
1558
|
tx = await unsafeApi.txFromCallData(callBinary);
|
|
1276
1559
|
callHex = target;
|
|
1277
1560
|
} else {
|
|
@@ -1291,7 +1574,7 @@ function registerTxCommand(cli) {
|
|
|
1291
1574
|
const { codec, location } = meta.builder.buildCall(palletInfo.name, callInfo.name);
|
|
1292
1575
|
const encodedArgs = codec.enc(callData);
|
|
1293
1576
|
const fullCall = new Uint8Array([location[0], location[1], ...encodedArgs]);
|
|
1294
|
-
console.log(
|
|
1577
|
+
console.log(Binary2.fromBytes(fullCall).asHex());
|
|
1295
1578
|
return;
|
|
1296
1579
|
}
|
|
1297
1580
|
tx = unsafeApi.tx[palletInfo.name][callInfo.name](callData);
|
|
@@ -1320,12 +1603,13 @@ function registerTxCommand(cli) {
|
|
|
1320
1603
|
console.log(` ${BOLD}Call:${RESET} ${callHex}`);
|
|
1321
1604
|
console.log(` ${BOLD}Decode:${RESET} ${decodedStr}`);
|
|
1322
1605
|
console.log(` ${BOLD}Tx:${RESET} ${result.txHash}`);
|
|
1323
|
-
|
|
1606
|
+
let dispatchErrorMsg;
|
|
1324
1607
|
if (result.ok) {
|
|
1325
1608
|
console.log(` ${BOLD}Status:${RESET} ${GREEN}ok${RESET}`);
|
|
1326
1609
|
} else {
|
|
1327
|
-
|
|
1328
|
-
console.log(` ${BOLD}
|
|
1610
|
+
dispatchErrorMsg = formatDispatchError(result.dispatchError);
|
|
1611
|
+
console.log(` ${BOLD}Status:${RESET} ${RED}dispatch error${RESET}`);
|
|
1612
|
+
console.log(` ${BOLD}Error:${RESET} ${dispatchErrorMsg}`);
|
|
1329
1613
|
}
|
|
1330
1614
|
if (result.events && result.events.length > 0) {
|
|
1331
1615
|
console.log(` ${BOLD}Events:${RESET}`);
|
|
@@ -1348,14 +1632,34 @@ function registerTxCommand(cli) {
|
|
|
1348
1632
|
console.log(` ${DIM}PAPI${RESET} ${papiLink(rpcUrl, blockHash)}`);
|
|
1349
1633
|
}
|
|
1350
1634
|
console.log();
|
|
1635
|
+
if (!result.ok) {
|
|
1636
|
+
throw new CliError(`Transaction dispatch error: ${dispatchErrorMsg}`);
|
|
1637
|
+
}
|
|
1351
1638
|
} finally {
|
|
1352
1639
|
clientHandle?.destroy();
|
|
1353
1640
|
}
|
|
1354
1641
|
});
|
|
1355
1642
|
}
|
|
1643
|
+
function formatDispatchError(err) {
|
|
1644
|
+
if (err.type === "Module" && err.value && typeof err.value === "object") {
|
|
1645
|
+
const mod = err.value;
|
|
1646
|
+
if (mod.type) {
|
|
1647
|
+
const inner = mod.value;
|
|
1648
|
+
if (inner && typeof inner === "object" && inner.type) {
|
|
1649
|
+
return `${mod.type}.${inner.type}`;
|
|
1650
|
+
}
|
|
1651
|
+
return mod.type;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
if (err.value !== undefined && err.value !== null) {
|
|
1655
|
+
const val = typeof err.value === "string" ? err.value : JSON.stringify(err.value);
|
|
1656
|
+
return `${err.type}: ${val}`;
|
|
1657
|
+
}
|
|
1658
|
+
return err.type;
|
|
1659
|
+
}
|
|
1356
1660
|
function decodeCall(meta, callHex) {
|
|
1357
1661
|
try {
|
|
1358
|
-
const viewBuilder =
|
|
1662
|
+
const viewBuilder = getViewBuilder2(meta.lookup);
|
|
1359
1663
|
const decoded = viewBuilder.callDecoder(callHex);
|
|
1360
1664
|
const palletName = decoded.pallet.value.name;
|
|
1361
1665
|
const callName = decoded.call.value.name;
|
|
@@ -1472,30 +1776,30 @@ function parseCallArgs(meta, palletName, callName, args) {
|
|
|
1472
1776
|
return;
|
|
1473
1777
|
}
|
|
1474
1778
|
if (variant.type === "struct") {
|
|
1475
|
-
return
|
|
1779
|
+
return parseStructArgs2(meta, variant.value, args, `${palletName}.${callName}`);
|
|
1476
1780
|
}
|
|
1477
1781
|
if (variant.type === "lookupEntry") {
|
|
1478
1782
|
const inner = variant.value;
|
|
1479
1783
|
if (inner.type === "struct") {
|
|
1480
|
-
return
|
|
1784
|
+
return parseStructArgs2(meta, inner.value, args, `${palletName}.${callName}`);
|
|
1481
1785
|
}
|
|
1482
1786
|
if (inner.type === "void")
|
|
1483
1787
|
return;
|
|
1484
1788
|
if (args.length !== 1) {
|
|
1485
1789
|
throw new Error(`${palletName}.${callName} takes 1 argument (${describeType(meta.lookup, inner.id)}), but ${args.length} provided.`);
|
|
1486
1790
|
}
|
|
1487
|
-
return
|
|
1791
|
+
return parseTypedArg2(meta, inner, args[0]);
|
|
1488
1792
|
}
|
|
1489
1793
|
if (variant.type === "tuple") {
|
|
1490
1794
|
const entries = variant.value;
|
|
1491
1795
|
if (args.length !== entries.length) {
|
|
1492
1796
|
throw new Error(`${palletName}.${callName} takes ${entries.length} arguments, but ${args.length} provided.`);
|
|
1493
1797
|
}
|
|
1494
|
-
return entries.map((entry, i) =>
|
|
1798
|
+
return entries.map((entry, i) => parseTypedArg2(meta, entry, args[i]));
|
|
1495
1799
|
}
|
|
1496
1800
|
return args.length === 0 ? undefined : args.map(parseValue);
|
|
1497
1801
|
}
|
|
1498
|
-
function
|
|
1802
|
+
function parseStructArgs2(meta, fields, args, callLabel) {
|
|
1499
1803
|
const fieldNames = Object.keys(fields);
|
|
1500
1804
|
if (args.length !== fieldNames.length) {
|
|
1501
1805
|
const expected = fieldNames.map((name) => `${name}: ${describeType(meta.lookup, fields[name].id)}`).join(", ");
|
|
@@ -1506,11 +1810,11 @@ function parseStructArgs(meta, fields, args, callLabel) {
|
|
|
1506
1810
|
for (let i = 0;i < fieldNames.length; i++) {
|
|
1507
1811
|
const name = fieldNames[i];
|
|
1508
1812
|
const entry = fields[name];
|
|
1509
|
-
result[name] =
|
|
1813
|
+
result[name] = parseTypedArg2(meta, entry, args[i]);
|
|
1510
1814
|
}
|
|
1511
1815
|
return result;
|
|
1512
1816
|
}
|
|
1513
|
-
function
|
|
1817
|
+
function normalizeValue2(lookup, entry, value) {
|
|
1514
1818
|
let resolved = entry;
|
|
1515
1819
|
while (resolved.type === "lookupEntry") {
|
|
1516
1820
|
resolved = resolved.value;
|
|
@@ -1530,7 +1834,7 @@ function normalizeValue(lookup, entry, value) {
|
|
|
1530
1834
|
normalizedInner = normalizedInner[0];
|
|
1531
1835
|
}
|
|
1532
1836
|
if (normalizedInner !== undefined && innerEntry.type !== "void") {
|
|
1533
|
-
normalizedInner =
|
|
1837
|
+
normalizedInner = normalizeValue2(lookup, innerEntry, normalizedInner);
|
|
1534
1838
|
}
|
|
1535
1839
|
return { type: enumValue.type, value: normalizedInner };
|
|
1536
1840
|
}
|
|
@@ -1543,7 +1847,7 @@ function normalizeValue(lookup, entry, value) {
|
|
|
1543
1847
|
const result = {};
|
|
1544
1848
|
for (const [key, val] of Object.entries(value)) {
|
|
1545
1849
|
if (key in fields) {
|
|
1546
|
-
result[key] =
|
|
1850
|
+
result[key] = normalizeValue2(lookup, fields[key], val);
|
|
1547
1851
|
} else {
|
|
1548
1852
|
result[key] = val;
|
|
1549
1853
|
}
|
|
@@ -1560,25 +1864,25 @@ function normalizeValue(lookup, entry, value) {
|
|
|
1560
1864
|
}
|
|
1561
1865
|
if (innerResolved.type === "primitive" && innerResolved.value === "u8" && typeof value === "string") {
|
|
1562
1866
|
if (/^0x[0-9a-fA-F]*$/.test(value))
|
|
1563
|
-
return
|
|
1564
|
-
return
|
|
1867
|
+
return Binary2.fromHex(value);
|
|
1868
|
+
return Binary2.fromText(value);
|
|
1565
1869
|
}
|
|
1566
1870
|
if (Array.isArray(value)) {
|
|
1567
1871
|
const innerEntry = resolved.value;
|
|
1568
|
-
return value.map((item) =>
|
|
1872
|
+
return value.map((item) => normalizeValue2(lookup, innerEntry, item));
|
|
1569
1873
|
}
|
|
1570
1874
|
return value;
|
|
1571
1875
|
}
|
|
1572
1876
|
case "tuple": {
|
|
1573
1877
|
if (Array.isArray(value)) {
|
|
1574
1878
|
const entries = resolved.value;
|
|
1575
|
-
return value.map((item, i) => i < entries.length ?
|
|
1879
|
+
return value.map((item, i) => i < entries.length ? normalizeValue2(lookup, entries[i], item) : item);
|
|
1576
1880
|
}
|
|
1577
1881
|
return value;
|
|
1578
1882
|
}
|
|
1579
1883
|
case "option": {
|
|
1580
1884
|
if (value !== null && value !== undefined) {
|
|
1581
|
-
return
|
|
1885
|
+
return normalizeValue2(lookup, resolved.value, value);
|
|
1582
1886
|
}
|
|
1583
1887
|
return;
|
|
1584
1888
|
}
|
|
@@ -1616,10 +1920,10 @@ function normalizeValue(lookup, entry, value) {
|
|
|
1616
1920
|
return value;
|
|
1617
1921
|
}
|
|
1618
1922
|
}
|
|
1619
|
-
function
|
|
1923
|
+
function parseTypedArg2(meta, entry, arg) {
|
|
1620
1924
|
switch (entry.type) {
|
|
1621
1925
|
case "primitive":
|
|
1622
|
-
return
|
|
1926
|
+
return parsePrimitive2(entry.value, arg);
|
|
1623
1927
|
case "compact":
|
|
1624
1928
|
return entry.isBig ? BigInt(arg) : parseInt(arg, 10);
|
|
1625
1929
|
case "AccountId32":
|
|
@@ -1629,16 +1933,16 @@ function parseTypedArg(meta, entry, arg) {
|
|
|
1629
1933
|
if (arg === "null" || arg === "undefined" || arg === "none") {
|
|
1630
1934
|
return;
|
|
1631
1935
|
}
|
|
1632
|
-
return
|
|
1936
|
+
return parseTypedArg2(meta, entry.value, arg);
|
|
1633
1937
|
}
|
|
1634
1938
|
case "enum": {
|
|
1635
1939
|
if (/^0x[0-9a-fA-F]+$/.test(arg) && meta.lookup.call != null && entry.id === meta.lookup.call) {
|
|
1636
1940
|
const callCodec = meta.builder.buildDefinition(meta.lookup.call);
|
|
1637
|
-
return callCodec.dec(
|
|
1941
|
+
return callCodec.dec(Binary2.fromHex(arg).asBytes());
|
|
1638
1942
|
}
|
|
1639
1943
|
if (arg.startsWith("{")) {
|
|
1640
1944
|
try {
|
|
1641
|
-
return
|
|
1945
|
+
return normalizeValue2(meta.lookup, entry, JSON.parse(arg));
|
|
1642
1946
|
} catch {}
|
|
1643
1947
|
}
|
|
1644
1948
|
const variants = Object.keys(entry.value);
|
|
@@ -1663,29 +1967,29 @@ function parseTypedArg(meta, entry, arg) {
|
|
|
1663
1967
|
const inner = entry.value;
|
|
1664
1968
|
if (inner.type === "primitive" && inner.value === "u8") {
|
|
1665
1969
|
if (/^0x[0-9a-fA-F]*$/.test(arg))
|
|
1666
|
-
return
|
|
1667
|
-
return
|
|
1970
|
+
return Binary2.fromHex(arg);
|
|
1971
|
+
return Binary2.fromText(arg);
|
|
1668
1972
|
}
|
|
1669
1973
|
if (arg.startsWith("[")) {
|
|
1670
1974
|
try {
|
|
1671
|
-
return
|
|
1975
|
+
return normalizeValue2(meta.lookup, entry, JSON.parse(arg));
|
|
1672
1976
|
} catch {}
|
|
1673
1977
|
}
|
|
1674
1978
|
if (/^0x[0-9a-fA-F]*$/.test(arg))
|
|
1675
|
-
return
|
|
1979
|
+
return Binary2.fromHex(arg);
|
|
1676
1980
|
return parseValue(arg);
|
|
1677
1981
|
}
|
|
1678
1982
|
case "struct":
|
|
1679
1983
|
if (arg.startsWith("{")) {
|
|
1680
1984
|
try {
|
|
1681
|
-
return
|
|
1985
|
+
return normalizeValue2(meta.lookup, entry, JSON.parse(arg));
|
|
1682
1986
|
} catch {}
|
|
1683
1987
|
}
|
|
1684
1988
|
return parseValue(arg);
|
|
1685
1989
|
case "tuple":
|
|
1686
1990
|
if (arg.startsWith("[")) {
|
|
1687
1991
|
try {
|
|
1688
|
-
return
|
|
1992
|
+
return normalizeValue2(meta.lookup, entry, JSON.parse(arg));
|
|
1689
1993
|
} catch {}
|
|
1690
1994
|
}
|
|
1691
1995
|
return parseValue(arg);
|
|
@@ -1693,7 +1997,7 @@ function parseTypedArg(meta, entry, arg) {
|
|
|
1693
1997
|
return parseValue(arg);
|
|
1694
1998
|
}
|
|
1695
1999
|
}
|
|
1696
|
-
function
|
|
2000
|
+
function parsePrimitive2(prim, arg) {
|
|
1697
2001
|
switch (prim) {
|
|
1698
2002
|
case "bool":
|
|
1699
2003
|
return arg === "true";
|
|
@@ -1718,7 +2022,7 @@ function parsePrimitive(prim, arg) {
|
|
|
1718
2022
|
return parseValue(arg);
|
|
1719
2023
|
}
|
|
1720
2024
|
}
|
|
1721
|
-
var
|
|
2025
|
+
var PAPI_BUILTIN_EXTENSIONS2 = new Set([
|
|
1722
2026
|
"CheckNonZeroSender",
|
|
1723
2027
|
"CheckSpecVersion",
|
|
1724
2028
|
"CheckTxVersion",
|
|
@@ -1748,12 +2052,12 @@ function parseExtOption(ext) {
|
|
|
1748
2052
|
` + `Expected format: '{"ExtName":{"value":...}}'`);
|
|
1749
2053
|
}
|
|
1750
2054
|
}
|
|
1751
|
-
var
|
|
2055
|
+
var NO_DEFAULT2 = Symbol("no-default");
|
|
1752
2056
|
function buildCustomSignedExtensions(meta, userOverrides) {
|
|
1753
2057
|
const result = {};
|
|
1754
2058
|
const extensions = getSignedExtensions(meta);
|
|
1755
2059
|
for (const ext of extensions) {
|
|
1756
|
-
if (
|
|
2060
|
+
if (PAPI_BUILTIN_EXTENSIONS2.has(ext.identifier))
|
|
1757
2061
|
continue;
|
|
1758
2062
|
if (ext.identifier in userOverrides) {
|
|
1759
2063
|
result[ext.identifier] = userOverrides[ext.identifier];
|
|
@@ -1763,10 +2067,10 @@ function buildCustomSignedExtensions(meta, userOverrides) {
|
|
|
1763
2067
|
const addEntry = meta.lookup(ext.additionalSigned);
|
|
1764
2068
|
const value = autoDefaultForType(valueEntry);
|
|
1765
2069
|
const add = autoDefaultForType(addEntry);
|
|
1766
|
-
if (value !==
|
|
2070
|
+
if (value !== NO_DEFAULT2 || add !== NO_DEFAULT2) {
|
|
1767
2071
|
result[ext.identifier] = {
|
|
1768
|
-
...value !==
|
|
1769
|
-
...add !==
|
|
2072
|
+
...value !== NO_DEFAULT2 ? { value } : {},
|
|
2073
|
+
...add !== NO_DEFAULT2 ? { additionalSigned: add } : {}
|
|
1770
2074
|
};
|
|
1771
2075
|
}
|
|
1772
2076
|
}
|
|
@@ -1783,7 +2087,7 @@ function autoDefaultForType(entry) {
|
|
|
1783
2087
|
return { type: "Disabled", value: undefined };
|
|
1784
2088
|
}
|
|
1785
2089
|
}
|
|
1786
|
-
return
|
|
2090
|
+
return NO_DEFAULT2;
|
|
1787
2091
|
}
|
|
1788
2092
|
function watchTransaction(observable) {
|
|
1789
2093
|
const spinner = new Spinner;
|
|
@@ -1810,7 +2114,7 @@ function watchTransaction(observable) {
|
|
|
1810
2114
|
}
|
|
1811
2115
|
break;
|
|
1812
2116
|
case "finalized":
|
|
1813
|
-
spinner.
|
|
2117
|
+
spinner.succeed(`Finalized in block #${event.block.number}`);
|
|
1814
2118
|
resolve(event);
|
|
1815
2119
|
break;
|
|
1816
2120
|
}
|
|
@@ -1823,6 +2127,110 @@ function watchTransaction(observable) {
|
|
|
1823
2127
|
});
|
|
1824
2128
|
}
|
|
1825
2129
|
|
|
2130
|
+
// src/core/update-notifier.ts
|
|
2131
|
+
import { readFileSync } from "node:fs";
|
|
2132
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
2133
|
+
import { join as join3 } from "node:path";
|
|
2134
|
+
var CACHE_FILE = "update-check.json";
|
|
2135
|
+
var STALE_MS = 24 * 60 * 60 * 1000;
|
|
2136
|
+
var FETCH_TIMEOUT_MS = 5000;
|
|
2137
|
+
var REGISTRY_URL = "https://registry.npmjs.org/polkadot-cli/latest";
|
|
2138
|
+
function parseSemver(v) {
|
|
2139
|
+
const clean = v.replace(/^v/, "").split("-")[0] ?? v;
|
|
2140
|
+
const parts = clean.split(".").map(Number);
|
|
2141
|
+
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
2142
|
+
}
|
|
2143
|
+
function compareSemver(a, b) {
|
|
2144
|
+
const pa = parseSemver(a);
|
|
2145
|
+
const pb = parseSemver(b);
|
|
2146
|
+
for (let i = 0;i < 3; i++) {
|
|
2147
|
+
const left = pa[i] ?? 0;
|
|
2148
|
+
const right = pb[i] ?? 0;
|
|
2149
|
+
if (left < right)
|
|
2150
|
+
return -1;
|
|
2151
|
+
if (left > right)
|
|
2152
|
+
return 1;
|
|
2153
|
+
}
|
|
2154
|
+
return 0;
|
|
2155
|
+
}
|
|
2156
|
+
function isNewerVersion(current, latest) {
|
|
2157
|
+
return compareSemver(current, latest) < 0;
|
|
2158
|
+
}
|
|
2159
|
+
function buildNotificationBox(current, latest) {
|
|
2160
|
+
const YELLOW2 = "\x1B[33m";
|
|
2161
|
+
const GREEN2 = "\x1B[32m";
|
|
2162
|
+
const CYAN2 = "\x1B[36m";
|
|
2163
|
+
const RESET2 = "\x1B[0m";
|
|
2164
|
+
const BOLD2 = "\x1B[1m";
|
|
2165
|
+
const line1 = `Update available! ${YELLOW2}${current}${RESET2} → ${GREEN2}${BOLD2}${latest}${RESET2}`;
|
|
2166
|
+
const line2 = `Run ${CYAN2}npm i -g polkadot-cli${RESET2} to update`;
|
|
2167
|
+
const visibleLine1 = `Update available! ${current} → ${latest}`;
|
|
2168
|
+
const visibleLine2 = `Run npm i -g polkadot-cli to update`;
|
|
2169
|
+
const innerWidth = Math.max(visibleLine1.length, visibleLine2.length) + 4;
|
|
2170
|
+
const pad1 = " ".repeat(innerWidth - visibleLine1.length - 4);
|
|
2171
|
+
const pad2 = " ".repeat(innerWidth - visibleLine2.length - 4);
|
|
2172
|
+
const empty = " ".repeat(innerWidth);
|
|
2173
|
+
const top = `╭${"─".repeat(innerWidth)}╮`;
|
|
2174
|
+
const bot = `╰${"─".repeat(innerWidth)}╯`;
|
|
2175
|
+
return [
|
|
2176
|
+
top,
|
|
2177
|
+
`│${empty}│`,
|
|
2178
|
+
`│ ${line1}${pad1} │`,
|
|
2179
|
+
`│ ${line2}${pad2} │`,
|
|
2180
|
+
`│${empty}│`,
|
|
2181
|
+
bot
|
|
2182
|
+
].join(`
|
|
2183
|
+
`);
|
|
2184
|
+
}
|
|
2185
|
+
function getCachePath() {
|
|
2186
|
+
return join3(getConfigDir(), CACHE_FILE);
|
|
2187
|
+
}
|
|
2188
|
+
function readCache() {
|
|
2189
|
+
try {
|
|
2190
|
+
const data = readFileSync(getCachePath(), "utf-8");
|
|
2191
|
+
return JSON.parse(data);
|
|
2192
|
+
} catch {
|
|
2193
|
+
return null;
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
async function writeCache(cache) {
|
|
2197
|
+
try {
|
|
2198
|
+
await mkdir3(getConfigDir(), { recursive: true });
|
|
2199
|
+
await writeFile3(getCachePath(), `${JSON.stringify(cache)}
|
|
2200
|
+
`);
|
|
2201
|
+
} catch {}
|
|
2202
|
+
}
|
|
2203
|
+
function startBackgroundCheck(_currentVersion) {
|
|
2204
|
+
const cache = readCache();
|
|
2205
|
+
const now = Date.now();
|
|
2206
|
+
if (cache && now - cache.lastCheck < STALE_MS) {
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
fetch(REGISTRY_URL, {
|
|
2210
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
2211
|
+
}).then((res) => res.json()).then((data) => {
|
|
2212
|
+
const latestVersion = data.version;
|
|
2213
|
+
if (typeof latestVersion === "string") {
|
|
2214
|
+
writeCache({ lastCheck: now, latestVersion });
|
|
2215
|
+
}
|
|
2216
|
+
}).catch(() => {});
|
|
2217
|
+
}
|
|
2218
|
+
function getUpdateNotification(currentVersion) {
|
|
2219
|
+
if (process.env.DOT_NO_UPDATE_CHECK === "1")
|
|
2220
|
+
return null;
|
|
2221
|
+
if (process.env.CI)
|
|
2222
|
+
return null;
|
|
2223
|
+
if (!process.stderr.isTTY)
|
|
2224
|
+
return null;
|
|
2225
|
+
const cache = readCache();
|
|
2226
|
+
if (!cache)
|
|
2227
|
+
return null;
|
|
2228
|
+
if (isNewerVersion(currentVersion, cache.latestVersion)) {
|
|
2229
|
+
return buildNotificationBox(currentVersion, cache.latestVersion);
|
|
2230
|
+
}
|
|
2231
|
+
return null;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
1826
2234
|
// src/utils/errors.ts
|
|
1827
2235
|
class CliError2 extends Error {
|
|
1828
2236
|
constructor(message) {
|
|
@@ -1832,6 +2240,7 @@ class CliError2 extends Error {
|
|
|
1832
2240
|
}
|
|
1833
2241
|
|
|
1834
2242
|
// src/cli.ts
|
|
2243
|
+
startBackgroundCheck(version);
|
|
1835
2244
|
var cli = cac("dot");
|
|
1836
2245
|
cli.option("--chain <name>", "Target chain (default from config)");
|
|
1837
2246
|
cli.option("--rpc <url>", "Override RPC endpoint for this call");
|
|
@@ -1848,6 +2257,13 @@ registerTxCommand(cli);
|
|
|
1848
2257
|
registerHashCommand(cli);
|
|
1849
2258
|
cli.help();
|
|
1850
2259
|
cli.version(version);
|
|
2260
|
+
function showUpdateAndExit(code) {
|
|
2261
|
+
const note = getUpdateNotification(version);
|
|
2262
|
+
if (note)
|
|
2263
|
+
process.stderr.write(`${note}
|
|
2264
|
+
`);
|
|
2265
|
+
process.exit(code);
|
|
2266
|
+
}
|
|
1851
2267
|
function handleError(err) {
|
|
1852
2268
|
if (err instanceof CliError2) {
|
|
1853
2269
|
console.error(`Error: ${err.message}`);
|
|
@@ -1856,16 +2272,19 @@ function handleError(err) {
|
|
|
1856
2272
|
} else {
|
|
1857
2273
|
console.error("An unexpected error occurred:", err);
|
|
1858
2274
|
}
|
|
1859
|
-
|
|
2275
|
+
showUpdateAndExit(1);
|
|
1860
2276
|
}
|
|
1861
2277
|
try {
|
|
1862
2278
|
cli.parse(process.argv, { run: false });
|
|
1863
|
-
if (
|
|
2279
|
+
if (cli.options.version || cli.options.help) {
|
|
2280
|
+
showUpdateAndExit(0);
|
|
2281
|
+
} else if (!cli.matchedCommandName) {
|
|
1864
2282
|
cli.outputHelp();
|
|
2283
|
+
showUpdateAndExit(0);
|
|
1865
2284
|
} else {
|
|
1866
2285
|
const result = cli.runMatchedCommand();
|
|
1867
2286
|
if (result && typeof result.then === "function") {
|
|
1868
|
-
result.then(() =>
|
|
2287
|
+
result.then(() => showUpdateAndExit(0), handleError);
|
|
1869
2288
|
}
|
|
1870
2289
|
}
|
|
1871
2290
|
} catch (err) {
|