@alchemy/cli 0.15.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-UL5ZSWTE.js → chunk-N422J6U3.js} +1 -1
- package/dist/{chunk-RQDWIB62.js → chunk-Q2VRERYE.js} +1 -1
- package/dist/index.js +653 -140
- package/dist/{interactive-3ACOLHPG.js → interactive-PQGRT27R.js} +4 -4
- package/dist/{onboarding-L2FTZRYN.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,7 +3821,7 @@ function registerWebhooks(program2) {
|
|
|
3371
3821
|
});
|
|
3372
3822
|
}
|
|
3373
3823
|
|
|
3374
|
-
//
|
|
3824
|
+
// ../../packages/sdk/dist/solana/index.js
|
|
3375
3825
|
var SOLANA_DAS_METHODS = /* @__PURE__ */ new Set([
|
|
3376
3826
|
"getAsset",
|
|
3377
3827
|
"getAssetsByOwner",
|
|
@@ -3385,7 +3835,37 @@ var SOLANA_DAS_METHODS = /* @__PURE__ */ new Set([
|
|
|
3385
3835
|
"getAssetSignatures",
|
|
3386
3836
|
"getNftEditions"
|
|
3387
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
|
+
}
|
|
3388
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) {
|
|
3389
3869
|
if (err instanceof CLIError) {
|
|
3390
3870
|
return [err.message, err.details].filter(Boolean).join(" ");
|
|
3391
3871
|
}
|
|
@@ -3394,22 +3874,19 @@ function errorText(err) {
|
|
|
3394
3874
|
}
|
|
3395
3875
|
return String(err);
|
|
3396
3876
|
}
|
|
3397
|
-
function solanaRpcFamilyForMethod(method) {
|
|
3398
|
-
return SOLANA_DAS_METHODS.has(method) ? "das" : "rpc";
|
|
3399
|
-
}
|
|
3400
3877
|
function normalizeSolanaDasPaywallError(err) {
|
|
3401
3878
|
if (err instanceof CLIError && err.code === ErrorCode.PAYMENT_REQUIRED) {
|
|
3402
3879
|
return err;
|
|
3403
3880
|
}
|
|
3404
|
-
const
|
|
3405
|
-
if (
|
|
3881
|
+
const paywall = classifySolanaDasPaywallError(err);
|
|
3882
|
+
if (!paywall) {
|
|
3406
3883
|
return null;
|
|
3407
3884
|
}
|
|
3408
3885
|
return new CLIError(
|
|
3409
3886
|
ErrorCode.PAYMENT_REQUIRED,
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3887
|
+
paywall.message,
|
|
3888
|
+
paywall.hint,
|
|
3889
|
+
paywall.details
|
|
3413
3890
|
);
|
|
3414
3891
|
}
|
|
3415
3892
|
async function callSolana(client, family, method, params) {
|
|
@@ -3420,7 +3897,7 @@ async function callSolana(client, family, method, params) {
|
|
|
3420
3897
|
debug(`solana ${family} ${method} ok ${Date.now() - startedAt}ms`);
|
|
3421
3898
|
return result;
|
|
3422
3899
|
} catch (err) {
|
|
3423
|
-
debug(`solana ${family} ${method} failed ${Date.now() - startedAt}ms`,
|
|
3900
|
+
debug(`solana ${family} ${method} failed ${Date.now() - startedAt}ms`, errorText2(err));
|
|
3424
3901
|
throw err;
|
|
3425
3902
|
}
|
|
3426
3903
|
}
|
|
@@ -5832,6 +6309,49 @@ var PortfolioApiClient = class {
|
|
|
5832
6309
|
return dataPost(portfolioBaseUrl(this.options), this.apiKey, path, body, this.options);
|
|
5833
6310
|
}
|
|
5834
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
|
+
}
|
|
5835
6355
|
async function dataFetch(url, method, body, options) {
|
|
5836
6356
|
const fetchFn = options.fetchFn ?? fetch;
|
|
5837
6357
|
const resp = await fetchFn(url, {
|
|
@@ -5850,6 +6370,48 @@ async function dataFetch(url, method, body, options) {
|
|
|
5850
6370
|
}
|
|
5851
6371
|
return resp;
|
|
5852
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
|
+
}
|
|
5853
6415
|
|
|
5854
6416
|
// ../../packages/sdk/dist/surfaces/index.js
|
|
5855
6417
|
var RPC_API_SURFACE = [
|
|
@@ -6378,7 +6940,7 @@ var AGENT_PROMPT_SCOPES = [
|
|
|
6378
6940
|
"xchain"
|
|
6379
6941
|
];
|
|
6380
6942
|
var SCOPE_COMMAND_PATHS = {
|
|
6381
|
-
app: ["app", "auth", "config"],
|
|
6943
|
+
app: ["app", "usage", "auth", "config"],
|
|
6382
6944
|
data: ["evm data", "evm logs", "evm block", "evm tx", "evm receipt"],
|
|
6383
6945
|
evm: ["evm"],
|
|
6384
6946
|
solana: ["solana"],
|
|
@@ -6395,7 +6957,7 @@ var SCOPE_COMMAND_PATHS = {
|
|
|
6395
6957
|
xchain: ["xchain"]
|
|
6396
6958
|
};
|
|
6397
6959
|
var SCOPE_EXAMPLE_MATCHERS = {
|
|
6398
|
-
app: [" app ", " auth ", " config "],
|
|
6960
|
+
app: [" app ", " usage ", " auth ", " config "],
|
|
6399
6961
|
data: [" evm data ", " evm logs ", " evm block ", " evm tx ", " evm receipt "],
|
|
6400
6962
|
evm: [" evm "],
|
|
6401
6963
|
solana: [" solana "],
|
|
@@ -6441,7 +7003,7 @@ function buildCommandSchema(cmd) {
|
|
|
6441
7003
|
required: a.required
|
|
6442
7004
|
}));
|
|
6443
7005
|
}
|
|
6444
|
-
const opts = cmd
|
|
7006
|
+
const opts = visibleOptions(cmd);
|
|
6445
7007
|
if (opts.length > 0) {
|
|
6446
7008
|
schema.options = opts.map((o) => ({
|
|
6447
7009
|
flags: o.flags,
|
|
@@ -6456,6 +7018,11 @@ function buildCommandSchema(cmd) {
|
|
|
6456
7018
|
}
|
|
6457
7019
|
return schema;
|
|
6458
7020
|
}
|
|
7021
|
+
function visibleOptions(cmd) {
|
|
7022
|
+
return cmd.options.filter((option) => {
|
|
7023
|
+
return !option.hidden;
|
|
7024
|
+
});
|
|
7025
|
+
}
|
|
6459
7026
|
function commandMatchesPath(cmd, path) {
|
|
6460
7027
|
if (path[0] !== cmd.name) return null;
|
|
6461
7028
|
if (path.length === 1) return cmd;
|
|
@@ -6507,6 +7074,7 @@ function applyScope(payload, scope) {
|
|
|
6507
7074
|
);
|
|
6508
7075
|
}
|
|
6509
7076
|
function buildAgentPrompt(program2) {
|
|
7077
|
+
const hasUsageCommand = program2.commands.some((cmd) => cmd.name() === "usage");
|
|
6510
7078
|
const errors = {};
|
|
6511
7079
|
for (const [code, exitCode] of Object.entries(EXIT_CODES)) {
|
|
6512
7080
|
errors[code] = {
|
|
@@ -6516,6 +7084,24 @@ function buildAgentPrompt(program2) {
|
|
|
6516
7084
|
};
|
|
6517
7085
|
}
|
|
6518
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
|
+
];
|
|
6519
7105
|
return {
|
|
6520
7106
|
executionPolicy: [
|
|
6521
7107
|
"Always pass --json --no-interactive",
|
|
@@ -6585,9 +7171,15 @@ function buildAgentPrompt(program2) {
|
|
|
6585
7171
|
},
|
|
6586
7172
|
{
|
|
6587
7173
|
method: "Alchemy login",
|
|
7174
|
+
envVar: "ALCHEMY_AUTH_TOKEN",
|
|
6588
7175
|
setup: "alchemy auth login",
|
|
6589
|
-
commandFamilies: [
|
|
6590
|
-
|
|
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."
|
|
6591
7183
|
},
|
|
6592
7184
|
{
|
|
6593
7185
|
method: "Webhook API key",
|
|
@@ -6641,20 +7233,7 @@ function buildAgentPrompt(program2) {
|
|
|
6641
7233
|
],
|
|
6642
7234
|
commands,
|
|
6643
7235
|
errors,
|
|
6644
|
-
examples
|
|
6645
|
-
"alchemy --json --no-interactive config status",
|
|
6646
|
-
"alchemy --json --no-interactive update-check",
|
|
6647
|
-
"alchemy --json --no-interactive evm data balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
6648
|
-
"alchemy --json --no-interactive app list",
|
|
6649
|
-
"alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY -n eth-mainnet",
|
|
6650
|
-
"alchemy --json --no-interactive evm network list",
|
|
6651
|
-
"alchemy --json --no-interactive evm send 0xRecipient 0.001 --dry-run -n eth-sepolia",
|
|
6652
|
-
`alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
|
|
6653
|
-
"alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n eth-mainnet",
|
|
6654
|
-
"alchemy --json --no-interactive evm logs --from-block latest --limit 25 -n eth-mainnet",
|
|
6655
|
-
"alchemy --json --no-interactive evm block latest --summary -n eth-mainnet",
|
|
6656
|
-
"alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
|
|
6657
|
-
],
|
|
7236
|
+
examples,
|
|
6658
7237
|
docs: "https://www.alchemy.com/docs"
|
|
6659
7238
|
};
|
|
6660
7239
|
}
|
|
@@ -6877,7 +7456,7 @@ function registrySymbolSuggestions(network) {
|
|
|
6877
7456
|
}
|
|
6878
7457
|
|
|
6879
7458
|
// src/lib/preflight-errors.ts
|
|
6880
|
-
function
|
|
7459
|
+
function errorText3(err) {
|
|
6881
7460
|
if (err instanceof CLIError) {
|
|
6882
7461
|
return [err.message, err.details].filter(Boolean).join(" ");
|
|
6883
7462
|
}
|
|
@@ -6912,7 +7491,7 @@ function normalizePreflightRevertError(err) {
|
|
|
6912
7491
|
if (err instanceof CLIError && err.code === ErrorCode.PREFLIGHT_REVERT) {
|
|
6913
7492
|
return err;
|
|
6914
7493
|
}
|
|
6915
|
-
const detail =
|
|
7494
|
+
const detail = errorText3(err);
|
|
6916
7495
|
const reason = extractRevertReason(detail);
|
|
6917
7496
|
if (!reason) return null;
|
|
6918
7497
|
return errPreflightRevert(reason, detail || void 0);
|
|
@@ -8250,13 +8829,6 @@ Examples:
|
|
|
8250
8829
|
}
|
|
8251
8830
|
|
|
8252
8831
|
// src/commands/portfolio.ts
|
|
8253
|
-
var BALANCE_FIELD_NAMES = /* @__PURE__ */ new Set([
|
|
8254
|
-
"balance",
|
|
8255
|
-
"tokenbalance",
|
|
8256
|
-
"rawbalance",
|
|
8257
|
-
"rawtokenbalance",
|
|
8258
|
-
"amount"
|
|
8259
|
-
]);
|
|
8260
8832
|
async function runDataCall(program2, title, path, body) {
|
|
8261
8833
|
const x402 = resolveX402Client(program2);
|
|
8262
8834
|
return withSpinner(
|
|
@@ -8265,85 +8837,10 @@ async function runDataCall(program2, title, path, body) {
|
|
|
8265
8837
|
() => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
|
|
8266
8838
|
);
|
|
8267
8839
|
}
|
|
8268
|
-
function limitPayload(value, limit) {
|
|
8269
|
-
if (limit === void 0) return value;
|
|
8270
|
-
if (Array.isArray(value)) {
|
|
8271
|
-
return value.slice(0, limit).map((item) => limitPayload(item, limit));
|
|
8272
|
-
}
|
|
8273
|
-
if (isRecord(value)) {
|
|
8274
|
-
return Object.fromEntries(
|
|
8275
|
-
Object.entries(value).map(([key, nested]) => [
|
|
8276
|
-
key,
|
|
8277
|
-
limitPayload(nested, limit)
|
|
8278
|
-
])
|
|
8279
|
-
);
|
|
8280
|
-
}
|
|
8281
|
-
return value;
|
|
8282
|
-
}
|
|
8283
|
-
function isRecord(value) {
|
|
8284
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8285
|
-
}
|
|
8286
|
-
function isHexQuantity(value) {
|
|
8287
|
-
return /^0x[0-9a-f]+$/i.test(value);
|
|
8288
|
-
}
|
|
8289
|
-
function parseDecimals2(value) {
|
|
8290
|
-
const decimals = typeof value === "number" ? value : typeof value === "string" && /^\d+$/.test(value) ? Number(value) : void 0;
|
|
8291
|
-
if (decimals === void 0 || !Number.isInteger(decimals) || decimals < 0 || decimals > 255) {
|
|
8292
|
-
return void 0;
|
|
8293
|
-
}
|
|
8294
|
-
return decimals;
|
|
8295
|
-
}
|
|
8296
|
-
function decimalsForRecord(value) {
|
|
8297
|
-
const direct = parseDecimals2(value.decimals);
|
|
8298
|
-
if (direct !== void 0) return direct;
|
|
8299
|
-
for (const key of ["tokenMetadata", "metadata", "token"]) {
|
|
8300
|
-
const nested = value[key];
|
|
8301
|
-
if (isRecord(nested)) {
|
|
8302
|
-
const decimals = parseDecimals2(nested.decimals);
|
|
8303
|
-
if (decimals !== void 0) return decimals;
|
|
8304
|
-
}
|
|
8305
|
-
}
|
|
8306
|
-
return void 0;
|
|
8307
|
-
}
|
|
8308
|
-
function formatRawAmount(raw, decimals) {
|
|
8309
|
-
if (decimals === 0) return raw.toString();
|
|
8310
|
-
const divisor = 10n ** BigInt(decimals);
|
|
8311
|
-
const whole = raw / divisor;
|
|
8312
|
-
const fraction = raw % divisor;
|
|
8313
|
-
if (fraction === 0n) return whole.toString();
|
|
8314
|
-
const fractionText = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
8315
|
-
return `${whole}.${fractionText}`;
|
|
8316
|
-
}
|
|
8317
|
-
function shouldNormalizeBalanceField(key) {
|
|
8318
|
-
const normalized = key.toLowerCase();
|
|
8319
|
-
return BALANCE_FIELD_NAMES.has(normalized) || normalized.endsWith("balance");
|
|
8320
|
-
}
|
|
8321
|
-
function normalizePortfolioOutput(value) {
|
|
8322
|
-
if (Array.isArray(value)) {
|
|
8323
|
-
return value.map(normalizePortfolioOutput);
|
|
8324
|
-
}
|
|
8325
|
-
if (!isRecord(value)) {
|
|
8326
|
-
return value;
|
|
8327
|
-
}
|
|
8328
|
-
const decimals = decimalsForRecord(value);
|
|
8329
|
-
const output = {};
|
|
8330
|
-
for (const [key, nested] of Object.entries(value)) {
|
|
8331
|
-
output[key] = normalizePortfolioOutput(nested);
|
|
8332
|
-
if (typeof nested !== "string" || !shouldNormalizeBalanceField(key) || !isHexQuantity(nested)) {
|
|
8333
|
-
continue;
|
|
8334
|
-
}
|
|
8335
|
-
const raw = BigInt(nested);
|
|
8336
|
-
output[`${key}Decimal`] = raw.toString();
|
|
8337
|
-
if (decimals !== void 0) {
|
|
8338
|
-
output[`${key}Formatted`] = formatRawAmount(raw, decimals);
|
|
8339
|
-
}
|
|
8340
|
-
}
|
|
8341
|
-
return output;
|
|
8342
|
-
}
|
|
8343
8840
|
async function runPortfolioCommand(program2, title, path, opts) {
|
|
8344
8841
|
const limit = parseOptionalInt(opts.limit, "--limit");
|
|
8345
8842
|
const result = await runDataCall(program2, title, path, JSON.parse(opts.body));
|
|
8346
|
-
const output = normalizePortfolioOutput(
|
|
8843
|
+
const output = normalizePortfolioOutput(limitPortfolioPayload(result, limit));
|
|
8347
8844
|
if (isJSONMode()) printJSON(output);
|
|
8348
8845
|
else printSyntaxJSON(output);
|
|
8349
8846
|
}
|
|
@@ -9001,7 +9498,7 @@ function buildWalletQuoteClient(program2, address3) {
|
|
|
9001
9498
|
}
|
|
9002
9499
|
|
|
9003
9500
|
// src/lib/quote-errors.ts
|
|
9004
|
-
function
|
|
9501
|
+
function errorText4(err) {
|
|
9005
9502
|
if (err instanceof CLIError) {
|
|
9006
9503
|
return [err.message, err.details].filter(Boolean).join(" ");
|
|
9007
9504
|
}
|
|
@@ -9059,7 +9556,7 @@ function normalizeQuoteError(err, flow) {
|
|
|
9059
9556
|
if (err instanceof CLIError && err.code !== ErrorCode.RPC_ERROR && err.code !== ErrorCode.INTERNAL_ERROR) {
|
|
9060
9557
|
return err;
|
|
9061
9558
|
}
|
|
9062
|
-
const detail =
|
|
9559
|
+
const detail = errorText4(err);
|
|
9063
9560
|
const cause = classifyQuoteFailure(detail);
|
|
9064
9561
|
return new CLIError(
|
|
9065
9562
|
ErrorCode.QUOTE_FAILED,
|
|
@@ -10648,7 +11145,7 @@ var ROOT_COMMAND_PILLARS = [
|
|
|
10648
11145
|
},
|
|
10649
11146
|
{
|
|
10650
11147
|
label: "Account & Platform",
|
|
10651
|
-
commands: ["auth", "wallet", "app", "webhook", "config"]
|
|
11148
|
+
commands: ["auth", "wallet", "app", "usage", "webhook", "config"]
|
|
10652
11149
|
},
|
|
10653
11150
|
{
|
|
10654
11151
|
label: "Utilities",
|
|
@@ -10682,7 +11179,12 @@ function rootOptionGroupLabel(flags) {
|
|
|
10682
11179
|
}
|
|
10683
11180
|
return "General";
|
|
10684
11181
|
}
|
|
10685
|
-
|
|
11182
|
+
function visibleOptions2(cmd) {
|
|
11183
|
+
return cmd.options.filter((option) => {
|
|
11184
|
+
return !option.hidden;
|
|
11185
|
+
});
|
|
11186
|
+
}
|
|
11187
|
+
var program = new Command2();
|
|
10686
11188
|
var argvTokens = process.argv.slice(2);
|
|
10687
11189
|
var isHelpInvocation = argvTokens.some(
|
|
10688
11190
|
(token) => token === "help" || token === "--help" || token === "-h"
|
|
@@ -10698,6 +11200,16 @@ var findCommandByPath = (root, path) => {
|
|
|
10698
11200
|
}
|
|
10699
11201
|
return current;
|
|
10700
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
|
+
};
|
|
10701
11213
|
var cachedAvailableUpdate;
|
|
10702
11214
|
var updateShownDuringInteractiveStartup = false;
|
|
10703
11215
|
function getAvailableUpdateOnce() {
|
|
@@ -10718,7 +11230,7 @@ async function flushProcessOutput() {
|
|
|
10718
11230
|
}
|
|
10719
11231
|
program.name("alchemy").description(
|
|
10720
11232
|
"The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
|
|
10721
|
-
).version("0.
|
|
11233
|
+
).version("0.16.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
|
|
10722
11234
|
"-n, --network <network>",
|
|
10723
11235
|
"Target network for networked commands"
|
|
10724
11236
|
).option("--x402", "Use x402 wallet-based gateway auth").option(
|
|
@@ -10756,7 +11268,7 @@ program.name("alchemy").description(
|
|
|
10756
11268
|
required: a.required
|
|
10757
11269
|
}));
|
|
10758
11270
|
}
|
|
10759
|
-
const opts = cmd
|
|
11271
|
+
const opts = visibleOptions2(cmd);
|
|
10760
11272
|
if (opts.length > 0) {
|
|
10761
11273
|
schema.options = opts.map((o) => ({
|
|
10762
11274
|
flags: o.flags,
|
|
@@ -10891,11 +11403,11 @@ ${styledLine}`;
|
|
|
10891
11403
|
reveal: Boolean(opts.reveal),
|
|
10892
11404
|
timeout: opts.timeout
|
|
10893
11405
|
});
|
|
10894
|
-
const
|
|
10895
|
-
const skipAppPrompt = [
|
|
11406
|
+
const skipAppPrompt = /* @__PURE__ */ new Set([
|
|
10896
11407
|
"auth",
|
|
10897
11408
|
"config",
|
|
10898
11409
|
"help",
|
|
11410
|
+
"usage",
|
|
10899
11411
|
"version",
|
|
10900
11412
|
"completions",
|
|
10901
11413
|
"agent-prompt",
|
|
@@ -10903,13 +11415,13 @@ ${styledLine}`;
|
|
|
10903
11415
|
"install",
|
|
10904
11416
|
"update-check",
|
|
10905
11417
|
"wallet"
|
|
10906
|
-
];
|
|
10907
|
-
if (!skipAppPrompt
|
|
10908
|
-
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");
|
|
10909
11421
|
const authToken = resolveAuthToken2(cfg);
|
|
10910
11422
|
const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
|
|
10911
11423
|
if (authToken && !hasApiKey) {
|
|
10912
|
-
const { selectAppAfterAuth } = await import("./auth-
|
|
11424
|
+
const { selectAppAfterAuth } = await import("./auth-JHVDOG26.js");
|
|
10913
11425
|
console.log("");
|
|
10914
11426
|
console.log(` No app selected. Please select an app to continue.`);
|
|
10915
11427
|
await selectAppAfterAuth(authToken);
|
|
@@ -10944,7 +11456,7 @@ ${styledLine}`;
|
|
|
10944
11456
|
if (isInteractiveAllowed(program)) {
|
|
10945
11457
|
let latestForInteractiveStartup = null;
|
|
10946
11458
|
if (shouldRunOnboarding(program, cfg)) {
|
|
10947
|
-
const { runOnboarding } = await import("./onboarding-
|
|
11459
|
+
const { runOnboarding } = await import("./onboarding-47TK4HNM.js");
|
|
10948
11460
|
const latest = getAvailableUpdateOnce();
|
|
10949
11461
|
const completed = await runOnboarding(program, latest);
|
|
10950
11462
|
updateShownDuringInteractiveStartup = Boolean(latest);
|
|
@@ -10958,7 +11470,7 @@ ${styledLine}`;
|
|
|
10958
11470
|
latestForInteractiveStartup
|
|
10959
11471
|
);
|
|
10960
11472
|
}
|
|
10961
|
-
const { startREPL } = await import("./interactive-
|
|
11473
|
+
const { startREPL } = await import("./interactive-PQGRT27R.js");
|
|
10962
11474
|
program.exitOverride();
|
|
10963
11475
|
program.configureOutput({
|
|
10964
11476
|
writeErr: () => {
|
|
@@ -10975,6 +11487,7 @@ registerXchain(program);
|
|
|
10975
11487
|
registerWallets(program);
|
|
10976
11488
|
registerGasManager(program);
|
|
10977
11489
|
registerApps(program);
|
|
11490
|
+
registerUsage(program);
|
|
10978
11491
|
registerWebhooks(program);
|
|
10979
11492
|
registerAuth(program);
|
|
10980
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 {
|