@alchemy/cli 0.7.4 → 0.8.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/dist/{auth-GD7BJOMK.js → auth-JPRZE2MA.js} +2 -2
- package/dist/auth-RINQSQDT.js +16 -0
- package/dist/{chunk-2BALTY22.js → chunk-46LMXT54.js} +8 -0
- package/dist/chunk-5Y7UQ27V.js +186 -0
- package/dist/{chunk-N36ZNOVV.js → chunk-76ZO4UJ4.js} +3 -3
- package/dist/{chunk-5IL2PMZ6.js → chunk-DGZYRBXR.js} +1 -1
- package/dist/{chunk-XSN4XA5Z.js → chunk-EKS2THJU.js} +6 -6
- package/dist/{chunk-R4W44A6E.js → chunk-GNOTKJF4.js} +2 -2
- package/dist/{chunk-K6V3R7SH.js → chunk-JWLZAO7S.js} +182 -2
- package/dist/{chunk-64A5W4M2.js → chunk-L7VFXQSF.js} +1 -1
- package/dist/{chunk-C5HNQOLB.js → chunk-NGF46GZP.js} +1 -1
- package/dist/{chunk-JUCUKTP3.js → chunk-ROBA7SR7.js} +1 -1
- package/dist/{errors-E2P6WHTX.js → errors-A53DVJDY.js} +3 -1
- package/dist/index.js +327 -40
- package/dist/{interactive-MHAC5WQI.js → interactive-6R3VKAPQ.js} +7 -7
- package/dist/{onboarding-CT4RRH6O.js → onboarding-YHYXW4F3.js} +6 -6
- package/dist/policy-prompt-7AUZOA7S.js +18 -0
- package/dist/{resolve-WXT5ZCUK.js → resolve-N3SX252M.js} +7 -3
- package/package.json +1 -1
- package/dist/auth-F2IXC6CM.js +0 -16
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
|
+
import {
|
|
4
|
+
registerAuth,
|
|
5
|
+
selectAppAfterAuth
|
|
6
|
+
} from "./chunk-EKS2THJU.js";
|
|
7
|
+
import "./chunk-NGF46GZP.js";
|
|
8
|
+
import "./chunk-L7VFXQSF.js";
|
|
9
|
+
import "./chunk-JWLZAO7S.js";
|
|
10
|
+
import "./chunk-DGZYRBXR.js";
|
|
11
|
+
import "./chunk-ROBA7SR7.js";
|
|
12
|
+
import "./chunk-46LMXT54.js";
|
|
13
|
+
export {
|
|
14
|
+
registerAuth,
|
|
15
|
+
selectAppAfterAuth
|
|
16
|
+
};
|
|
@@ -375,6 +375,13 @@ function errAccessKeyRequired() {
|
|
|
375
375
|
"Get an access key: https://www.alchemy.com/docs/reference/admin-api/overview"
|
|
376
376
|
);
|
|
377
377
|
}
|
|
378
|
+
function errLoginRequired() {
|
|
379
|
+
return new CLIError(
|
|
380
|
+
ErrorCode.AUTH_REQUIRED,
|
|
381
|
+
"Sign in to Alchemy to continue. Run 'alchemy auth login', then retry.",
|
|
382
|
+
"alchemy auth login"
|
|
383
|
+
);
|
|
384
|
+
}
|
|
378
385
|
function errInvalidAPIKey(details) {
|
|
379
386
|
return new CLIError(
|
|
380
387
|
ErrorCode.INVALID_API_KEY,
|
|
@@ -541,6 +548,7 @@ export {
|
|
|
541
548
|
CLIError,
|
|
542
549
|
errAuthRequired,
|
|
543
550
|
errAccessKeyRequired,
|
|
551
|
+
errLoginRequired,
|
|
544
552
|
errInvalidAPIKey,
|
|
545
553
|
errNetworkNotEnabled,
|
|
546
554
|
errNetwork,
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
|
+
import {
|
|
4
|
+
gasManagerClientFromFlags,
|
|
5
|
+
toAdminNetworkId
|
|
6
|
+
} from "./chunk-JWLZAO7S.js";
|
|
7
|
+
import {
|
|
8
|
+
dim,
|
|
9
|
+
green,
|
|
10
|
+
promptAutocomplete,
|
|
11
|
+
promptConfirm,
|
|
12
|
+
promptText,
|
|
13
|
+
withSpinner
|
|
14
|
+
} from "./chunk-DGZYRBXR.js";
|
|
15
|
+
import {
|
|
16
|
+
load,
|
|
17
|
+
save
|
|
18
|
+
} from "./chunk-ROBA7SR7.js";
|
|
19
|
+
import {
|
|
20
|
+
errAppRequired,
|
|
21
|
+
errInvalidArgs,
|
|
22
|
+
errLoginRequired
|
|
23
|
+
} from "./chunk-46LMXT54.js";
|
|
24
|
+
|
|
25
|
+
// src/lib/policy-prompt.ts
|
|
26
|
+
var CREATE_NEW_SENTINEL = "__create_new__";
|
|
27
|
+
var DEFAULT_SPONSORSHIP_EXPIRY_MS = "600000";
|
|
28
|
+
var DEFAULT_SOLANA_MAX_COUNT = "1000";
|
|
29
|
+
function flavorNoun(flavor) {
|
|
30
|
+
return flavor === "solana" ? "fee sponsorship" : "gas sponsorship";
|
|
31
|
+
}
|
|
32
|
+
async function selectOrCreatePolicy(opts) {
|
|
33
|
+
const cfg = load();
|
|
34
|
+
const appId = cfg.app?.id;
|
|
35
|
+
if (!appId) throw errAppRequired();
|
|
36
|
+
const client = opts.client ?? gasManagerClientFromFlags(opts.program);
|
|
37
|
+
const flavorLabel = flavorNoun(opts.flavor);
|
|
38
|
+
const policies = await withSpinner(
|
|
39
|
+
"Fetching gas policies\u2026",
|
|
40
|
+
"Policies fetched",
|
|
41
|
+
() => client.listAllPolicies({ appId })
|
|
42
|
+
);
|
|
43
|
+
const matching = filterPolicies(policies, opts.flavor, opts.network);
|
|
44
|
+
let selectedId = null;
|
|
45
|
+
if (matching.length === 0) {
|
|
46
|
+
console.log(
|
|
47
|
+
` ${dim(`No ${flavorLabel} policies found for ${opts.network} on app ${appId}. Let's create one.`)}`
|
|
48
|
+
);
|
|
49
|
+
const created = await runCreate(opts, client, appId);
|
|
50
|
+
if (!created) return null;
|
|
51
|
+
selectedId = created.policyId;
|
|
52
|
+
} else {
|
|
53
|
+
const selected = await promptAutocomplete({
|
|
54
|
+
message: `Select a ${flavorLabel} policy for ${opts.network}`,
|
|
55
|
+
placeholder: "Policy name or ID",
|
|
56
|
+
options: [
|
|
57
|
+
...matching.map((p) => ({
|
|
58
|
+
label: formatPolicyOption(p),
|
|
59
|
+
value: p.policyId
|
|
60
|
+
})),
|
|
61
|
+
{ label: "Create a new policy", value: CREATE_NEW_SENTINEL }
|
|
62
|
+
],
|
|
63
|
+
cancelMessage: "Cancelled policy selection.",
|
|
64
|
+
commitLabel: null
|
|
65
|
+
});
|
|
66
|
+
if (selected === null) return null;
|
|
67
|
+
if (selected === CREATE_NEW_SENTINEL) {
|
|
68
|
+
const created = await runCreate(opts, client, appId);
|
|
69
|
+
if (!created) return null;
|
|
70
|
+
selectedId = created.policyId;
|
|
71
|
+
} else {
|
|
72
|
+
selectedId = selected;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!opts.skipPersistPrompt && selectedId) {
|
|
76
|
+
await maybePersist(opts.flavor, selectedId);
|
|
77
|
+
}
|
|
78
|
+
return selectedId;
|
|
79
|
+
}
|
|
80
|
+
async function createPolicyInteractive(opts) {
|
|
81
|
+
const cfg = load();
|
|
82
|
+
const appId = cfg.app?.id;
|
|
83
|
+
if (!appId) throw errAppRequired();
|
|
84
|
+
const client = opts.client ?? gasManagerClientFromFlags(opts.program);
|
|
85
|
+
const result = await runCreate(opts, client, appId);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function filterPolicies(policies, flavor, network) {
|
|
89
|
+
const adminId = toAdminNetworkId(network);
|
|
90
|
+
return policies.filter((p) => {
|
|
91
|
+
if (p.policyType !== flavor) return false;
|
|
92
|
+
if (!Array.isArray(p.networks)) return false;
|
|
93
|
+
return p.networks.includes(adminId);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function formatPolicyOption(p) {
|
|
97
|
+
const status = p.status === "active" ? green("active") : dim(p.status);
|
|
98
|
+
return `${p.policyName} (${p.policyId.slice(0, 10)}\u2026) \u2014 ${status}`;
|
|
99
|
+
}
|
|
100
|
+
async function runCreate(opts, client, appId) {
|
|
101
|
+
const name = await promptText({
|
|
102
|
+
message: "Policy name",
|
|
103
|
+
cancelMessage: "Cancelled policy creation."
|
|
104
|
+
});
|
|
105
|
+
if (name === null) return null;
|
|
106
|
+
if (!name.trim()) {
|
|
107
|
+
console.log(` ${dim("Skipped policy creation (no name).")}`);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const adminNetworkId = toAdminNetworkId(opts.network);
|
|
111
|
+
const nowUnix = String(Math.floor(Date.now() / 1e3));
|
|
112
|
+
const payload = opts.flavor === "sponsorship" ? {
|
|
113
|
+
policyName: name.trim(),
|
|
114
|
+
policyType: "sponsorship",
|
|
115
|
+
appId,
|
|
116
|
+
networks: [adminNetworkId],
|
|
117
|
+
rules: {
|
|
118
|
+
startTimeUnix: nowUnix,
|
|
119
|
+
sponsorshipExpiryMs: DEFAULT_SPONSORSHIP_EXPIRY_MS
|
|
120
|
+
}
|
|
121
|
+
} : {
|
|
122
|
+
policyName: name.trim(),
|
|
123
|
+
policyType: "solana",
|
|
124
|
+
appId,
|
|
125
|
+
networks: [adminNetworkId],
|
|
126
|
+
solanaRules: {
|
|
127
|
+
startTimeUnix: nowUnix,
|
|
128
|
+
maxCount: DEFAULT_SOLANA_MAX_COUNT
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const created = await withSpinner(
|
|
132
|
+
"Creating policy\u2026",
|
|
133
|
+
"Policy created",
|
|
134
|
+
() => client.createPolicy(payload)
|
|
135
|
+
);
|
|
136
|
+
console.log(` ${green("\u2713")} Created ${created.policyName} (${created.policyId})`);
|
|
137
|
+
const activate = await promptConfirm({
|
|
138
|
+
message: "Activate this policy now? (required before use)",
|
|
139
|
+
initialValue: true,
|
|
140
|
+
cancelMessage: "Skipped activation."
|
|
141
|
+
});
|
|
142
|
+
let activated = false;
|
|
143
|
+
if (activate === true) {
|
|
144
|
+
await withSpinner(
|
|
145
|
+
"Activating policy\u2026",
|
|
146
|
+
"Policy active",
|
|
147
|
+
() => client.setPolicyStatus(created.policyId, "active")
|
|
148
|
+
);
|
|
149
|
+
activated = true;
|
|
150
|
+
} else {
|
|
151
|
+
console.log(
|
|
152
|
+
` ${dim("Policy left inactive. Activate later with `alchemy gas-manager policy activate " + created.policyId + "`.")}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
return { policyId: created.policyId, status: "created", activated };
|
|
156
|
+
}
|
|
157
|
+
async function maybePersist(flavor, policyId) {
|
|
158
|
+
const confirmed = await promptConfirm({
|
|
159
|
+
message: "Save as default policy for this CLI?",
|
|
160
|
+
initialValue: true,
|
|
161
|
+
cancelMessage: "Skipped saving default."
|
|
162
|
+
});
|
|
163
|
+
if (confirmed !== true) return;
|
|
164
|
+
const cfg = load();
|
|
165
|
+
const updated = flavor === "sponsorship" ? { ...cfg, evm_gas_policy_id: policyId } : { ...cfg, solana_fee_policy_id: policyId };
|
|
166
|
+
save(updated);
|
|
167
|
+
const key = flavor === "sponsorship" ? "evm-gas-policy-id" : "solana-fee-policy-id";
|
|
168
|
+
console.log(` ${green("\u2713")} Saved ${key} = ${policyId}`);
|
|
169
|
+
}
|
|
170
|
+
function errSponsorshipNeedsPolicy(flavor) {
|
|
171
|
+
const flag = flavor === "sponsorship" ? "--gas-policy-id" : "--fee-policy-id";
|
|
172
|
+
const label = flavor === "sponsorship" ? "Gas sponsorship" : "Fee sponsorship";
|
|
173
|
+
return errInvalidArgs(
|
|
174
|
+
`${label} requires a policy ID. Run 'alchemy gas-manager policy list' to pick one, pass ${flag} <id>, or run interactively to be prompted.`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
function errNotLoggedInForPolicyLookup() {
|
|
178
|
+
return errLoginRequired();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
selectOrCreatePolicy,
|
|
183
|
+
createPolicyInteractive,
|
|
184
|
+
errSponsorshipNeedsPolicy,
|
|
185
|
+
errNotLoggedInForPolicyLookup
|
|
186
|
+
};
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
configPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ROBA7SR7.js";
|
|
6
6
|
import {
|
|
7
7
|
esc
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-46LMXT54.js";
|
|
9
9
|
|
|
10
10
|
// src/lib/update-check.ts
|
|
11
11
|
import { execFileSync } from "child_process";
|
|
@@ -53,7 +53,7 @@ function semverLT(a, b) {
|
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
55
|
function currentVersion() {
|
|
56
|
-
return true ? "0.
|
|
56
|
+
return true ? "0.8.0" : "0.0.0";
|
|
57
57
|
}
|
|
58
58
|
function toUpdateStatus(latestVersion, checkedAt) {
|
|
59
59
|
const current = currentVersion();
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
completeLogin,
|
|
5
5
|
prepareLogin,
|
|
6
6
|
revokeToken
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NGF46GZP.js";
|
|
8
8
|
import {
|
|
9
9
|
isInteractiveAllowed
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-L7VFXQSF.js";
|
|
11
11
|
import {
|
|
12
12
|
AdminClient,
|
|
13
13
|
resolveAuthToken
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JWLZAO7S.js";
|
|
15
15
|
import {
|
|
16
16
|
bold,
|
|
17
17
|
brand,
|
|
@@ -20,13 +20,13 @@ import {
|
|
|
20
20
|
promptAutocomplete,
|
|
21
21
|
promptText,
|
|
22
22
|
withSpinner
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-DGZYRBXR.js";
|
|
24
24
|
import {
|
|
25
25
|
configPath,
|
|
26
26
|
load,
|
|
27
27
|
maskIf,
|
|
28
28
|
save
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-ROBA7SR7.js";
|
|
30
30
|
import {
|
|
31
31
|
CLIError,
|
|
32
32
|
ErrorCode,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
exitWithError,
|
|
35
35
|
isJSONMode,
|
|
36
36
|
printHuman
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-46LMXT54.js";
|
|
38
38
|
|
|
39
39
|
// src/commands/auth.ts
|
|
40
40
|
function registerAuth(program) {
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
3
|
import {
|
|
4
4
|
isInteractiveAllowed
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-L7VFXQSF.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveAuthToken,
|
|
8
8
|
resolveWalletSession
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-JWLZAO7S.js";
|
|
10
10
|
|
|
11
11
|
// src/lib/onboarding.ts
|
|
12
12
|
var SETUP_CAPABILITY_ORDER = [
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
configDir,
|
|
5
5
|
load,
|
|
6
6
|
save
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ROBA7SR7.js";
|
|
8
8
|
import {
|
|
9
9
|
CLIError,
|
|
10
10
|
ErrorCode,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
errInvalidAPIKey,
|
|
18
18
|
errInvalidAccessKey,
|
|
19
19
|
errInvalidArgs,
|
|
20
|
+
errLoginRequired,
|
|
20
21
|
errNetwork,
|
|
21
22
|
errNetworkNotEnabled,
|
|
22
23
|
errNotFound,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
parseBaseURLOverride,
|
|
30
31
|
redactSensitiveText,
|
|
31
32
|
verbose
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-46LMXT54.js";
|
|
33
34
|
|
|
34
35
|
// src/lib/resolve.ts
|
|
35
36
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -293,6 +294,12 @@ var NATIVE_TOKEN_SYMBOLS = {
|
|
|
293
294
|
function isSolanaNetwork(networkId) {
|
|
294
295
|
return networkId.startsWith("solana-");
|
|
295
296
|
}
|
|
297
|
+
function toAdminNetworkId(slug) {
|
|
298
|
+
return slug.trim().toUpperCase().replace(/-/g, "_");
|
|
299
|
+
}
|
|
300
|
+
function fromAdminNetworkId(id) {
|
|
301
|
+
return id.trim().toLowerCase().replace(/_/g, "-");
|
|
302
|
+
}
|
|
296
303
|
function nativeTokenSymbol(networkId) {
|
|
297
304
|
const prefix = networkId.replace(/-(mainnet|testnet|sepolia|holesky|hoodi|devnet|amoy|fuji|cardona|saigon|chiado|signet|mocha|blaze|curtis|bepolia).*$/, "");
|
|
298
305
|
return NATIVE_TOKEN_SYMBOLS[prefix] ?? "ETH";
|
|
@@ -862,6 +869,166 @@ var AdminClient = class _AdminClient {
|
|
|
862
869
|
}
|
|
863
870
|
};
|
|
864
871
|
|
|
872
|
+
// src/lib/gas-manager-client.ts
|
|
873
|
+
var GasManagerClient = class _GasManagerClient {
|
|
874
|
+
static get HOST() {
|
|
875
|
+
return `manage.g.${getBaseDomain()}`;
|
|
876
|
+
}
|
|
877
|
+
// Test/debug only: route requests to a local mock.
|
|
878
|
+
static BASE_URL_ENV = "ALCHEMY_GAS_MANAGER_BASE_URL";
|
|
879
|
+
credential;
|
|
880
|
+
constructor(credential) {
|
|
881
|
+
if (typeof credential === "string") {
|
|
882
|
+
this.validateAccessKey(credential);
|
|
883
|
+
this.credential = { type: "access_key", key: credential };
|
|
884
|
+
} else {
|
|
885
|
+
if (credential.type === "access_key") {
|
|
886
|
+
this.validateAccessKey(credential.key);
|
|
887
|
+
} else if (!credential.token.trim()) {
|
|
888
|
+
throw errAuthRequired();
|
|
889
|
+
}
|
|
890
|
+
this.credential = credential;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
baseURL() {
|
|
894
|
+
const override = this.baseURLOverride();
|
|
895
|
+
if (override) return override.toString().replace(/\/$/, "");
|
|
896
|
+
return `https://manage.g.${getBaseDomain()}`;
|
|
897
|
+
}
|
|
898
|
+
allowedHosts() {
|
|
899
|
+
const hosts = /* @__PURE__ */ new Set([_GasManagerClient.HOST]);
|
|
900
|
+
const override = this.baseURLOverride();
|
|
901
|
+
if (override) hosts.add(override.hostname);
|
|
902
|
+
return hosts;
|
|
903
|
+
}
|
|
904
|
+
allowInsecureTransport(hostname) {
|
|
905
|
+
return isLocalhost(hostname);
|
|
906
|
+
}
|
|
907
|
+
baseURLOverride() {
|
|
908
|
+
return parseBaseURLOverride(_GasManagerClient.BASE_URL_ENV);
|
|
909
|
+
}
|
|
910
|
+
validateAccessKey(accessKey) {
|
|
911
|
+
if (!accessKey.trim() || /\s/.test(accessKey)) {
|
|
912
|
+
throw errInvalidAccessKey();
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
assertSafeRequestTarget(url) {
|
|
916
|
+
let parsed;
|
|
917
|
+
try {
|
|
918
|
+
parsed = new URL(url);
|
|
919
|
+
} catch {
|
|
920
|
+
throw errInvalidArgs("Invalid gas manager API URL.");
|
|
921
|
+
}
|
|
922
|
+
if (!this.allowedHosts().has(parsed.hostname)) {
|
|
923
|
+
throw errInvalidArgs(`Refusing to send credentials to unexpected host: ${parsed.hostname}`);
|
|
924
|
+
}
|
|
925
|
+
if (parsed.protocol !== "https:" && !this.allowInsecureTransport(parsed.hostname)) {
|
|
926
|
+
throw errInvalidArgs("Refusing to send credentials over non-HTTPS connection.");
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
async request(method, path, body) {
|
|
930
|
+
const url = `${this.baseURL()}${path}`;
|
|
931
|
+
debug(`${method} ${url}`);
|
|
932
|
+
this.assertSafeRequestTarget(url);
|
|
933
|
+
const token = this.credential.type === "access_key" ? this.credential.key : this.credential.token;
|
|
934
|
+
const resp = await fetchWithTimeout(url, {
|
|
935
|
+
method,
|
|
936
|
+
redirect: "error",
|
|
937
|
+
headers: {
|
|
938
|
+
Authorization: `Bearer ${token}`,
|
|
939
|
+
"Content-Type": "application/json",
|
|
940
|
+
Accept: "application/json"
|
|
941
|
+
},
|
|
942
|
+
...body !== void 0 && { body: JSON.stringify(body) }
|
|
943
|
+
});
|
|
944
|
+
if (resp.status === 401) {
|
|
945
|
+
throw this.credential.type === "auth_token" ? errLoginRequired() : errInvalidAccessKey();
|
|
946
|
+
}
|
|
947
|
+
if (resp.status === 403) {
|
|
948
|
+
const detail = await resp.text().catch(() => "");
|
|
949
|
+
let reason;
|
|
950
|
+
try {
|
|
951
|
+
const parsed = JSON.parse(detail);
|
|
952
|
+
reason = parsed?.error?.msg ?? parsed?.message ?? parsed?.error ?? void 0;
|
|
953
|
+
} catch {
|
|
954
|
+
reason = detail || void 0;
|
|
955
|
+
}
|
|
956
|
+
if (this.credential.type === "auth_token") {
|
|
957
|
+
const tail = reason ? ` (${reason})` : "";
|
|
958
|
+
throw new CLIError(
|
|
959
|
+
ErrorCode.AUTH_REQUIRED,
|
|
960
|
+
`Access denied for this Alchemy account or app${tail}. Re-authenticate with 'alchemy auth login' or check that the default app is one you have permission to manage.`,
|
|
961
|
+
"alchemy auth login"
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
throw errAccessDenied(typeof reason === "string" ? reason : void 0);
|
|
965
|
+
}
|
|
966
|
+
if (resp.status === 404) {
|
|
967
|
+
const text = await resp.text().catch(() => "");
|
|
968
|
+
throw errNotFound(text || path);
|
|
969
|
+
}
|
|
970
|
+
if (resp.status === 429) throw errRateLimited();
|
|
971
|
+
if (!resp.ok) {
|
|
972
|
+
const text = await resp.text().catch(() => "");
|
|
973
|
+
throw errAdminAPI(resp.status, text);
|
|
974
|
+
}
|
|
975
|
+
return resp.json();
|
|
976
|
+
}
|
|
977
|
+
async listPolicies(opts) {
|
|
978
|
+
const params = new URLSearchParams();
|
|
979
|
+
params.set("appId", opts.appId);
|
|
980
|
+
if (opts.limit !== void 0) params.set("limit", String(opts.limit));
|
|
981
|
+
if (opts.after) params.set("after", opts.after);
|
|
982
|
+
if (opts.before) params.set("before", opts.before);
|
|
983
|
+
const resp = await this.request(
|
|
984
|
+
"GET",
|
|
985
|
+
`/api/gasManager/policies?${params.toString()}`
|
|
986
|
+
);
|
|
987
|
+
return resp.data;
|
|
988
|
+
}
|
|
989
|
+
async listAllPolicies(opts) {
|
|
990
|
+
const policies = [];
|
|
991
|
+
const seen = /* @__PURE__ */ new Set();
|
|
992
|
+
let after;
|
|
993
|
+
do {
|
|
994
|
+
const page = await this.listPolicies({
|
|
995
|
+
appId: opts.appId,
|
|
996
|
+
...opts.limit !== void 0 && { limit: opts.limit },
|
|
997
|
+
...after && { after }
|
|
998
|
+
});
|
|
999
|
+
policies.push(...page.policies);
|
|
1000
|
+
const next = page.after ?? void 0;
|
|
1001
|
+
if (next && seen.has(next)) break;
|
|
1002
|
+
if (next) seen.add(next);
|
|
1003
|
+
after = next;
|
|
1004
|
+
} while (after);
|
|
1005
|
+
return policies;
|
|
1006
|
+
}
|
|
1007
|
+
async getPolicy(policyId) {
|
|
1008
|
+
const resp = await this.request(
|
|
1009
|
+
"GET",
|
|
1010
|
+
`/api/gasManager/policy/${encodeURIComponent(policyId)}`
|
|
1011
|
+
);
|
|
1012
|
+
return resp.data.policy;
|
|
1013
|
+
}
|
|
1014
|
+
async createPolicy(payload) {
|
|
1015
|
+
const resp = await this.request(
|
|
1016
|
+
"POST",
|
|
1017
|
+
"/api/gasManager/policy",
|
|
1018
|
+
payload
|
|
1019
|
+
);
|
|
1020
|
+
return resp.data.policy;
|
|
1021
|
+
}
|
|
1022
|
+
async setPolicyStatus(policyId, status) {
|
|
1023
|
+
const resp = await this.request(
|
|
1024
|
+
"PUT",
|
|
1025
|
+
`/api/gasManager/policy/${encodeURIComponent(policyId)}/status`,
|
|
1026
|
+
{ status }
|
|
1027
|
+
);
|
|
1028
|
+
return resp.data.policy;
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
|
|
865
1032
|
// src/lib/wallet-session.ts
|
|
866
1033
|
import { generateKeyPairSync, randomUUID } from "crypto";
|
|
867
1034
|
import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync } from "fs";
|
|
@@ -1094,6 +1261,15 @@ function adminClientFromFlags(program) {
|
|
|
1094
1261
|
if (authToken) return new AdminClient({ type: "auth_token", token: authToken });
|
|
1095
1262
|
throw errAccessKeyRequired();
|
|
1096
1263
|
}
|
|
1264
|
+
function hasAuthLoginToken(cfg) {
|
|
1265
|
+
return Boolean(resolveAuthToken(cfg));
|
|
1266
|
+
}
|
|
1267
|
+
function gasManagerClientFromFlags(_program) {
|
|
1268
|
+
const cfg = load();
|
|
1269
|
+
const authToken = resolveAuthToken(cfg);
|
|
1270
|
+
if (!authToken) throw errLoginRequired();
|
|
1271
|
+
return new GasManagerClient({ type: "auth_token", token: authToken });
|
|
1272
|
+
}
|
|
1097
1273
|
function resolveX402(program, cfg) {
|
|
1098
1274
|
const opts = getCommandOptions(program);
|
|
1099
1275
|
if (opts.x402) return true;
|
|
@@ -1240,6 +1416,8 @@ export {
|
|
|
1240
1416
|
getRPCNetworks,
|
|
1241
1417
|
getRPCNetworkIds,
|
|
1242
1418
|
isSolanaNetwork,
|
|
1419
|
+
toAdminNetworkId,
|
|
1420
|
+
fromAdminNetworkId,
|
|
1243
1421
|
nativeTokenSymbol,
|
|
1244
1422
|
AdminClient,
|
|
1245
1423
|
createPendingSession,
|
|
@@ -1256,6 +1434,8 @@ export {
|
|
|
1256
1434
|
resolveAppId,
|
|
1257
1435
|
resolveAuthToken,
|
|
1258
1436
|
adminClientFromFlags,
|
|
1437
|
+
hasAuthLoginToken,
|
|
1438
|
+
gasManagerClientFromFlags,
|
|
1259
1439
|
resolveX402,
|
|
1260
1440
|
resolveX402Client,
|
|
1261
1441
|
resolveWalletKey,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
errInvalidAPIKey,
|
|
13
13
|
errInvalidAccessKey,
|
|
14
14
|
errInvalidArgs,
|
|
15
|
+
errLoginRequired,
|
|
15
16
|
errNetwork,
|
|
16
17
|
errNetworkNotEnabled,
|
|
17
18
|
errNoActiveSession,
|
|
@@ -26,7 +27,7 @@ import {
|
|
|
26
27
|
exitWithError,
|
|
27
28
|
isReplMode,
|
|
28
29
|
setReplMode
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-46LMXT54.js";
|
|
30
31
|
export {
|
|
31
32
|
CLIError,
|
|
32
33
|
EXIT_CODES,
|
|
@@ -39,6 +40,7 @@ export {
|
|
|
39
40
|
errInvalidAPIKey,
|
|
40
41
|
errInvalidAccessKey,
|
|
41
42
|
errInvalidArgs,
|
|
43
|
+
errLoginRequired,
|
|
42
44
|
errNetwork,
|
|
43
45
|
errNetworkNotEnabled,
|
|
44
46
|
errNoActiveSession,
|