@alchemy/cli 0.14.0 → 0.16.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 +11 -0
- package/dist/{auth-ZBEPAFEP.js → auth-JHVDOG26.js} +3 -3
- package/dist/{chunk-CXR7CCJ7.js → chunk-FFQ7XKW7.js} +32 -2
- package/dist/{chunk-OIRERSZT.js → chunk-GJL52AFY.js} +1 -0
- package/dist/{chunk-M7HFRKW6.js → chunk-HPRJEGSP.js} +2 -2
- package/dist/{chunk-WDGPT4OT.js → chunk-LRCCQA3I.js} +2 -2
- package/dist/{chunk-22KBYYLI.js → chunk-N422J6U3.js} +1 -1
- package/dist/{chunk-RQDWIB62.js → chunk-Q2VRERYE.js} +1 -1
- package/dist/index.js +719 -69
- package/dist/{interactive-XNDXNMAJ.js → interactive-PQGRT27R.js} +4 -4
- package/dist/{onboarding-QE43IUEK.js → onboarding-47TK4HNM.js} +3 -3
- package/dist/{policy-prompt-UNNIF63S.js → policy-prompt-DRO7Q5VI.js} +3 -3
- package/dist/{resolve-IRTGQL4A.js → resolve-B64J4LR6.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,6 +182,16 @@ Per-command override: pass `--signer <session\|local>` to `evm send`, `evm appro
|
|
|
182
182
|
| `agent-prompt` | Emits complete agent/automation usage instructions | `alchemy --json --no-interactive agent-prompt` |
|
|
183
183
|
| `version` | Prints CLI version | `alchemy version` |
|
|
184
184
|
|
|
185
|
+
### Usage API (alpha)
|
|
186
|
+
|
|
187
|
+
The `usage` commands are in **alpha** — the response shape may change, and
|
|
188
|
+
access is limited to teams enrolled in the Usage API alpha.
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
alchemy --json usage summary
|
|
192
|
+
alchemy usage timeseries --start-date 2026-06-01 --granularity day
|
|
193
|
+
```
|
|
194
|
+
|
|
185
195
|
## Flags
|
|
186
196
|
|
|
187
197
|
### Global flags
|
|
@@ -221,6 +231,7 @@ Additional env vars:
|
|
|
221
231
|
| Env var | Description |
|
|
222
232
|
|---|---|
|
|
223
233
|
| `ALCHEMY_CONFIG` | Custom path to config file |
|
|
234
|
+
| `ALCHEMY_AUTH_TOKEN` | Admin API auth token override |
|
|
224
235
|
| `ALCHEMY_WALLET_KEY` | EVM wallet private key for x402 auth and local signing |
|
|
225
236
|
| `ALCHEMY_SOLANA_WALLET_KEY` | Solana wallet private key |
|
|
226
237
|
| `ALCHEMY_ACTIVE_SIGNER` | Active EVM signer override (`session` or `local`) |
|
|
@@ -3,11 +3,11 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
|
3
3
|
import {
|
|
4
4
|
registerAuth,
|
|
5
5
|
selectAppAfterAuth
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LRCCQA3I.js";
|
|
7
7
|
import "./chunk-CZWKHYTE.js";
|
|
8
8
|
import "./chunk-EJB4WDTU.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-FFQ7XKW7.js";
|
|
10
|
+
import "./chunk-GJL52AFY.js";
|
|
11
11
|
import "./chunk-PISUI34T.js";
|
|
12
12
|
import "./chunk-CFIDLPKB.js";
|
|
13
13
|
export {
|
|
@@ -953,6 +953,7 @@ var AdminClient = class _AdminClient {
|
|
|
953
953
|
}
|
|
954
954
|
// Test/debug only: used by mock E2E to route admin requests locally.
|
|
955
955
|
static ADMIN_API_BASE_URL_ENV = "ALCHEMY_ADMIN_API_BASE_URL";
|
|
956
|
+
static USAGE_DEBUG_TEAM_ID_HEADER = "x-alchemy-cli-debug-team-id";
|
|
956
957
|
credential;
|
|
957
958
|
constructor(credential) {
|
|
958
959
|
if (!credential.token.trim()) {
|
|
@@ -993,7 +994,7 @@ var AdminClient = class _AdminClient {
|
|
|
993
994
|
throw errInvalidArgs("Refusing to send credentials over non-HTTPS connection.");
|
|
994
995
|
}
|
|
995
996
|
}
|
|
996
|
-
async request(method, path, body) {
|
|
997
|
+
async request(method, path, body, options) {
|
|
997
998
|
const url = `${this.baseURL()}${path}`;
|
|
998
999
|
debug(`${method} ${url}`);
|
|
999
1000
|
this.assertSafeRequestTarget(url);
|
|
@@ -1003,7 +1004,8 @@ var AdminClient = class _AdminClient {
|
|
|
1003
1004
|
headers: {
|
|
1004
1005
|
Authorization: `Bearer ${this.credential.token}`,
|
|
1005
1006
|
"Content-Type": "application/json",
|
|
1006
|
-
Accept: "application/json"
|
|
1007
|
+
Accept: "application/json",
|
|
1008
|
+
...options?.headers
|
|
1007
1009
|
},
|
|
1008
1010
|
...body !== void 0 && { body: JSON.stringify(body) }
|
|
1009
1011
|
});
|
|
@@ -1070,6 +1072,31 @@ var AdminClient = class _AdminClient {
|
|
|
1070
1072
|
} while (cursor);
|
|
1071
1073
|
return { apps, pages };
|
|
1072
1074
|
}
|
|
1075
|
+
usageDebugHeaders(options) {
|
|
1076
|
+
if (options?.teamId === void 0) return void 0;
|
|
1077
|
+
const baseUrl = new URL(this.baseURL());
|
|
1078
|
+
if (!isLocalhost(baseUrl.hostname)) {
|
|
1079
|
+
throw errInvalidArgs(
|
|
1080
|
+
"--team-id is a temporary debug option and only works with ALCHEMY_ADMIN_API_BASE_URL pointing at localhost."
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
return {
|
|
1084
|
+
[_AdminClient.USAGE_DEBUG_TEAM_ID_HEADER]: String(options.teamId)
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
async getUsageSummary(options) {
|
|
1088
|
+
return await this.request("GET", "/v1/usage/summary", void 0, {
|
|
1089
|
+
headers: this.usageDebugHeaders(options)
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
async getUsageTimeseries(body, options) {
|
|
1093
|
+
return await this.request(
|
|
1094
|
+
"POST",
|
|
1095
|
+
"/v1/usage/time-series",
|
|
1096
|
+
body,
|
|
1097
|
+
{ headers: this.usageDebugHeaders(options) }
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1073
1100
|
async getApp(id) {
|
|
1074
1101
|
const resp = await this.request("GET", `/v1/apps/${id}`);
|
|
1075
1102
|
return resp.data;
|
|
@@ -1621,6 +1648,9 @@ function resolveAppId(program, cfg) {
|
|
|
1621
1648
|
return void 0;
|
|
1622
1649
|
}
|
|
1623
1650
|
function resolveAuthToken(cfg) {
|
|
1651
|
+
if (process.env.ALCHEMY_AUTH_TOKEN?.trim()) {
|
|
1652
|
+
return process.env.ALCHEMY_AUTH_TOKEN.trim();
|
|
1653
|
+
}
|
|
1624
1654
|
const config = cfg ?? load();
|
|
1625
1655
|
if (!config.auth_token?.trim()) return void 0;
|
|
1626
1656
|
if (config.auth_token_expires_at) {
|
|
@@ -3,7 +3,7 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
|
3
3
|
import {
|
|
4
4
|
gasManagerClientFromFlags,
|
|
5
5
|
toAdminNetworkId
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FFQ7XKW7.js";
|
|
7
7
|
import {
|
|
8
8
|
dim,
|
|
9
9
|
green,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
promptConfirm,
|
|
12
12
|
promptText,
|
|
13
13
|
withSpinner
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GJL52AFY.js";
|
|
15
15
|
import {
|
|
16
16
|
load,
|
|
17
17
|
save
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
AdminClient,
|
|
13
13
|
resolveAuthToken
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FFQ7XKW7.js";
|
|
15
15
|
import {
|
|
16
16
|
bold,
|
|
17
17
|
brand,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
promptAutocomplete,
|
|
21
21
|
promptText,
|
|
22
22
|
withSpinner
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-GJL52AFY.js";
|
|
24
24
|
import {
|
|
25
25
|
configPath,
|
|
26
26
|
load,
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
errNotLoggedInForPolicyLookup,
|
|
6
6
|
errSponsorshipNeedsPolicy,
|
|
7
7
|
selectOrCreatePolicy
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HPRJEGSP.js";
|
|
9
9
|
import {
|
|
10
10
|
registerAuth
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LRCCQA3I.js";
|
|
12
12
|
import {
|
|
13
13
|
openBrowser
|
|
14
14
|
} from "./chunk-CZWKHYTE.js";
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
getSetupStatus,
|
|
19
19
|
isSetupComplete,
|
|
20
20
|
shouldRunOnboarding
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-Q2VRERYE.js";
|
|
22
22
|
import {
|
|
23
23
|
isInteractiveAllowed
|
|
24
24
|
} from "./chunk-EJB4WDTU.js";
|
|
@@ -63,16 +63,17 @@ import {
|
|
|
63
63
|
updateSession,
|
|
64
64
|
validateNetwork,
|
|
65
65
|
walletNetworkToChain
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-FFQ7XKW7.js";
|
|
67
67
|
import {
|
|
68
68
|
getAvailableUpdate,
|
|
69
69
|
getUpdateStatus,
|
|
70
70
|
printUpdateNotice
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-N422J6U3.js";
|
|
72
72
|
import {
|
|
73
73
|
bold,
|
|
74
74
|
brand,
|
|
75
75
|
brandedHelp,
|
|
76
|
+
cyan,
|
|
76
77
|
dim,
|
|
77
78
|
emptyState,
|
|
78
79
|
etherscanTxURL,
|
|
@@ -92,7 +93,7 @@ import {
|
|
|
92
93
|
weiToEth,
|
|
93
94
|
withSpinner,
|
|
94
95
|
yellow
|
|
95
|
-
} from "./chunk-
|
|
96
|
+
} from "./chunk-GJL52AFY.js";
|
|
96
97
|
import {
|
|
97
98
|
KEY_MAP,
|
|
98
99
|
configDir,
|
|
@@ -148,7 +149,7 @@ import {
|
|
|
148
149
|
} from "./chunk-CFIDLPKB.js";
|
|
149
150
|
|
|
150
151
|
// src/index.ts
|
|
151
|
-
import { Command, Help } from "commander";
|
|
152
|
+
import { Command as Command2, Help } from "commander";
|
|
152
153
|
|
|
153
154
|
// src/lib/ens.ts
|
|
154
155
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
@@ -582,8 +583,8 @@ function registerConfig(program2) {
|
|
|
582
583
|
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set evm-gas-policy-id <id>`."
|
|
583
584
|
);
|
|
584
585
|
}
|
|
585
|
-
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-
|
|
586
|
-
const { resolveNetwork: resolveNetwork2 } = await import("./resolve-
|
|
586
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-DRO7Q5VI.js");
|
|
587
|
+
const { resolveNetwork: resolveNetwork2 } = await import("./resolve-B64J4LR6.js");
|
|
587
588
|
const network = resolveNetwork2(program2);
|
|
588
589
|
await selectOrCreatePolicy2({
|
|
589
590
|
flavor: "sponsorship",
|
|
@@ -637,8 +638,8 @@ function registerConfig(program2) {
|
|
|
637
638
|
"Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set solana-fee-policy-id <id>`."
|
|
638
639
|
);
|
|
639
640
|
}
|
|
640
|
-
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-
|
|
641
|
-
const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-
|
|
641
|
+
const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-DRO7Q5VI.js");
|
|
642
|
+
const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-B64J4LR6.js");
|
|
642
643
|
const network = resolveSolanaNetwork2(program2);
|
|
643
644
|
await selectOrCreatePolicy2({
|
|
644
645
|
flavor: "solana",
|
|
@@ -695,7 +696,7 @@ function registerConfig(program2) {
|
|
|
695
696
|
printJSON(toMap(cfg));
|
|
696
697
|
return;
|
|
697
698
|
}
|
|
698
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
699
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-B64J4LR6.js");
|
|
699
700
|
const validToken = resolveAuthToken2(cfg);
|
|
700
701
|
const authStatus = cfg.auth_token ? validToken ? `${green("\u2713")} authenticated${cfg.auth_token_expires_at ? ` ${dim(`(expires ${cfg.auth_token_expires_at})`)}` : ""}` : `${yellow("\u25C6")} expired${cfg.auth_token_expires_at ? ` ${dim(`(${cfg.auth_token_expires_at})`)}` : ""}` : dim("(not set) \u2014 run 'alchemy auth' to log in");
|
|
701
702
|
const pairs = [
|
|
@@ -1370,6 +1371,455 @@ function registerApps(program2) {
|
|
|
1370
1371
|
});
|
|
1371
1372
|
}
|
|
1372
1373
|
|
|
1374
|
+
// src/commands/usage.ts
|
|
1375
|
+
import { Option } from "commander";
|
|
1376
|
+
|
|
1377
|
+
// src/lib/usage-format.ts
|
|
1378
|
+
var BLOCKS = [" ", "\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u2588"];
|
|
1379
|
+
var SPARKS = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588";
|
|
1380
|
+
var MAX_ROWS = 31;
|
|
1381
|
+
function asRecord(value) {
|
|
1382
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
1383
|
+
return void 0;
|
|
1384
|
+
}
|
|
1385
|
+
return value;
|
|
1386
|
+
}
|
|
1387
|
+
function asStringArray(value) {
|
|
1388
|
+
if (!Array.isArray(value)) return void 0;
|
|
1389
|
+
const strings = value.filter((item) => typeof item === "string");
|
|
1390
|
+
return strings.length > 0 ? strings : void 0;
|
|
1391
|
+
}
|
|
1392
|
+
function parsePoint(value) {
|
|
1393
|
+
const record = asRecord(value);
|
|
1394
|
+
if (!record) return void 0;
|
|
1395
|
+
const dimensions = asRecord(record.dimensions);
|
|
1396
|
+
return {
|
|
1397
|
+
startTime: typeof record.startTime === "string" ? record.startTime : void 0,
|
|
1398
|
+
endTime: typeof record.endTime === "string" ? record.endTime : void 0,
|
|
1399
|
+
isPartial: typeof record.isPartial === "boolean" ? record.isPartial : void 0,
|
|
1400
|
+
dimensions: dimensions ? Object.fromEntries(
|
|
1401
|
+
Object.entries(dimensions).filter((entry) => typeof entry[1] === "string")
|
|
1402
|
+
) : void 0,
|
|
1403
|
+
amount: typeof record.amount === "string" ? record.amount : void 0,
|
|
1404
|
+
unit: typeof record.unit === "string" ? record.unit : void 0,
|
|
1405
|
+
usd: typeof record.usd === "string" ? record.usd : void 0
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
function getUsageTimeSeriesData(result) {
|
|
1409
|
+
const root = asRecord(result);
|
|
1410
|
+
const envelope = asRecord(root?.data);
|
|
1411
|
+
const points = Array.isArray(envelope?.data) ? envelope.data.map(parsePoint).filter((point) => Boolean(point)) : void 0;
|
|
1412
|
+
if (!envelope || !points) return void 0;
|
|
1413
|
+
const query = asRecord(envelope.query);
|
|
1414
|
+
const freshness = asRecord(envelope.freshness);
|
|
1415
|
+
return {
|
|
1416
|
+
query: query ? {
|
|
1417
|
+
startTime: typeof query.startTime === "string" ? query.startTime : void 0,
|
|
1418
|
+
endTime: typeof query.endTime === "string" ? query.endTime : void 0,
|
|
1419
|
+
metrics: asStringArray(query.metrics),
|
|
1420
|
+
groupBy: asStringArray(query.groupBy)
|
|
1421
|
+
} : void 0,
|
|
1422
|
+
freshness: freshness ? {
|
|
1423
|
+
dataThrough: typeof freshness.dataThrough === "string" ? freshness.dataThrough : void 0,
|
|
1424
|
+
containsPartialToday: typeof freshness.containsPartialToday === "boolean" ? freshness.containsPartialToday : void 0
|
|
1425
|
+
} : void 0,
|
|
1426
|
+
data: points
|
|
1427
|
+
};
|
|
1428
|
+
}
|
|
1429
|
+
function finiteNumber(value) {
|
|
1430
|
+
if (!value) return void 0;
|
|
1431
|
+
const parsed = Number(value);
|
|
1432
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
1433
|
+
}
|
|
1434
|
+
function chooseValueField(data) {
|
|
1435
|
+
const metrics = data.query?.metrics ?? [];
|
|
1436
|
+
const hasAmount = data.data.some((point) => finiteNumber(point.amount) !== void 0);
|
|
1437
|
+
const hasUsd = data.data.some((point) => finiteNumber(point.usd) !== void 0);
|
|
1438
|
+
if (metrics.includes("usd") && !metrics.includes("amount") && hasUsd) return "usd";
|
|
1439
|
+
if (hasAmount) return "amount";
|
|
1440
|
+
if (hasUsd) return "usd";
|
|
1441
|
+
return void 0;
|
|
1442
|
+
}
|
|
1443
|
+
function dateLabel(value) {
|
|
1444
|
+
if (!value) return "unknown";
|
|
1445
|
+
return value.slice(0, 10);
|
|
1446
|
+
}
|
|
1447
|
+
function aggregateByDay(points, field) {
|
|
1448
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
1449
|
+
for (const point of points) {
|
|
1450
|
+
const value = finiteNumber(point[field]);
|
|
1451
|
+
if (value === void 0) continue;
|
|
1452
|
+
const date = dateLabel(point.startTime);
|
|
1453
|
+
const existing = buckets.get(date);
|
|
1454
|
+
if (existing) {
|
|
1455
|
+
existing.value += value;
|
|
1456
|
+
existing.isPartial = existing.isPartial || point.isPartial === true;
|
|
1457
|
+
} else {
|
|
1458
|
+
buckets.set(date, {
|
|
1459
|
+
date,
|
|
1460
|
+
value,
|
|
1461
|
+
isPartial: point.isPartial === true
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return [...buckets.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
1466
|
+
}
|
|
1467
|
+
function formatNumber(value, field) {
|
|
1468
|
+
return new Intl.NumberFormat("en-US", {
|
|
1469
|
+
maximumFractionDigits: field === "usd" ? 2 : 3
|
|
1470
|
+
}).format(value);
|
|
1471
|
+
}
|
|
1472
|
+
function metricLabel(args) {
|
|
1473
|
+
if (args.field === "usd") return "USD";
|
|
1474
|
+
return args.unit ?? "usage";
|
|
1475
|
+
}
|
|
1476
|
+
function bar(args) {
|
|
1477
|
+
if (args.max <= 0 || args.value <= 0) return dim(" ".repeat(args.width));
|
|
1478
|
+
const filled = args.value / args.max * args.width;
|
|
1479
|
+
const full = Math.floor(filled);
|
|
1480
|
+
const partial = Math.round((filled - full) * 8);
|
|
1481
|
+
const partialBlock = partial > 0 ? BLOCKS[partial] : "";
|
|
1482
|
+
const barText = "\u2588".repeat(full) + partialBlock;
|
|
1483
|
+
const padding = " ".repeat(Math.max(0, args.width - full - (partial > 0 ? 1 : 0)));
|
|
1484
|
+
return cyan(barText) + dim(padding);
|
|
1485
|
+
}
|
|
1486
|
+
function sparkline(values) {
|
|
1487
|
+
const max = Math.max(...values, 1);
|
|
1488
|
+
const line = values.map((value) => SPARKS[Math.round(value / max * 7)] ?? SPARKS[0]).join("");
|
|
1489
|
+
return green(line);
|
|
1490
|
+
}
|
|
1491
|
+
function labelWidth(labels) {
|
|
1492
|
+
return Math.min(Math.max(...labels.map((label) => label.length), 4), 18);
|
|
1493
|
+
}
|
|
1494
|
+
function formatRange(data, buckets) {
|
|
1495
|
+
const start = data.query?.startTime ? dateLabel(data.query.startTime) : buckets[0]?.date;
|
|
1496
|
+
const end = data.query?.endTime ? dateLabel(data.query.endTime) : buckets[buckets.length - 1]?.date;
|
|
1497
|
+
return start && end ? `${start} -> ${end}` : "unknown range";
|
|
1498
|
+
}
|
|
1499
|
+
function dimensionLabel(point) {
|
|
1500
|
+
const entries = Object.entries(point.dimensions ?? {}).filter(([, value]) => value).map(([key, value]) => `${key}=${value}`);
|
|
1501
|
+
return entries.length > 0 ? entries.join(", ") : void 0;
|
|
1502
|
+
}
|
|
1503
|
+
function aggregateDimensions(points, field) {
|
|
1504
|
+
const totals = /* @__PURE__ */ new Map();
|
|
1505
|
+
for (const point of points) {
|
|
1506
|
+
const label = dimensionLabel(point);
|
|
1507
|
+
const value = finiteNumber(point[field]);
|
|
1508
|
+
if (!label || value === void 0) continue;
|
|
1509
|
+
totals.set(label, (totals.get(label) ?? 0) + value);
|
|
1510
|
+
}
|
|
1511
|
+
return [...totals.entries()].map(([label, value]) => ({ label, value })).sort((a, b) => b.value - a.value).slice(0, 6);
|
|
1512
|
+
}
|
|
1513
|
+
function formatUsageTimeSeriesResult(result) {
|
|
1514
|
+
const data = getUsageTimeSeriesData(result);
|
|
1515
|
+
if (!data || data.data.length === 0) return null;
|
|
1516
|
+
const field = chooseValueField(data);
|
|
1517
|
+
if (!field) return null;
|
|
1518
|
+
const buckets = aggregateByDay(data.data, field);
|
|
1519
|
+
if (buckets.length === 0) return null;
|
|
1520
|
+
const unit = metricLabel({
|
|
1521
|
+
field,
|
|
1522
|
+
unit: data.data.find((point) => point.unit)?.unit
|
|
1523
|
+
});
|
|
1524
|
+
const values = buckets.map((bucket) => bucket.value);
|
|
1525
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1526
|
+
const peak = buckets.reduce(
|
|
1527
|
+
(best, bucket) => bucket.value > best.value ? bucket : best
|
|
1528
|
+
);
|
|
1529
|
+
const max = Math.max(...values, 1);
|
|
1530
|
+
const shownBuckets = buckets.slice(0, MAX_ROWS);
|
|
1531
|
+
const width = labelWidth(shownBuckets.map((bucket) => bucket.date));
|
|
1532
|
+
const lines = [];
|
|
1533
|
+
lines.push("");
|
|
1534
|
+
lines.push(` ${brand(bold("Usage time series"))}`);
|
|
1535
|
+
lines.push(` ${dim(formatRange(data, buckets))} ${dim("metric")} ${field}`);
|
|
1536
|
+
lines.push("");
|
|
1537
|
+
lines.push(
|
|
1538
|
+
` ${dim("total")} ${green(formatNumber(total, field))} ${dim(unit)} ${dim("peak")} ${yellow(`${peak.date} ${formatNumber(peak.value, field)}`)}`
|
|
1539
|
+
);
|
|
1540
|
+
if (data.freshness?.dataThrough) {
|
|
1541
|
+
const partial = data.freshness.containsPartialToday ? " partial today" : "";
|
|
1542
|
+
lines.push(` ${dim("fresh through")} ${dateLabel(data.freshness.dataThrough)}${dim(partial)}`);
|
|
1543
|
+
}
|
|
1544
|
+
lines.push("");
|
|
1545
|
+
lines.push(` ${sparkline(values)}`);
|
|
1546
|
+
lines.push("");
|
|
1547
|
+
for (const bucket of shownBuckets) {
|
|
1548
|
+
const date = bucket.date.padEnd(width);
|
|
1549
|
+
const partial = bucket.isPartial ? " *" : " ";
|
|
1550
|
+
const value = formatNumber(bucket.value, field).padStart(12);
|
|
1551
|
+
lines.push(
|
|
1552
|
+
` ${dim(date)}${partial} ${value} ${dim(unit)} ${bar({
|
|
1553
|
+
value: bucket.value,
|
|
1554
|
+
max,
|
|
1555
|
+
width: 28
|
|
1556
|
+
})}`
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
if (buckets.length > shownBuckets.length) {
|
|
1560
|
+
lines.push(
|
|
1561
|
+
` ${dim(`showing ${shownBuckets.length} of ${buckets.length} days; use --json for full data`)}`
|
|
1562
|
+
);
|
|
1563
|
+
}
|
|
1564
|
+
if (buckets.some((bucket) => bucket.isPartial)) {
|
|
1565
|
+
lines.push(` ${dim("* partial bucket")}`);
|
|
1566
|
+
}
|
|
1567
|
+
const dimensions = aggregateDimensions(data.data, field);
|
|
1568
|
+
if (dimensions.length > 0) {
|
|
1569
|
+
const dimensionMax = Math.max(...dimensions.map((item) => item.value), 1);
|
|
1570
|
+
const dimensionWidth = labelWidth(dimensions.map((item) => item.label));
|
|
1571
|
+
lines.push("");
|
|
1572
|
+
lines.push(` ${brand(bold("Top dimensions"))}`);
|
|
1573
|
+
for (const item of dimensions) {
|
|
1574
|
+
const label = item.label.length > dimensionWidth ? `${item.label.slice(0, dimensionWidth - 1)}\u2026` : item.label.padEnd(dimensionWidth);
|
|
1575
|
+
lines.push(
|
|
1576
|
+
` ${dim(label)} ${formatNumber(item.value, field).padStart(12)} ${dim(unit)} ${bar({
|
|
1577
|
+
value: item.value,
|
|
1578
|
+
max: dimensionMax,
|
|
1579
|
+
width: 20
|
|
1580
|
+
})}`
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
return `${lines.join("\n")}
|
|
1585
|
+
`;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/commands/usage.ts
|
|
1589
|
+
var DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1590
|
+
var DATETIME_WITH_TIMEZONE_RE = /^\d{4}-\d{2}-\d{2}T.+(Z|[+-]\d{2}:\d{2})$/;
|
|
1591
|
+
var TEAM_ID_RE = /^\d+$/;
|
|
1592
|
+
var VALID_METRICS = /* @__PURE__ */ new Set(["amount", "usd"]);
|
|
1593
|
+
var VALID_GROUP_BY = /* @__PURE__ */ new Set([
|
|
1594
|
+
"requestType",
|
|
1595
|
+
"app",
|
|
1596
|
+
"network",
|
|
1597
|
+
"method"
|
|
1598
|
+
]);
|
|
1599
|
+
var VALID_REQUEST_TYPES = /* @__PURE__ */ new Set([
|
|
1600
|
+
"http",
|
|
1601
|
+
"websocket",
|
|
1602
|
+
"webhook",
|
|
1603
|
+
"grpc"
|
|
1604
|
+
]);
|
|
1605
|
+
function parseBodyJSON(value) {
|
|
1606
|
+
let parsed;
|
|
1607
|
+
try {
|
|
1608
|
+
parsed = JSON.parse(value);
|
|
1609
|
+
} catch {
|
|
1610
|
+
throw errInvalidArgs("--body must be valid JSON.");
|
|
1611
|
+
}
|
|
1612
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1613
|
+
throw errInvalidArgs("--body must be a JSON object.");
|
|
1614
|
+
}
|
|
1615
|
+
return parsed;
|
|
1616
|
+
}
|
|
1617
|
+
function splitCommaList2(value) {
|
|
1618
|
+
if (!value) return void 0;
|
|
1619
|
+
const items = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1620
|
+
return items.length > 0 ? items : void 0;
|
|
1621
|
+
}
|
|
1622
|
+
function assertAllowedValues(values, allowed, flagName) {
|
|
1623
|
+
for (const value of values ?? []) {
|
|
1624
|
+
if (!allowed.has(value)) {
|
|
1625
|
+
throw errInvalidArgs(
|
|
1626
|
+
`${flagName} contains unsupported value '${value}'.`
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
function debugTeamIdOption() {
|
|
1632
|
+
return new Option(
|
|
1633
|
+
"--team-id <id>",
|
|
1634
|
+
"Temporary local usage API team override"
|
|
1635
|
+
).hideHelp();
|
|
1636
|
+
}
|
|
1637
|
+
function parseTeamId(value) {
|
|
1638
|
+
if (value === void 0) return void 0;
|
|
1639
|
+
if (!TEAM_ID_RE.test(value)) {
|
|
1640
|
+
throw errInvalidArgs("--team-id must be a positive integer.");
|
|
1641
|
+
}
|
|
1642
|
+
const teamId = Number(value);
|
|
1643
|
+
if (!Number.isSafeInteger(teamId) || teamId <= 0) {
|
|
1644
|
+
throw errInvalidArgs("--team-id must be a positive integer.");
|
|
1645
|
+
}
|
|
1646
|
+
return teamId;
|
|
1647
|
+
}
|
|
1648
|
+
function buildUsageRequestOptions(opts) {
|
|
1649
|
+
const teamId = parseTeamId(opts.teamId);
|
|
1650
|
+
return teamId === void 0 ? void 0 : { teamId };
|
|
1651
|
+
}
|
|
1652
|
+
function normalizeDateTime(value, flagName) {
|
|
1653
|
+
if (!value) return void 0;
|
|
1654
|
+
if (DATE_ONLY_RE.test(value)) {
|
|
1655
|
+
const date2 = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
|
|
1656
|
+
if (Number.isNaN(date2.getTime()) || date2.toISOString().slice(0, 10) !== value) {
|
|
1657
|
+
throw errInvalidArgs(`${flagName} must be a valid date or datetime.`);
|
|
1658
|
+
}
|
|
1659
|
+
return `${value}T00:00:00.000Z`;
|
|
1660
|
+
}
|
|
1661
|
+
if (!DATETIME_WITH_TIMEZONE_RE.test(value)) {
|
|
1662
|
+
throw errInvalidArgs(
|
|
1663
|
+
`${flagName} must be YYYY-MM-DD or an ISO datetime with a timezone.`
|
|
1664
|
+
);
|
|
1665
|
+
}
|
|
1666
|
+
const date = new Date(value);
|
|
1667
|
+
if (Number.isNaN(date.getTime())) {
|
|
1668
|
+
throw errInvalidArgs(`${flagName} must be a valid date or datetime.`);
|
|
1669
|
+
}
|
|
1670
|
+
return date.toISOString();
|
|
1671
|
+
}
|
|
1672
|
+
function hasBuilderOptions(opts) {
|
|
1673
|
+
return Object.entries(opts).some(
|
|
1674
|
+
([key, value]) => key !== "body" && key !== "teamId" && value !== void 0
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
function buildTimeseriesRequest(opts) {
|
|
1678
|
+
if (opts.body) {
|
|
1679
|
+
if (hasBuilderOptions(opts)) {
|
|
1680
|
+
throw errInvalidArgs("--body cannot be combined with other time series flags.");
|
|
1681
|
+
}
|
|
1682
|
+
return parseBodyJSON(opts.body);
|
|
1683
|
+
}
|
|
1684
|
+
if (opts.startDate && opts.startTime) {
|
|
1685
|
+
throw errInvalidArgs("Pass either --start-date or --start-time, not both.");
|
|
1686
|
+
}
|
|
1687
|
+
if (opts.endDate && opts.endTime) {
|
|
1688
|
+
throw errInvalidArgs("Pass either --end-date or --end-time, not both.");
|
|
1689
|
+
}
|
|
1690
|
+
const startTime = normalizeDateTime(
|
|
1691
|
+
opts.startTime ?? opts.startDate,
|
|
1692
|
+
opts.startTime ? "--start-time" : "--start-date"
|
|
1693
|
+
);
|
|
1694
|
+
const endTime = normalizeDateTime(
|
|
1695
|
+
opts.endTime ?? opts.endDate,
|
|
1696
|
+
opts.endTime ? "--end-time" : "--end-date"
|
|
1697
|
+
) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1698
|
+
if (!startTime) {
|
|
1699
|
+
throw errInvalidArgs(
|
|
1700
|
+
"Usage time series requires --start-date or --start-time, or --body."
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
const products = splitCommaList2(opts.products);
|
|
1704
|
+
const metrics = splitCommaList2(opts.metrics);
|
|
1705
|
+
const appIds = splitCommaList2(opts.appIds);
|
|
1706
|
+
const networks = splitCommaList2(opts.networks);
|
|
1707
|
+
const methods = splitCommaList2(opts.methods);
|
|
1708
|
+
const requestTypes = splitCommaList2(opts.requestTypes);
|
|
1709
|
+
const groupBy = splitCommaList2(opts.groupBy);
|
|
1710
|
+
assertAllowedValues(metrics, VALID_METRICS, "--metrics");
|
|
1711
|
+
assertAllowedValues(requestTypes, VALID_REQUEST_TYPES, "--request-types");
|
|
1712
|
+
assertAllowedValues(groupBy, VALID_GROUP_BY, "--group-by");
|
|
1713
|
+
if (groupBy && groupBy.length > 1) {
|
|
1714
|
+
throw errInvalidArgs("--group-by accepts at most one dimension.");
|
|
1715
|
+
}
|
|
1716
|
+
const granularity = opts.granularity ?? "day";
|
|
1717
|
+
if (granularity !== "day" && granularity !== "hour") {
|
|
1718
|
+
throw errInvalidArgs("--granularity must be 'hour' or 'day'.");
|
|
1719
|
+
}
|
|
1720
|
+
const filters = {
|
|
1721
|
+
...appIds && { appIds },
|
|
1722
|
+
...networks && { networks },
|
|
1723
|
+
...methods && { methods },
|
|
1724
|
+
...requestTypes && { requestTypes }
|
|
1725
|
+
};
|
|
1726
|
+
return {
|
|
1727
|
+
startTime,
|
|
1728
|
+
endTime,
|
|
1729
|
+
granularity,
|
|
1730
|
+
...products && { products },
|
|
1731
|
+
...metrics && { metrics },
|
|
1732
|
+
...Object.keys(filters).length > 0 && { filters },
|
|
1733
|
+
...groupBy && { groupBy }
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
function printUsageResult(result) {
|
|
1737
|
+
if (isJSONMode()) {
|
|
1738
|
+
printJSON(result);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
printSyntaxJSON(result);
|
|
1742
|
+
}
|
|
1743
|
+
function printUsageTimeseriesResult(result) {
|
|
1744
|
+
if (isJSONMode()) {
|
|
1745
|
+
printJSON(result);
|
|
1746
|
+
return;
|
|
1747
|
+
}
|
|
1748
|
+
const formatted = formatUsageTimeSeriesResult(result);
|
|
1749
|
+
if (formatted) {
|
|
1750
|
+
printHuman(formatted, result);
|
|
1751
|
+
return;
|
|
1752
|
+
}
|
|
1753
|
+
printSyntaxJSON(result);
|
|
1754
|
+
}
|
|
1755
|
+
function registerUsage(program2) {
|
|
1756
|
+
const cmd = program2.command("usage").description("View Alchemy usage data (alpha)").addHelpText(
|
|
1757
|
+
"after",
|
|
1758
|
+
() => (
|
|
1759
|
+
// Skip in JSON help mode so structured output stays valid JSON.
|
|
1760
|
+
isJSONMode() ? "" : [
|
|
1761
|
+
"",
|
|
1762
|
+
"Alpha: the Usage API is in early access. The response shape may",
|
|
1763
|
+
"change, and access is limited to teams enrolled in the alpha."
|
|
1764
|
+
].join("\n")
|
|
1765
|
+
)
|
|
1766
|
+
);
|
|
1767
|
+
cmd.command("summary").description("Get account usage summary").addOption(debugTeamIdOption()).action(async (opts) => {
|
|
1768
|
+
try {
|
|
1769
|
+
const admin = adminClientFromFlags(program2);
|
|
1770
|
+
const usageOptions = buildUsageRequestOptions(opts);
|
|
1771
|
+
const result = await withSpinner(
|
|
1772
|
+
"Fetching usage summary...",
|
|
1773
|
+
"Usage summary fetched",
|
|
1774
|
+
() => usageOptions ? admin.getUsageSummary(usageOptions) : admin.getUsageSummary()
|
|
1775
|
+
);
|
|
1776
|
+
printUsageResult(result);
|
|
1777
|
+
} catch (err) {
|
|
1778
|
+
exitWithError(err);
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
cmd.command("timeseries").alias("time-series").description("Get account usage time series data").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--start-time <datetime>", "Start time as an ISO datetime").option("--end-time <datetime>", "End time as an ISO datetime").option("--products <products>", "Comma-separated BillingProduct enum names").option("--metrics <metrics>", "Comma-separated metrics: amount,usd").option("--app-ids <ids>", "Filter by app IDs (comma-separated)").option(
|
|
1782
|
+
"--networks <networks>",
|
|
1783
|
+
"Filter by networks (comma-separated), e.g. eth-mainnet,base-mainnet"
|
|
1784
|
+
).option("--methods <methods>", "Filter by methods (comma-separated), e.g. eth_getLogs").option(
|
|
1785
|
+
"--request-types <types>",
|
|
1786
|
+
"Filter by request types (comma-separated): http, websocket, webhook, grpc"
|
|
1787
|
+
).option(
|
|
1788
|
+
"--group-by <dimension>",
|
|
1789
|
+
"Group by one dimension: requestType, app, network, method"
|
|
1790
|
+
).option("--granularity <granularity>", "Granularity: hour or day (default day)").option("--body <json>", "Raw time series request JSON body").addOption(debugTeamIdOption()).addHelpText(
|
|
1791
|
+
"after",
|
|
1792
|
+
() => (
|
|
1793
|
+
// Skip in JSON help mode so the structured output stays valid JSON.
|
|
1794
|
+
isJSONMode() ? "" : [
|
|
1795
|
+
"",
|
|
1796
|
+
"Filters (optional, comma-separated, combined with AND):",
|
|
1797
|
+
" --app-ids one or more app IDs",
|
|
1798
|
+
" --networks network slugs, e.g. eth-mainnet,base-mainnet",
|
|
1799
|
+
" --methods RPC/REST methods, e.g. eth_getLogs",
|
|
1800
|
+
" --request-types http, websocket, webhook, grpc",
|
|
1801
|
+
"",
|
|
1802
|
+
"Group by (choose one dimension):",
|
|
1803
|
+
" requestType | app | network | method"
|
|
1804
|
+
].join("\n")
|
|
1805
|
+
)
|
|
1806
|
+
).action(async (opts) => {
|
|
1807
|
+
try {
|
|
1808
|
+
const admin = adminClientFromFlags(program2);
|
|
1809
|
+
const body = buildTimeseriesRequest(opts);
|
|
1810
|
+
const usageOptions = buildUsageRequestOptions(opts);
|
|
1811
|
+
const result = await withSpinner(
|
|
1812
|
+
"Fetching usage time series...",
|
|
1813
|
+
"Usage time series fetched",
|
|
1814
|
+
() => usageOptions ? admin.getUsageTimeseries(body, usageOptions) : admin.getUsageTimeseries(body)
|
|
1815
|
+
);
|
|
1816
|
+
printUsageTimeseriesResult(result);
|
|
1817
|
+
} catch (err) {
|
|
1818
|
+
exitWithError(err);
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1373
1823
|
// src/commands/wallet.ts
|
|
1374
1824
|
import { readFileSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
|
1375
1825
|
import { join, dirname } from "path";
|
|
@@ -3371,6 +3821,87 @@ function registerWebhooks(program2) {
|
|
|
3371
3821
|
});
|
|
3372
3822
|
}
|
|
3373
3823
|
|
|
3824
|
+
// ../../packages/sdk/dist/solana/index.js
|
|
3825
|
+
var SOLANA_DAS_METHODS = /* @__PURE__ */ new Set([
|
|
3826
|
+
"getAsset",
|
|
3827
|
+
"getAssetsByOwner",
|
|
3828
|
+
"searchAssets",
|
|
3829
|
+
"getTokenAccounts",
|
|
3830
|
+
"getAssets",
|
|
3831
|
+
"getAssetProof",
|
|
3832
|
+
"getAssetsByAuthority",
|
|
3833
|
+
"getAssetsByGroup",
|
|
3834
|
+
"getAssetsByCreator",
|
|
3835
|
+
"getAssetSignatures",
|
|
3836
|
+
"getNftEditions"
|
|
3837
|
+
]);
|
|
3838
|
+
var SOLANA_DAS_PAYWALL_PATTERN = /\b(free tier|payg|paid tier|paid plan|upgrade|plan does not|current plan|not available on your plan)\b/i;
|
|
3839
|
+
function isSolanaDasMethod(method) {
|
|
3840
|
+
return SOLANA_DAS_METHODS.has(method);
|
|
3841
|
+
}
|
|
3842
|
+
function solanaRpcFamilyForMethod(method) {
|
|
3843
|
+
return isSolanaDasMethod(method) ? "das" : "rpc";
|
|
3844
|
+
}
|
|
3845
|
+
function classifySolanaDasPaywallError(err) {
|
|
3846
|
+
const details = errorText(err);
|
|
3847
|
+
if (!SOLANA_DAS_PAYWALL_PATTERN.test(details)) {
|
|
3848
|
+
return void 0;
|
|
3849
|
+
}
|
|
3850
|
+
return {
|
|
3851
|
+
message: "Solana DAS request requires a paid Alchemy plan.",
|
|
3852
|
+
hint: "Upgrade your app to PAYG or use a plan with Solana DAS access at https://dashboard.alchemy.com/.",
|
|
3853
|
+
...details && { details }
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
function errorText(err) {
|
|
3857
|
+
if (err instanceof Error) {
|
|
3858
|
+
const details = stringValue(err.details);
|
|
3859
|
+
return [err.message, details].filter(Boolean).join(" ");
|
|
3860
|
+
}
|
|
3861
|
+
return String(err);
|
|
3862
|
+
}
|
|
3863
|
+
function stringValue(value) {
|
|
3864
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
// src/lib/solana-rpc.ts
|
|
3868
|
+
function errorText2(err) {
|
|
3869
|
+
if (err instanceof CLIError) {
|
|
3870
|
+
return [err.message, err.details].filter(Boolean).join(" ");
|
|
3871
|
+
}
|
|
3872
|
+
if (err instanceof Error) {
|
|
3873
|
+
return err.message;
|
|
3874
|
+
}
|
|
3875
|
+
return String(err);
|
|
3876
|
+
}
|
|
3877
|
+
function normalizeSolanaDasPaywallError(err) {
|
|
3878
|
+
if (err instanceof CLIError && err.code === ErrorCode.PAYMENT_REQUIRED) {
|
|
3879
|
+
return err;
|
|
3880
|
+
}
|
|
3881
|
+
const paywall = classifySolanaDasPaywallError(err);
|
|
3882
|
+
if (!paywall) {
|
|
3883
|
+
return null;
|
|
3884
|
+
}
|
|
3885
|
+
return new CLIError(
|
|
3886
|
+
ErrorCode.PAYMENT_REQUIRED,
|
|
3887
|
+
paywall.message,
|
|
3888
|
+
paywall.hint,
|
|
3889
|
+
paywall.details
|
|
3890
|
+
);
|
|
3891
|
+
}
|
|
3892
|
+
async function callSolana(client, family, method, params) {
|
|
3893
|
+
const startedAt = Date.now();
|
|
3894
|
+
debug(`solana ${family} ${method} params`, params);
|
|
3895
|
+
try {
|
|
3896
|
+
const result = await client.call(method, params);
|
|
3897
|
+
debug(`solana ${family} ${method} ok ${Date.now() - startedAt}ms`);
|
|
3898
|
+
return result;
|
|
3899
|
+
} catch (err) {
|
|
3900
|
+
debug(`solana ${family} ${method} failed ${Date.now() - startedAt}ms`, errorText2(err));
|
|
3901
|
+
throw err;
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
|
|
3374
3905
|
// src/commands/network.ts
|
|
3375
3906
|
function registerNetwork(program2) {
|
|
3376
3907
|
const cmd = program2.command("network").description("Manage networks");
|
|
@@ -5778,6 +6309,49 @@ var PortfolioApiClient = class {
|
|
|
5778
6309
|
return dataPost(portfolioBaseUrl(this.options), this.apiKey, path, body, this.options);
|
|
5779
6310
|
}
|
|
5780
6311
|
};
|
|
6312
|
+
var PORTFOLIO_BALANCE_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
6313
|
+
"balance",
|
|
6314
|
+
"tokenbalance",
|
|
6315
|
+
"rawbalance",
|
|
6316
|
+
"rawtokenbalance",
|
|
6317
|
+
"amount"
|
|
6318
|
+
]);
|
|
6319
|
+
function limitPortfolioPayload(value, limit) {
|
|
6320
|
+
if (limit === void 0)
|
|
6321
|
+
return value;
|
|
6322
|
+
if (Array.isArray(value)) {
|
|
6323
|
+
return value.slice(0, limit).map((item) => limitPortfolioPayload(item, limit));
|
|
6324
|
+
}
|
|
6325
|
+
if (isRecord(value)) {
|
|
6326
|
+
return Object.fromEntries(Object.entries(value).map(([key, nested]) => [
|
|
6327
|
+
key,
|
|
6328
|
+
limitPortfolioPayload(nested, limit)
|
|
6329
|
+
]));
|
|
6330
|
+
}
|
|
6331
|
+
return value;
|
|
6332
|
+
}
|
|
6333
|
+
function normalizePortfolioOutput(value) {
|
|
6334
|
+
if (Array.isArray(value)) {
|
|
6335
|
+
return value.map(normalizePortfolioOutput);
|
|
6336
|
+
}
|
|
6337
|
+
if (!isRecord(value)) {
|
|
6338
|
+
return value;
|
|
6339
|
+
}
|
|
6340
|
+
const decimals = decimalsForRecord(value);
|
|
6341
|
+
const output = {};
|
|
6342
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
6343
|
+
output[key] = normalizePortfolioOutput(nested);
|
|
6344
|
+
if (typeof nested !== "string" || !shouldNormalizeBalanceField(key) || !isHexQuantity(nested)) {
|
|
6345
|
+
continue;
|
|
6346
|
+
}
|
|
6347
|
+
const raw = BigInt(nested);
|
|
6348
|
+
output[`${key}Decimal`] = raw.toString();
|
|
6349
|
+
if (decimals !== void 0) {
|
|
6350
|
+
output[`${key}Formatted`] = formatRawAmount(raw, decimals);
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
return output;
|
|
6354
|
+
}
|
|
5781
6355
|
async function dataFetch(url, method, body, options) {
|
|
5782
6356
|
const fetchFn = options.fetchFn ?? fetch;
|
|
5783
6357
|
const resp = await fetchFn(url, {
|
|
@@ -5796,6 +6370,48 @@ async function dataFetch(url, method, body, options) {
|
|
|
5796
6370
|
}
|
|
5797
6371
|
return resp;
|
|
5798
6372
|
}
|
|
6373
|
+
function isRecord(value) {
|
|
6374
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6375
|
+
}
|
|
6376
|
+
function isHexQuantity(value) {
|
|
6377
|
+
return /^0x[0-9a-f]+$/i.test(value);
|
|
6378
|
+
}
|
|
6379
|
+
function parseDecimals2(value) {
|
|
6380
|
+
const decimals = typeof value === "number" ? value : typeof value === "string" && /^\d+$/.test(value) ? Number(value) : void 0;
|
|
6381
|
+
if (decimals === void 0 || !Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
|
|
6382
|
+
return void 0;
|
|
6383
|
+
}
|
|
6384
|
+
return decimals;
|
|
6385
|
+
}
|
|
6386
|
+
function decimalsForRecord(value) {
|
|
6387
|
+
const direct = parseDecimals2(value.decimals);
|
|
6388
|
+
if (direct !== void 0)
|
|
6389
|
+
return direct;
|
|
6390
|
+
for (const key of ["tokenMetadata", "metadata", "token"]) {
|
|
6391
|
+
const nested = value[key];
|
|
6392
|
+
if (isRecord(nested)) {
|
|
6393
|
+
const decimals = parseDecimals2(nested.decimals);
|
|
6394
|
+
if (decimals !== void 0)
|
|
6395
|
+
return decimals;
|
|
6396
|
+
}
|
|
6397
|
+
}
|
|
6398
|
+
return void 0;
|
|
6399
|
+
}
|
|
6400
|
+
function formatRawAmount(raw, decimals) {
|
|
6401
|
+
if (decimals === 0)
|
|
6402
|
+
return raw.toString();
|
|
6403
|
+
const divisor = 10n ** BigInt(decimals);
|
|
6404
|
+
const whole = raw / divisor;
|
|
6405
|
+
const fraction = raw % divisor;
|
|
6406
|
+
if (fraction === 0n)
|
|
6407
|
+
return whole.toString();
|
|
6408
|
+
const fractionText = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
6409
|
+
return `${whole}.${fractionText}`;
|
|
6410
|
+
}
|
|
6411
|
+
function shouldNormalizeBalanceField(key) {
|
|
6412
|
+
const normalized = key.toLowerCase();
|
|
6413
|
+
return PORTFOLIO_BALANCE_FIELD_NAMES.has(normalized) || normalized.endsWith("balance");
|
|
6414
|
+
}
|
|
5799
6415
|
|
|
5800
6416
|
// ../../packages/sdk/dist/surfaces/index.js
|
|
5801
6417
|
var RPC_API_SURFACE = [
|
|
@@ -6020,7 +6636,7 @@ function registerRpcSurfaceCommand({ root, parent, method }) {
|
|
|
6020
6636
|
result = await withSpinner(
|
|
6021
6637
|
`Calling ${method.name}...`,
|
|
6022
6638
|
`Called ${method.name}`,
|
|
6023
|
-
() => client
|
|
6639
|
+
() => callNetworkRpcMethod(client, method, params)
|
|
6024
6640
|
);
|
|
6025
6641
|
}
|
|
6026
6642
|
printSyntaxJSON(result);
|
|
@@ -6029,6 +6645,20 @@ function registerRpcSurfaceCommand({ root, parent, method }) {
|
|
|
6029
6645
|
}
|
|
6030
6646
|
});
|
|
6031
6647
|
}
|
|
6648
|
+
async function callNetworkRpcMethod(client, method, params) {
|
|
6649
|
+
if (method.family !== "solana") {
|
|
6650
|
+
return await client.call(method.rpcMethod, params);
|
|
6651
|
+
}
|
|
6652
|
+
const solanaFamily = solanaRpcFamilyForMethod(method.rpcMethod);
|
|
6653
|
+
try {
|
|
6654
|
+
return await callSolana(client, solanaFamily, method.rpcMethod, params);
|
|
6655
|
+
} catch (err) {
|
|
6656
|
+
if (solanaFamily === "das") {
|
|
6657
|
+
throw normalizeSolanaDasPaywallError(err) ?? err;
|
|
6658
|
+
}
|
|
6659
|
+
throw err;
|
|
6660
|
+
}
|
|
6661
|
+
}
|
|
6032
6662
|
function parseRpcParams(input) {
|
|
6033
6663
|
const parsed = parseRequiredJSON(input, "--params");
|
|
6034
6664
|
if (Array.isArray(parsed)) {
|
|
@@ -6141,7 +6771,7 @@ function registerSolana(program2) {
|
|
|
6141
6771
|
const result = await withSpinner(
|
|
6142
6772
|
`Calling ${method}\u2026`,
|
|
6143
6773
|
`Called ${method}`,
|
|
6144
|
-
() => client
|
|
6774
|
+
() => callSolana(client, "rpc", method, parseCLIParams(params))
|
|
6145
6775
|
);
|
|
6146
6776
|
printSyntaxJSON(result);
|
|
6147
6777
|
} catch (err) {
|
|
@@ -6158,7 +6788,9 @@ function registerSolana(program2) {
|
|
|
6158
6788
|
const result = await withSpinner(
|
|
6159
6789
|
`Calling ${method}\u2026`,
|
|
6160
6790
|
`Called ${method}`,
|
|
6161
|
-
() => client
|
|
6791
|
+
() => callSolana(client, "das", method, rpcParams).catch((err) => {
|
|
6792
|
+
throw normalizeSolanaDasPaywallError(err) ?? err;
|
|
6793
|
+
})
|
|
6162
6794
|
);
|
|
6163
6795
|
printSyntaxJSON(result);
|
|
6164
6796
|
} catch (err) {
|
|
@@ -6308,7 +6940,7 @@ var AGENT_PROMPT_SCOPES = [
|
|
|
6308
6940
|
"xchain"
|
|
6309
6941
|
];
|
|
6310
6942
|
var SCOPE_COMMAND_PATHS = {
|
|
6311
|
-
app: ["app", "auth", "config"],
|
|
6943
|
+
app: ["app", "usage", "auth", "config"],
|
|
6312
6944
|
data: ["evm data", "evm logs", "evm block", "evm tx", "evm receipt"],
|
|
6313
6945
|
evm: ["evm"],
|
|
6314
6946
|
solana: ["solana"],
|
|
@@ -6325,7 +6957,7 @@ var SCOPE_COMMAND_PATHS = {
|
|
|
6325
6957
|
xchain: ["xchain"]
|
|
6326
6958
|
};
|
|
6327
6959
|
var SCOPE_EXAMPLE_MATCHERS = {
|
|
6328
|
-
app: [" app ", " auth ", " config "],
|
|
6960
|
+
app: [" app ", " usage ", " auth ", " config "],
|
|
6329
6961
|
data: [" evm data ", " evm logs ", " evm block ", " evm tx ", " evm receipt "],
|
|
6330
6962
|
evm: [" evm "],
|
|
6331
6963
|
solana: [" solana "],
|
|
@@ -6371,7 +7003,7 @@ function buildCommandSchema(cmd) {
|
|
|
6371
7003
|
required: a.required
|
|
6372
7004
|
}));
|
|
6373
7005
|
}
|
|
6374
|
-
const opts = cmd
|
|
7006
|
+
const opts = visibleOptions(cmd);
|
|
6375
7007
|
if (opts.length > 0) {
|
|
6376
7008
|
schema.options = opts.map((o) => ({
|
|
6377
7009
|
flags: o.flags,
|
|
@@ -6386,6 +7018,11 @@ function buildCommandSchema(cmd) {
|
|
|
6386
7018
|
}
|
|
6387
7019
|
return schema;
|
|
6388
7020
|
}
|
|
7021
|
+
function visibleOptions(cmd) {
|
|
7022
|
+
return cmd.options.filter((option) => {
|
|
7023
|
+
return !option.hidden;
|
|
7024
|
+
});
|
|
7025
|
+
}
|
|
6389
7026
|
function commandMatchesPath(cmd, path) {
|
|
6390
7027
|
if (path[0] !== cmd.name) return null;
|
|
6391
7028
|
if (path.length === 1) return cmd;
|
|
@@ -6437,6 +7074,7 @@ function applyScope(payload, scope) {
|
|
|
6437
7074
|
);
|
|
6438
7075
|
}
|
|
6439
7076
|
function buildAgentPrompt(program2) {
|
|
7077
|
+
const hasUsageCommand = program2.commands.some((cmd) => cmd.name() === "usage");
|
|
6440
7078
|
const errors = {};
|
|
6441
7079
|
for (const [code, exitCode] of Object.entries(EXIT_CODES)) {
|
|
6442
7080
|
errors[code] = {
|
|
@@ -6446,6 +7084,24 @@ function buildAgentPrompt(program2) {
|
|
|
6446
7084
|
};
|
|
6447
7085
|
}
|
|
6448
7086
|
const commands = program2.commands.filter((cmd) => cmd.name() !== "agent-prompt").map(buildCommandSchema);
|
|
7087
|
+
const examples = [
|
|
7088
|
+
"alchemy --json --no-interactive config status",
|
|
7089
|
+
"alchemy --json --no-interactive update-check",
|
|
7090
|
+
"alchemy --json --no-interactive evm data balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
7091
|
+
"alchemy --json --no-interactive app list",
|
|
7092
|
+
...hasUsageCommand ? [
|
|
7093
|
+
"alchemy --json --no-interactive usage summary",
|
|
7094
|
+
"alchemy --json --no-interactive usage timeseries --start-date 2026-06-01 --end-date 2026-06-08"
|
|
7095
|
+
] : [],
|
|
7096
|
+
"alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
7097
|
+
"alchemy --json --no-interactive evm network list",
|
|
7098
|
+
"alchemy --json --no-interactive evm send 0xRecipient 0.001 --dry-run -n eth-sepolia",
|
|
7099
|
+
`alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
|
|
7100
|
+
"alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n eth-mainnet",
|
|
7101
|
+
"alchemy --json --no-interactive evm logs --from-block latest --limit 25 -n eth-mainnet",
|
|
7102
|
+
"alchemy --json --no-interactive evm block latest --summary -n eth-mainnet",
|
|
7103
|
+
"alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
|
|
7104
|
+
];
|
|
6449
7105
|
return {
|
|
6450
7106
|
executionPolicy: [
|
|
6451
7107
|
"Always pass --json --no-interactive",
|
|
@@ -6515,9 +7171,15 @@ function buildAgentPrompt(program2) {
|
|
|
6515
7171
|
},
|
|
6516
7172
|
{
|
|
6517
7173
|
method: "Alchemy login",
|
|
7174
|
+
envVar: "ALCHEMY_AUTH_TOKEN",
|
|
6518
7175
|
setup: "alchemy auth login",
|
|
6519
|
-
commandFamilies: [
|
|
6520
|
-
|
|
7176
|
+
commandFamilies: [
|
|
7177
|
+
"app",
|
|
7178
|
+
...hasUsageCommand ? ["usage"] : [],
|
|
7179
|
+
"evm network",
|
|
7180
|
+
"gas-manager"
|
|
7181
|
+
],
|
|
7182
|
+
notes: "Admin surfaces use the browser login session stored by `alchemy auth login`, or `ALCHEMY_AUTH_TOKEN` when set."
|
|
6521
7183
|
},
|
|
6522
7184
|
{
|
|
6523
7185
|
method: "Webhook API key",
|
|
@@ -6571,20 +7233,7 @@ function buildAgentPrompt(program2) {
|
|
|
6571
7233
|
],
|
|
6572
7234
|
commands,
|
|
6573
7235
|
errors,
|
|
6574
|
-
examples
|
|
6575
|
-
"alchemy --json --no-interactive config status",
|
|
6576
|
-
"alchemy --json --no-interactive update-check",
|
|
6577
|
-
"alchemy --json --no-interactive evm data balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
6578
|
-
"alchemy --json --no-interactive app list",
|
|
6579
|
-
"alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
6580
|
-
"alchemy --json --no-interactive evm network list",
|
|
6581
|
-
"alchemy --json --no-interactive evm send 0xRecipient 0.001 --dry-run -n eth-sepolia",
|
|
6582
|
-
`alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
|
|
6583
|
-
"alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n eth-mainnet",
|
|
6584
|
-
"alchemy --json --no-interactive evm logs --from-block latest --limit 25 -n eth-mainnet",
|
|
6585
|
-
"alchemy --json --no-interactive evm block latest --summary -n eth-mainnet",
|
|
6586
|
-
"alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
|
|
6587
|
-
],
|
|
7236
|
+
examples,
|
|
6588
7237
|
docs: "https://www.alchemy.com/docs"
|
|
6589
7238
|
};
|
|
6590
7239
|
}
|
|
@@ -6807,7 +7456,7 @@ function registrySymbolSuggestions(network) {
|
|
|
6807
7456
|
}
|
|
6808
7457
|
|
|
6809
7458
|
// src/lib/preflight-errors.ts
|
|
6810
|
-
function
|
|
7459
|
+
function errorText3(err) {
|
|
6811
7460
|
if (err instanceof CLIError) {
|
|
6812
7461
|
return [err.message, err.details].filter(Boolean).join(" ");
|
|
6813
7462
|
}
|
|
@@ -6842,7 +7491,7 @@ function normalizePreflightRevertError(err) {
|
|
|
6842
7491
|
if (err instanceof CLIError && err.code === ErrorCode.PREFLIGHT_REVERT) {
|
|
6843
7492
|
return err;
|
|
6844
7493
|
}
|
|
6845
|
-
const detail =
|
|
7494
|
+
const detail = errorText3(err);
|
|
6846
7495
|
const reason = extractRevertReason(detail);
|
|
6847
7496
|
if (!reason) return null;
|
|
6848
7497
|
return errPreflightRevert(reason, detail || void 0);
|
|
@@ -8188,25 +8837,10 @@ async function runDataCall(program2, title, path, body) {
|
|
|
8188
8837
|
() => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
|
|
8189
8838
|
);
|
|
8190
8839
|
}
|
|
8191
|
-
function limitPayload(value, limit) {
|
|
8192
|
-
if (limit === void 0) return value;
|
|
8193
|
-
if (Array.isArray(value)) {
|
|
8194
|
-
return value.slice(0, limit);
|
|
8195
|
-
}
|
|
8196
|
-
if (value && typeof value === "object") {
|
|
8197
|
-
return Object.fromEntries(
|
|
8198
|
-
Object.entries(value).map(([key, nested]) => [
|
|
8199
|
-
key,
|
|
8200
|
-
Array.isArray(nested) ? nested.slice(0, limit) : nested
|
|
8201
|
-
])
|
|
8202
|
-
);
|
|
8203
|
-
}
|
|
8204
|
-
return value;
|
|
8205
|
-
}
|
|
8206
8840
|
async function runPortfolioCommand(program2, title, path, opts) {
|
|
8207
8841
|
const limit = parseOptionalInt(opts.limit, "--limit");
|
|
8208
8842
|
const result = await runDataCall(program2, title, path, JSON.parse(opts.body));
|
|
8209
|
-
const output =
|
|
8843
|
+
const output = normalizePortfolioOutput(limitPortfolioPayload(result, limit));
|
|
8210
8844
|
if (isJSONMode()) printJSON(output);
|
|
8211
8845
|
else printSyntaxJSON(output);
|
|
8212
8846
|
}
|
|
@@ -8864,7 +9498,7 @@ function buildWalletQuoteClient(program2, address3) {
|
|
|
8864
9498
|
}
|
|
8865
9499
|
|
|
8866
9500
|
// src/lib/quote-errors.ts
|
|
8867
|
-
function
|
|
9501
|
+
function errorText4(err) {
|
|
8868
9502
|
if (err instanceof CLIError) {
|
|
8869
9503
|
return [err.message, err.details].filter(Boolean).join(" ");
|
|
8870
9504
|
}
|
|
@@ -8922,7 +9556,7 @@ function normalizeQuoteError(err, flow) {
|
|
|
8922
9556
|
if (err instanceof CLIError && err.code !== ErrorCode.RPC_ERROR && err.code !== ErrorCode.INTERNAL_ERROR) {
|
|
8923
9557
|
return err;
|
|
8924
9558
|
}
|
|
8925
|
-
const detail =
|
|
9559
|
+
const detail = errorText4(err);
|
|
8926
9560
|
const cause = classifyQuoteFailure(detail);
|
|
8927
9561
|
return new CLIError(
|
|
8928
9562
|
ErrorCode.QUOTE_FAILED,
|
|
@@ -9962,7 +10596,7 @@ function displayPath(path) {
|
|
|
9962
10596
|
const home = getHomeDir();
|
|
9963
10597
|
return path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
9964
10598
|
}
|
|
9965
|
-
function
|
|
10599
|
+
function isRecord2(value) {
|
|
9966
10600
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9967
10601
|
}
|
|
9968
10602
|
function isClientId(value) {
|
|
@@ -10149,7 +10783,7 @@ async function readJSONConfig(path) {
|
|
|
10149
10783
|
const raw = await readFile(path, "utf8");
|
|
10150
10784
|
if (raw.trim().length === 0) return {};
|
|
10151
10785
|
const parsed = JSON.parse(raw);
|
|
10152
|
-
if (!
|
|
10786
|
+
if (!isRecord2(parsed)) {
|
|
10153
10787
|
throw errInvalidArgs(`${displayPath(path)} must contain a JSON object.`);
|
|
10154
10788
|
}
|
|
10155
10789
|
return parsed;
|
|
@@ -10163,7 +10797,7 @@ async function readJSONConfig(path) {
|
|
|
10163
10797
|
}
|
|
10164
10798
|
function withMcpServerConfig(config) {
|
|
10165
10799
|
const existing = config.mcpServers;
|
|
10166
|
-
if (existing !== void 0 && !
|
|
10800
|
+
if (existing !== void 0 && !isRecord2(existing)) {
|
|
10167
10801
|
throw errInvalidArgs("Cursor mcpServers must be a JSON object.");
|
|
10168
10802
|
}
|
|
10169
10803
|
return {
|
|
@@ -10511,7 +11145,7 @@ var ROOT_COMMAND_PILLARS = [
|
|
|
10511
11145
|
},
|
|
10512
11146
|
{
|
|
10513
11147
|
label: "Account & Platform",
|
|
10514
|
-
commands: ["auth", "wallet", "app", "webhook", "config"]
|
|
11148
|
+
commands: ["auth", "wallet", "app", "usage", "webhook", "config"]
|
|
10515
11149
|
},
|
|
10516
11150
|
{
|
|
10517
11151
|
label: "Utilities",
|
|
@@ -10545,7 +11179,12 @@ function rootOptionGroupLabel(flags) {
|
|
|
10545
11179
|
}
|
|
10546
11180
|
return "General";
|
|
10547
11181
|
}
|
|
10548
|
-
|
|
11182
|
+
function visibleOptions2(cmd) {
|
|
11183
|
+
return cmd.options.filter((option) => {
|
|
11184
|
+
return !option.hidden;
|
|
11185
|
+
});
|
|
11186
|
+
}
|
|
11187
|
+
var program = new Command2();
|
|
10549
11188
|
var argvTokens = process.argv.slice(2);
|
|
10550
11189
|
var isHelpInvocation = argvTokens.some(
|
|
10551
11190
|
(token) => token === "help" || token === "--help" || token === "-h"
|
|
@@ -10561,6 +11200,16 @@ var findCommandByPath = (root, path) => {
|
|
|
10561
11200
|
}
|
|
10562
11201
|
return current;
|
|
10563
11202
|
};
|
|
11203
|
+
var commandPathIncludes = (command, names) => {
|
|
11204
|
+
let current = command;
|
|
11205
|
+
while (current) {
|
|
11206
|
+
if (names.has(current.name())) {
|
|
11207
|
+
return true;
|
|
11208
|
+
}
|
|
11209
|
+
current = current.parent ?? null;
|
|
11210
|
+
}
|
|
11211
|
+
return false;
|
|
11212
|
+
};
|
|
10564
11213
|
var cachedAvailableUpdate;
|
|
10565
11214
|
var updateShownDuringInteractiveStartup = false;
|
|
10566
11215
|
function getAvailableUpdateOnce() {
|
|
@@ -10581,7 +11230,7 @@ async function flushProcessOutput() {
|
|
|
10581
11230
|
}
|
|
10582
11231
|
program.name("alchemy").description(
|
|
10583
11232
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
10584
|
-
).version("0.
|
|
11233
|
+
).version("0.16.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
10585
11234
|
"-n, --network <network>",
|
|
10586
11235
|
"Target network for networked commands"
|
|
10587
11236
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -10619,7 +11268,7 @@ program.name("alchemy").description(
|
|
|
10619
11268
|
required: a.required
|
|
10620
11269
|
}));
|
|
10621
11270
|
}
|
|
10622
|
-
const opts = cmd
|
|
11271
|
+
const opts = visibleOptions2(cmd);
|
|
10623
11272
|
if (opts.length > 0) {
|
|
10624
11273
|
schema.options = opts.map((o) => ({
|
|
10625
11274
|
flags: o.flags,
|
|
@@ -10754,11 +11403,11 @@ ${styledLine}`;
|
|
|
10754
11403
|
reveal: Boolean(opts.reveal),
|
|
10755
11404
|
timeout: opts.timeout
|
|
10756
11405
|
});
|
|
10757
|
-
const
|
|
10758
|
-
const skipAppPrompt = [
|
|
11406
|
+
const skipAppPrompt = /* @__PURE__ */ new Set([
|
|
10759
11407
|
"auth",
|
|
10760
11408
|
"config",
|
|
10761
11409
|
"help",
|
|
11410
|
+
"usage",
|
|
10762
11411
|
"version",
|
|
10763
11412
|
"completions",
|
|
10764
11413
|
"agent-prompt",
|
|
@@ -10766,13 +11415,13 @@ ${styledLine}`;
|
|
|
10766
11415
|
"install",
|
|
10767
11416
|
"update-check",
|
|
10768
11417
|
"wallet"
|
|
10769
|
-
];
|
|
10770
|
-
if (!skipAppPrompt
|
|
10771
|
-
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-
|
|
11418
|
+
]);
|
|
11419
|
+
if (!commandPathIncludes(actionCommand, skipAppPrompt) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
|
|
11420
|
+
const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-B64J4LR6.js");
|
|
10772
11421
|
const authToken = resolveAuthToken2(cfg);
|
|
10773
11422
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
10774
11423
|
if (authToken && !hasApiKey) {
|
|
10775
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
11424
|
+
const { selectAppAfterAuth } = await import("./auth-JHVDOG26.js");
|
|
10776
11425
|
console.log("");
|
|
10777
11426
|
console.log(` No app selected. Please select an app to continue.`);
|
|
10778
11427
|
await selectAppAfterAuth(authToken);
|
|
@@ -10807,7 +11456,7 @@ ${styledLine}`;
|
|
|
10807
11456
|
if (isInteractiveAllowed(program)) {
|
|
10808
11457
|
let latestForInteractiveStartup = null;
|
|
10809
11458
|
if (shouldRunOnboarding(program, cfg)) {
|
|
10810
|
-
const { runOnboarding } = await import("./onboarding-
|
|
11459
|
+
const { runOnboarding } = await import("./onboarding-47TK4HNM.js");
|
|
10811
11460
|
const latest = getAvailableUpdateOnce();
|
|
10812
11461
|
const completed = await runOnboarding(program, latest);
|
|
10813
11462
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -10821,7 +11470,7 @@ ${styledLine}`;
|
|
|
10821
11470
|
latestForInteractiveStartup
|
|
10822
11471
|
);
|
|
10823
11472
|
}
|
|
10824
|
-
const { startREPL } = await import("./interactive-
|
|
11473
|
+
const { startREPL } = await import("./interactive-PQGRT27R.js");
|
|
10825
11474
|
program.exitOverride();
|
|
10826
11475
|
program.configureOutput({
|
|
10827
11476
|
writeErr: () => {
|
|
@@ -10838,6 +11487,7 @@ registerXchain(program);
|
|
|
10838
11487
|
registerWallets(program);
|
|
10839
11488
|
registerGasManager(program);
|
|
10840
11489
|
registerApps(program);
|
|
11490
|
+
registerUsage(program);
|
|
10841
11491
|
registerWebhooks(program);
|
|
10842
11492
|
registerAuth(program);
|
|
10843
11493
|
registerConfig(program);
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
getSetupMethod
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Q2VRERYE.js";
|
|
6
6
|
import "./chunk-EJB4WDTU.js";
|
|
7
7
|
import {
|
|
8
8
|
getRPCNetworkIds
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-FFQ7XKW7.js";
|
|
10
10
|
import {
|
|
11
11
|
getUpdateNoticeLines
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-N422J6U3.js";
|
|
13
13
|
import {
|
|
14
14
|
bold,
|
|
15
15
|
brand,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
dim,
|
|
18
18
|
green,
|
|
19
19
|
setBrandedHelpSuppressed
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GJL52AFY.js";
|
|
21
21
|
import {
|
|
22
22
|
configDir,
|
|
23
23
|
load
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
getUpdateNoticeLines
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-N422J6U3.js";
|
|
6
6
|
import {
|
|
7
7
|
bold,
|
|
8
8
|
brand,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
dim,
|
|
11
11
|
green,
|
|
12
12
|
promptText
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-GJL52AFY.js";
|
|
14
14
|
import {
|
|
15
15
|
load,
|
|
16
16
|
save
|
|
@@ -51,7 +51,7 @@ async function runOnboarding(_program, latestUpdate = null) {
|
|
|
51
51
|
auth_token_expires_at: result.expiresAt
|
|
52
52
|
});
|
|
53
53
|
console.log(` ${green("\u2713")} Logged in successfully`);
|
|
54
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
54
|
+
const { selectAppAfterAuth } = await import("./auth-JHVDOG26.js");
|
|
55
55
|
await selectAppAfterAuth(result.token);
|
|
56
56
|
return true;
|
|
57
57
|
} catch (err) {
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
errNotLoggedInForPolicyLookup,
|
|
6
6
|
errSponsorshipNeedsPolicy,
|
|
7
7
|
selectOrCreatePolicy
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-HPRJEGSP.js";
|
|
9
|
+
import "./chunk-FFQ7XKW7.js";
|
|
10
|
+
import "./chunk-GJL52AFY.js";
|
|
11
11
|
import "./chunk-PISUI34T.js";
|
|
12
12
|
import "./chunk-CFIDLPKB.js";
|
|
13
13
|
export {
|