@alchemy/cli 0.4.0 → 0.5.1
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-7E33EMAI.js +13 -0
- package/dist/auth-E26YCAJV.js +23 -0
- package/dist/chunk-44OGGLN4.js +681 -0
- package/dist/chunk-56ZVYB4G.js +536 -0
- package/dist/{chunk-Z3LXQFIY.js → chunk-5X6YRTPU.js} +15 -5
- package/dist/chunk-IGD4NIK7.js +300 -0
- package/dist/chunk-LYUW7O6X.js +231 -0
- package/dist/chunk-T2XSNZE3.js +1398 -0
- package/dist/chunk-Z7J64GJJ.js +118 -0
- package/dist/index.js +127 -60
- package/dist/{interactive-NASSNJHQ.js → interactive-G4ON47AR.js} +12 -7
- package/dist/{onboarding-WQ2TWDM3.js → onboarding-CWCVWSUG.js} +57 -15
- package/package.json +1 -1
- package/scripts/postinstall.cjs +17 -1
- package/dist/chunk-PIWNNNMZ.js +0 -1327
- package/dist/chunk-TH75DFAY.js +0 -1246
package/dist/chunk-TH75DFAY.js
DELETED
|
@@ -1,1246 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
|
|
3
|
-
|
|
4
|
-
// src/lib/colors.ts
|
|
5
|
-
var forceColor = "FORCE_COLOR" in process.env && process.env.FORCE_COLOR !== "0";
|
|
6
|
-
var noColor = !forceColor && ("NO_COLOR" in process.env || process.env.TERM === "dumb");
|
|
7
|
-
function setNoColor(value) {
|
|
8
|
-
noColor = value;
|
|
9
|
-
}
|
|
10
|
-
var identity = (s) => s;
|
|
11
|
-
var esc = (code) => (s) => noColor ? s : `\x1B[${code}m${s}\x1B[0m`;
|
|
12
|
-
var rgb = (r, g, b) => (s) => noColor ? s : `\x1B[38;2;${r};${g};${b}m${s}\x1B[39m`;
|
|
13
|
-
var bgRgb = (r, g, b) => (s) => noColor ? s : `\x1B[48;2;${r};${g};${b}m${s}\x1B[49m`;
|
|
14
|
-
|
|
15
|
-
// src/lib/redact.ts
|
|
16
|
-
var SENSITIVE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
17
|
-
"AUTH_REQUIRED",
|
|
18
|
-
"INVALID_API_KEY",
|
|
19
|
-
"INVALID_ACCESS_KEY",
|
|
20
|
-
"ACCESS_KEY_REQUIRED"
|
|
21
|
-
]);
|
|
22
|
-
var ALCHEMY_KEY_PATH_MARKERS = ["alchemy.com/v2/", "alchemy.com/nft/v3/"];
|
|
23
|
-
function isSecretBoundaryChar(char) {
|
|
24
|
-
return char === "/" || char === "?" || char === " " || char === " " || char === "\n" || char === "\r" || char === '"' || char === "'" || char === "`";
|
|
25
|
-
}
|
|
26
|
-
function redactAfterMarker(input, marker) {
|
|
27
|
-
const lower = input.toLowerCase();
|
|
28
|
-
let index = 0;
|
|
29
|
-
let cursor = 0;
|
|
30
|
-
let out = "";
|
|
31
|
-
while (index < input.length) {
|
|
32
|
-
const markerIndex = lower.indexOf(marker, index);
|
|
33
|
-
if (markerIndex === -1) break;
|
|
34
|
-
const secretStart = markerIndex + marker.length;
|
|
35
|
-
let secretEnd = secretStart;
|
|
36
|
-
while (secretEnd < input.length && !isSecretBoundaryChar(input[secretEnd])) {
|
|
37
|
-
secretEnd += 1;
|
|
38
|
-
}
|
|
39
|
-
out += input.slice(cursor, secretStart);
|
|
40
|
-
out += "[REDACTED]";
|
|
41
|
-
cursor = secretEnd;
|
|
42
|
-
index = secretEnd;
|
|
43
|
-
}
|
|
44
|
-
if (!out) return input;
|
|
45
|
-
return out + input.slice(cursor);
|
|
46
|
-
}
|
|
47
|
-
function redactSensitiveText(value) {
|
|
48
|
-
let redacted = value;
|
|
49
|
-
for (const marker of ALCHEMY_KEY_PATH_MARKERS) {
|
|
50
|
-
redacted = redactAfterMarker(redacted, marker);
|
|
51
|
-
}
|
|
52
|
-
return redacted;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/lib/error-format.ts
|
|
56
|
-
var ansi = {
|
|
57
|
-
red: (s) => `\x1B[31m${s}\x1B[0m`,
|
|
58
|
-
boldRed: (s) => `\x1B[1;31m${s}\x1B[0m`,
|
|
59
|
-
dim: (s) => `\x1B[2m${s}\x1B[0m`
|
|
60
|
-
};
|
|
61
|
-
function toSafeErrorJSON(err) {
|
|
62
|
-
const payload = err.toJSON();
|
|
63
|
-
const error = payload.error ?? {};
|
|
64
|
-
const code = error.code ?? err.code;
|
|
65
|
-
const safeError = {
|
|
66
|
-
...code && { code },
|
|
67
|
-
...typeof error.message === "string" && { message: redactSensitiveText(error.message) },
|
|
68
|
-
...typeof error.hint === "string" && { hint: redactSensitiveText(error.hint) },
|
|
69
|
-
...typeof error.retryable === "boolean" && { retryable: error.retryable }
|
|
70
|
-
};
|
|
71
|
-
if (typeof error.details === "string" && !SENSITIVE_ERROR_CODES.has(code)) {
|
|
72
|
-
safeError.details = redactSensitiveText(error.details);
|
|
73
|
-
}
|
|
74
|
-
if (error.data !== void 0) {
|
|
75
|
-
safeError.data = error.data;
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
error: safeError
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function wrapWithPrefix(text, prefix, width) {
|
|
82
|
-
const safeWidth = Math.max(20, width - prefix.length);
|
|
83
|
-
const words = text.trim().split(/\s+/);
|
|
84
|
-
if (words.length === 0 || words.length === 1 && words[0] === "") return [prefix];
|
|
85
|
-
const lines = [];
|
|
86
|
-
let current = "";
|
|
87
|
-
for (const word of words) {
|
|
88
|
-
if (current.length === 0) {
|
|
89
|
-
current = word;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
if (current.length + 1 + word.length <= safeWidth) {
|
|
93
|
-
current += ` ${word}`;
|
|
94
|
-
} else {
|
|
95
|
-
lines.push(`${prefix}${current}`);
|
|
96
|
-
current = word;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (current.length > 0) {
|
|
100
|
-
lines.push(`${prefix}${current}`);
|
|
101
|
-
}
|
|
102
|
-
return lines;
|
|
103
|
-
}
|
|
104
|
-
function supportsStderrStyling() {
|
|
105
|
-
return (process.stderr.isTTY || forceColor) && !noColor;
|
|
106
|
-
}
|
|
107
|
-
function printError(err) {
|
|
108
|
-
if (isJSONMode()) {
|
|
109
|
-
console.error(JSON.stringify(toSafeErrorJSON(err), null, 2));
|
|
110
|
-
} else {
|
|
111
|
-
const width = process.stderr.columns ?? 100;
|
|
112
|
-
const safeMessage = redactSensitiveText(err.message);
|
|
113
|
-
const safeHint = err.hint ? redactSensitiveText(err.hint) : void 0;
|
|
114
|
-
const safeDetails = err.details && !SENSITIVE_ERROR_CODES.has(err.code) ? redactSensitiveText(err.details) : void 0;
|
|
115
|
-
const detailLines = safeDetails ? safeDetails.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0) : [];
|
|
116
|
-
const lines = [` \u2717 ${err.code}`, ` ${"\u2500".repeat(40)}`];
|
|
117
|
-
lines.push(...wrapWithPrefix(safeMessage, " - ", width));
|
|
118
|
-
if (detailLines.length > 0) {
|
|
119
|
-
lines.push("");
|
|
120
|
-
lines.push(" - Provider:");
|
|
121
|
-
for (const line of detailLines) {
|
|
122
|
-
lines.push(...wrapWithPrefix(line, " - ", width));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (safeHint) {
|
|
126
|
-
lines.push("");
|
|
127
|
-
lines.push(...wrapWithPrefix(`Hint: ${safeHint}`, " - ", width));
|
|
128
|
-
}
|
|
129
|
-
if (supportsStderrStyling()) {
|
|
130
|
-
const styled = [
|
|
131
|
-
` ${ansi.red("\u2717")} ${ansi.boldRed(err.code)}`,
|
|
132
|
-
` ${ansi.dim("\u2500".repeat(40))}`,
|
|
133
|
-
...wrapWithPrefix(safeMessage, " - ", width).map((line) => ansi.red(line))
|
|
134
|
-
];
|
|
135
|
-
if (detailLines.length > 0) {
|
|
136
|
-
styled.push("");
|
|
137
|
-
styled.push(` ${ansi.dim("- Provider:")}`);
|
|
138
|
-
for (const line of detailLines) {
|
|
139
|
-
styled.push(...wrapWithPrefix(line, " - ", width).map((ln) => ansi.dim(ln)));
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (safeHint) {
|
|
143
|
-
styled.push("");
|
|
144
|
-
styled.push(
|
|
145
|
-
...wrapWithPrefix(`Hint: ${safeHint}`, " - ", width).map((line) => ansi.dim(line))
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
console.error(`
|
|
149
|
-
${styled.join("\n")}
|
|
150
|
-
`);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
console.error(`
|
|
154
|
-
${lines.join("\n")}
|
|
155
|
-
`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
function formatCommanderError(message) {
|
|
159
|
-
const jsonMode = !process.stdout.isTTY || process.argv.includes("--json");
|
|
160
|
-
const lines = message.trimEnd().split("\n").filter((line) => line.trim() !== "");
|
|
161
|
-
if (lines.length === 0) return message;
|
|
162
|
-
const [first, ...rest] = lines;
|
|
163
|
-
const detail = first.replace(/^error:\s*/i, "").trim();
|
|
164
|
-
if (jsonMode) {
|
|
165
|
-
const err = {
|
|
166
|
-
error: {
|
|
167
|
-
code: "INVALID_ARGS",
|
|
168
|
-
message: detail,
|
|
169
|
-
...rest.length > 0 && { hint: rest.map((l) => l.trim()).join(" ") }
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
return JSON.stringify(err, null, 2) + "\n";
|
|
173
|
-
}
|
|
174
|
-
if (!supportsStderrStyling()) return message;
|
|
175
|
-
const styled = [
|
|
176
|
-
` ${ansi.red("\u2717")} ${ansi.boldRed("Error")}`,
|
|
177
|
-
` ${ansi.red(detail)}`,
|
|
178
|
-
...rest.map((line) => ` ${ansi.dim(line)}`)
|
|
179
|
-
];
|
|
180
|
-
return `
|
|
181
|
-
${styled.join("\n")}
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// src/lib/output.ts
|
|
186
|
-
var forceJSON = false;
|
|
187
|
-
var quiet = false;
|
|
188
|
-
var verbose = false;
|
|
189
|
-
var debugMode = false;
|
|
190
|
-
var timeout;
|
|
191
|
-
var reveal = false;
|
|
192
|
-
function setFlags(opts) {
|
|
193
|
-
forceJSON = opts.json ?? false;
|
|
194
|
-
quiet = opts.quiet ?? false;
|
|
195
|
-
verbose = opts.verbose ?? false;
|
|
196
|
-
debugMode = opts.debug ?? false;
|
|
197
|
-
reveal = opts.reveal ?? false;
|
|
198
|
-
timeout = opts.timeout;
|
|
199
|
-
}
|
|
200
|
-
function isRevealMode() {
|
|
201
|
-
return reveal;
|
|
202
|
-
}
|
|
203
|
-
function isJSONMode() {
|
|
204
|
-
if (forceJSON) return true;
|
|
205
|
-
return !process.stdout.isTTY;
|
|
206
|
-
}
|
|
207
|
-
function printJSON(value) {
|
|
208
|
-
console.log(JSON.stringify(value, null, 2));
|
|
209
|
-
}
|
|
210
|
-
function printHuman(humanText, jsonValue) {
|
|
211
|
-
if (isJSONMode()) {
|
|
212
|
-
printJSON(jsonValue);
|
|
213
|
-
} else {
|
|
214
|
-
process.stdout.write(humanText);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function debug(message, ...args) {
|
|
218
|
-
if (debugMode) {
|
|
219
|
-
console.error(`[debug] ${message}`, ...args);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// src/lib/errors.ts
|
|
224
|
-
var ErrorCode = {
|
|
225
|
-
AUTH_REQUIRED: "AUTH_REQUIRED",
|
|
226
|
-
INVALID_API_KEY: "INVALID_API_KEY",
|
|
227
|
-
NETWORK_NOT_ENABLED: "NETWORK_NOT_ENABLED",
|
|
228
|
-
INVALID_ACCESS_KEY: "INVALID_ACCESS_KEY",
|
|
229
|
-
ACCESS_KEY_REQUIRED: "ACCESS_KEY_REQUIRED",
|
|
230
|
-
APP_REQUIRED: "APP_REQUIRED",
|
|
231
|
-
ADMIN_API_ERROR: "ADMIN_API_ERROR",
|
|
232
|
-
NETWORK_ERROR: "NETWORK_ERROR",
|
|
233
|
-
RPC_ERROR: "RPC_ERROR",
|
|
234
|
-
INVALID_ARGS: "INVALID_ARGS",
|
|
235
|
-
NOT_FOUND: "NOT_FOUND",
|
|
236
|
-
RATE_LIMITED: "RATE_LIMITED",
|
|
237
|
-
PAYMENT_REQUIRED: "PAYMENT_REQUIRED",
|
|
238
|
-
SETUP_REQUIRED: "SETUP_REQUIRED",
|
|
239
|
-
INTERNAL_ERROR: "INTERNAL_ERROR"
|
|
240
|
-
};
|
|
241
|
-
var RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
242
|
-
ErrorCode.RATE_LIMITED,
|
|
243
|
-
ErrorCode.NETWORK_ERROR
|
|
244
|
-
]);
|
|
245
|
-
var EXIT_CODES = {
|
|
246
|
-
AUTH_REQUIRED: 3,
|
|
247
|
-
INVALID_API_KEY: 3,
|
|
248
|
-
NETWORK_NOT_ENABLED: 3,
|
|
249
|
-
INVALID_ACCESS_KEY: 3,
|
|
250
|
-
ACCESS_KEY_REQUIRED: 3,
|
|
251
|
-
APP_REQUIRED: 3,
|
|
252
|
-
INVALID_ARGS: 2,
|
|
253
|
-
NOT_FOUND: 4,
|
|
254
|
-
RATE_LIMITED: 5,
|
|
255
|
-
NETWORK_ERROR: 6,
|
|
256
|
-
RPC_ERROR: 7,
|
|
257
|
-
ADMIN_API_ERROR: 8,
|
|
258
|
-
PAYMENT_REQUIRED: 9,
|
|
259
|
-
SETUP_REQUIRED: 3,
|
|
260
|
-
INTERNAL_ERROR: 1
|
|
261
|
-
};
|
|
262
|
-
var CLIError = class extends Error {
|
|
263
|
-
code;
|
|
264
|
-
hint;
|
|
265
|
-
details;
|
|
266
|
-
data;
|
|
267
|
-
constructor(code, message, hint, details, data) {
|
|
268
|
-
super(message);
|
|
269
|
-
this.name = "CLIError";
|
|
270
|
-
this.code = code;
|
|
271
|
-
this.hint = hint;
|
|
272
|
-
this.details = details;
|
|
273
|
-
this.data = data;
|
|
274
|
-
}
|
|
275
|
-
toJSON() {
|
|
276
|
-
return {
|
|
277
|
-
error: {
|
|
278
|
-
code: this.code,
|
|
279
|
-
message: this.message,
|
|
280
|
-
...this.hint && { hint: this.hint },
|
|
281
|
-
...this.details && { details: this.details },
|
|
282
|
-
...this.data !== void 0 && { data: this.data },
|
|
283
|
-
retryable: RETRYABLE_CODES.has(this.code)
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
format() {
|
|
288
|
-
let out = `${this.code}: ${this.message}`;
|
|
289
|
-
if (this.hint) out += `
|
|
290
|
-
Hint: ${this.hint}`;
|
|
291
|
-
return out;
|
|
292
|
-
}
|
|
293
|
-
};
|
|
294
|
-
function errAuthRequired() {
|
|
295
|
-
return new CLIError(
|
|
296
|
-
ErrorCode.AUTH_REQUIRED,
|
|
297
|
-
"Not authenticated. Set ALCHEMY_API_KEY or run 'alchemy config set api-key <key>'.",
|
|
298
|
-
"alchemy config set api-key <your-key>"
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
function errAccessKeyRequired() {
|
|
302
|
-
return new CLIError(
|
|
303
|
-
ErrorCode.ACCESS_KEY_REQUIRED,
|
|
304
|
-
"Access key required. Set ALCHEMY_ACCESS_KEY or run 'alchemy config set access-key <key>'.",
|
|
305
|
-
"Get an access key: https://www.alchemy.com/docs/reference/admin-api/overview"
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
function errInvalidAPIKey(details) {
|
|
309
|
-
return new CLIError(
|
|
310
|
-
ErrorCode.INVALID_API_KEY,
|
|
311
|
-
"Invalid API key. Check your key and try again.",
|
|
312
|
-
"alchemy config set api-key <your-key>",
|
|
313
|
-
details
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
function errNetworkNotEnabled(network, details) {
|
|
317
|
-
const networkLabel = network.toLowerCase().replace(/_/g, "-");
|
|
318
|
-
return new CLIError(
|
|
319
|
-
ErrorCode.NETWORK_NOT_ENABLED,
|
|
320
|
-
`API key is valid, but ${networkLabel} is not enabled for this app.`,
|
|
321
|
-
void 0,
|
|
322
|
-
details
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
function errNetwork(detail) {
|
|
326
|
-
return new CLIError(
|
|
327
|
-
ErrorCode.NETWORK_ERROR,
|
|
328
|
-
`Network error: ${detail}`,
|
|
329
|
-
"Check your internet connection and try again."
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
var RPC_ERROR_HINTS = {
|
|
333
|
-
[-32700]: "Parse error. The request JSON is malformed.",
|
|
334
|
-
[-32600]: "Invalid request. Check the JSON-RPC request format.",
|
|
335
|
-
[-32601]: "Method not supported. Check the method name and ensure your plan supports it.",
|
|
336
|
-
[-32602]: "Invalid parameters. Check argument types and format.",
|
|
337
|
-
[-32603]: "Internal JSON-RPC error."
|
|
338
|
-
};
|
|
339
|
-
function errRPC(code, message) {
|
|
340
|
-
const hint = RPC_ERROR_HINTS[code];
|
|
341
|
-
return new CLIError(ErrorCode.RPC_ERROR, `RPC error ${code}: ${message}`, hint);
|
|
342
|
-
}
|
|
343
|
-
function errInvalidArgs(detail) {
|
|
344
|
-
return new CLIError(ErrorCode.INVALID_ARGS, detail);
|
|
345
|
-
}
|
|
346
|
-
function errNotFound(resource) {
|
|
347
|
-
return new CLIError(ErrorCode.NOT_FOUND, `Not found: ${resource}`);
|
|
348
|
-
}
|
|
349
|
-
function errRateLimited() {
|
|
350
|
-
return new CLIError(
|
|
351
|
-
ErrorCode.RATE_LIMITED,
|
|
352
|
-
"Rate limited. Please wait and try again.",
|
|
353
|
-
"Consider upgrading your Alchemy plan for higher rate limits."
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
function errInvalidAccessKey() {
|
|
357
|
-
return new CLIError(
|
|
358
|
-
ErrorCode.INVALID_ACCESS_KEY,
|
|
359
|
-
"Invalid access key. Check your key and try again.",
|
|
360
|
-
"Get an access key: https://www.alchemy.com/docs/reference/admin-api/overview"
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
function errAccessDenied(detail) {
|
|
364
|
-
const message = detail ? `Access denied: ${detail}` : "Access denied. Your access key may not have permission for this operation.";
|
|
365
|
-
return new CLIError(
|
|
366
|
-
ErrorCode.INVALID_ACCESS_KEY,
|
|
367
|
-
message,
|
|
368
|
-
"Check your account tier and feature access at https://dashboard.alchemy.com/"
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
function errAppRequired() {
|
|
372
|
-
return new CLIError(
|
|
373
|
-
ErrorCode.APP_REQUIRED,
|
|
374
|
-
"No app selected. Set an app to resolve the API key automatically.",
|
|
375
|
-
"alchemy config set app <app-id>"
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
function errWalletKeyRequired() {
|
|
379
|
-
return new CLIError(
|
|
380
|
-
ErrorCode.AUTH_REQUIRED,
|
|
381
|
-
"Wallet key required for x402. Set ALCHEMY_WALLET_KEY, run 'alchemy wallet generate', or use --wallet-key-file.",
|
|
382
|
-
"alchemy wallet generate"
|
|
383
|
-
);
|
|
384
|
-
}
|
|
385
|
-
function errAdminAPI(status, message) {
|
|
386
|
-
return new CLIError(
|
|
387
|
-
ErrorCode.ADMIN_API_ERROR,
|
|
388
|
-
`Admin API error (HTTP ${status}): ${message}`
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
function errSetupRequired(data) {
|
|
392
|
-
return new CLIError(
|
|
393
|
-
ErrorCode.SETUP_REQUIRED,
|
|
394
|
-
"Setup required before running in non-interactive mode.",
|
|
395
|
-
"Run 'alchemy' in a TTY for guided onboarding, or run 'alchemy setup status --json' for machine-readable remediation steps.",
|
|
396
|
-
void 0,
|
|
397
|
-
data
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
var replMode = false;
|
|
401
|
-
function setReplMode(enabled) {
|
|
402
|
-
replMode = enabled;
|
|
403
|
-
}
|
|
404
|
-
function exitWithError(err) {
|
|
405
|
-
const cliErr = err instanceof CLIError ? err : new CLIError(
|
|
406
|
-
ErrorCode.INTERNAL_ERROR,
|
|
407
|
-
err instanceof Error ? err.message : String(err)
|
|
408
|
-
);
|
|
409
|
-
printError(cliErr);
|
|
410
|
-
if (replMode) {
|
|
411
|
-
throw cliErr;
|
|
412
|
-
}
|
|
413
|
-
process.exit(EXIT_CODES[cliErr.code]);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// src/lib/secrets.ts
|
|
417
|
-
function maskSecret(value) {
|
|
418
|
-
if (value.length <= 8) return "\u2022".repeat(value.length);
|
|
419
|
-
return value.slice(0, 4) + "\u2022".repeat(value.length - 8) + value.slice(-4);
|
|
420
|
-
}
|
|
421
|
-
function maskIf(value) {
|
|
422
|
-
return isRevealMode() ? value : maskSecret(value);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// src/lib/config.ts
|
|
426
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
427
|
-
import { homedir } from "os";
|
|
428
|
-
import { join, dirname } from "path";
|
|
429
|
-
import { z } from "zod";
|
|
430
|
-
var KEY_MAP = {
|
|
431
|
-
"api-key": "api_key",
|
|
432
|
-
api_key: "api_key",
|
|
433
|
-
"access-key": "access_key",
|
|
434
|
-
access_key: "access_key",
|
|
435
|
-
"webhook-api-key": "webhook_api_key",
|
|
436
|
-
webhook_api_key: "webhook_api_key",
|
|
437
|
-
network: "network",
|
|
438
|
-
verbose: "verbose",
|
|
439
|
-
"wallet-key-file": "wallet_key_file",
|
|
440
|
-
wallet_key_file: "wallet_key_file",
|
|
441
|
-
"wallet-address": "wallet_address",
|
|
442
|
-
wallet_address: "wallet_address",
|
|
443
|
-
x402: "x402"
|
|
444
|
-
};
|
|
445
|
-
var SAFE_ID_RE = /^[A-Za-z0-9:_-]{1,128}$/;
|
|
446
|
-
var SAFE_NETWORK_RE = /^[A-Za-z0-9:_-]{1,128}$/;
|
|
447
|
-
var MAX_SECRET_LEN = 512;
|
|
448
|
-
var MAX_APP_NAME_LEN = 128;
|
|
449
|
-
var CONTROL_CHAR_RE = /[\u0000-\u001f\u007f]/;
|
|
450
|
-
var safeTextSchema = (maxLen) => z.string().min(1).max(maxLen).refine((value) => !CONTROL_CHAR_RE.test(value));
|
|
451
|
-
var appConfigSchema = z.object({
|
|
452
|
-
id: z.string().regex(SAFE_ID_RE),
|
|
453
|
-
name: safeTextSchema(MAX_APP_NAME_LEN),
|
|
454
|
-
apiKey: safeTextSchema(MAX_SECRET_LEN),
|
|
455
|
-
webhookApiKey: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0)
|
|
456
|
-
}).strip();
|
|
457
|
-
var MAX_PATH_LEN = 4096;
|
|
458
|
-
var configSchema = z.object({
|
|
459
|
-
api_key: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
|
|
460
|
-
access_key: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
|
|
461
|
-
webhook_api_key: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
|
|
462
|
-
app: appConfigSchema.optional().catch(void 0),
|
|
463
|
-
network: z.string().regex(SAFE_NETWORK_RE).optional().catch(void 0),
|
|
464
|
-
verbose: z.boolean().optional().catch(void 0),
|
|
465
|
-
wallet_key_file: safeTextSchema(MAX_PATH_LEN).optional().catch(void 0),
|
|
466
|
-
wallet_address: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
|
|
467
|
-
x402: z.boolean().optional().catch(void 0)
|
|
468
|
-
}).strip();
|
|
469
|
-
function sanitizeConfig(input) {
|
|
470
|
-
const parsed = configSchema.safeParse(input);
|
|
471
|
-
if (!parsed.success) {
|
|
472
|
-
return {};
|
|
473
|
-
}
|
|
474
|
-
return parsed.data;
|
|
475
|
-
}
|
|
476
|
-
function getHome() {
|
|
477
|
-
return process.env.HOME || homedir();
|
|
478
|
-
}
|
|
479
|
-
function configPath() {
|
|
480
|
-
if (process.env.ALCHEMY_CONFIG) return process.env.ALCHEMY_CONFIG;
|
|
481
|
-
const configHome = process.env.XDG_CONFIG_HOME || join(getHome(), ".config");
|
|
482
|
-
return join(configHome, "alchemy", "config.json");
|
|
483
|
-
}
|
|
484
|
-
function configDir() {
|
|
485
|
-
return dirname(configPath());
|
|
486
|
-
}
|
|
487
|
-
function load() {
|
|
488
|
-
const p = configPath();
|
|
489
|
-
if (!existsSync(p)) return {};
|
|
490
|
-
try {
|
|
491
|
-
const data = readFileSync(p, "utf-8");
|
|
492
|
-
return sanitizeConfig(JSON.parse(data));
|
|
493
|
-
} catch {
|
|
494
|
-
console.error(`warning: could not parse config file at ${p} \u2014 using defaults`);
|
|
495
|
-
return {};
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
function save(cfg) {
|
|
499
|
-
const p = configPath();
|
|
500
|
-
const sanitized = sanitizeConfig(cfg);
|
|
501
|
-
mkdirSync(dirname(p), { recursive: true, mode: 493 });
|
|
502
|
-
writeFileSync(p, JSON.stringify(sanitized, null, 2) + "\n", {
|
|
503
|
-
mode: 384
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
function get(cfg, key) {
|
|
507
|
-
if (key === "app") {
|
|
508
|
-
if (!cfg.app) return void 0;
|
|
509
|
-
return `${cfg.app.name} (${cfg.app.id})`;
|
|
510
|
-
}
|
|
511
|
-
const mapped = KEY_MAP[key];
|
|
512
|
-
if (!mapped) return void 0;
|
|
513
|
-
const value = cfg[mapped];
|
|
514
|
-
if (value === void 0) return void 0;
|
|
515
|
-
if (typeof value === "boolean") return String(value);
|
|
516
|
-
if (typeof value === "string") return value;
|
|
517
|
-
return void 0;
|
|
518
|
-
}
|
|
519
|
-
function toMap(cfg) {
|
|
520
|
-
const m = {};
|
|
521
|
-
if (cfg.api_key) m["api-key"] = maskIf(cfg.api_key);
|
|
522
|
-
if (cfg.access_key) m["access-key"] = maskIf(cfg.access_key);
|
|
523
|
-
if (cfg.webhook_api_key) m["webhook-api-key"] = maskIf(cfg.webhook_api_key);
|
|
524
|
-
if (cfg.app) m["app"] = `${cfg.app.name} (${cfg.app.id})`;
|
|
525
|
-
if (cfg.network) m["network"] = cfg.network;
|
|
526
|
-
if (cfg.verbose !== void 0) m["verbose"] = String(cfg.verbose);
|
|
527
|
-
if (cfg.wallet_key_file) m["wallet-key-file"] = cfg.wallet_key_file;
|
|
528
|
-
if (cfg.wallet_address) m["wallet-address"] = cfg.wallet_address;
|
|
529
|
-
if (cfg.x402 !== void 0) m["x402"] = String(cfg.x402);
|
|
530
|
-
return m;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// src/lib/terminal-ui.ts
|
|
534
|
-
import * as readline from "readline";
|
|
535
|
-
import { stdin, stdout } from "process";
|
|
536
|
-
var ansi2 = {
|
|
537
|
-
cyan: esc("36"),
|
|
538
|
-
dim: esc("2"),
|
|
539
|
-
green: esc("32"),
|
|
540
|
-
red: esc("31"),
|
|
541
|
-
purple: rgb(180, 160, 255)
|
|
542
|
-
};
|
|
543
|
-
var FLOW_PIPE = "\u2502";
|
|
544
|
-
function optionLabel(option) {
|
|
545
|
-
return option.label ?? String(option.value);
|
|
546
|
-
}
|
|
547
|
-
function printCancel(message) {
|
|
548
|
-
if (!message) return;
|
|
549
|
-
console.log(` ${ansi2.dim(FLOW_PIPE)}`);
|
|
550
|
-
console.log(` ${ansi2.dim(message)}`);
|
|
551
|
-
}
|
|
552
|
-
function clearRenderedLines(lines) {
|
|
553
|
-
for (let i = 0; i < lines; i += 1) {
|
|
554
|
-
readline.clearLine(stdout, 0);
|
|
555
|
-
readline.cursorTo(stdout, 0);
|
|
556
|
-
if (i < lines - 1) {
|
|
557
|
-
readline.moveCursor(stdout, 0, -1);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
function suspendStdinKeypressListeners() {
|
|
562
|
-
const listeners = stdin.listeners("keypress");
|
|
563
|
-
for (const listener of listeners) {
|
|
564
|
-
stdin.removeListener("keypress", listener);
|
|
565
|
-
}
|
|
566
|
-
return () => {
|
|
567
|
-
for (const listener of listeners) {
|
|
568
|
-
stdin.on("keypress", listener);
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
async function runListPrompt(opts) {
|
|
573
|
-
if (!stdin.isTTY || !stdout.isTTY) {
|
|
574
|
-
const initial = opts.initialValue ?? opts.options.find((o) => !o.disabled)?.value ?? null;
|
|
575
|
-
return { value: initial, cancelled: false };
|
|
576
|
-
}
|
|
577
|
-
readline.emitKeypressEvents(stdin);
|
|
578
|
-
const restoreKeypressListeners = suspendStdinKeypressListeners();
|
|
579
|
-
const previousRawMode = stdin.isRaw;
|
|
580
|
-
stdin.resume();
|
|
581
|
-
stdin.setRawMode(true);
|
|
582
|
-
let query = "";
|
|
583
|
-
let cursor = Math.max(
|
|
584
|
-
0,
|
|
585
|
-
opts.options.findIndex((o) => o.value === opts.initialValue && !o.disabled)
|
|
586
|
-
);
|
|
587
|
-
const selected = /* @__PURE__ */ new Set();
|
|
588
|
-
const maxVisible = 8;
|
|
589
|
-
let renderedLines = 0;
|
|
590
|
-
const getFiltered = () => {
|
|
591
|
-
if (!opts.filterable || !query.trim()) return opts.options;
|
|
592
|
-
const q = query.toLowerCase();
|
|
593
|
-
return opts.options.filter((option) => {
|
|
594
|
-
const label = optionLabel(option).toLowerCase();
|
|
595
|
-
const hint = (option.hint ?? "").toLowerCase();
|
|
596
|
-
const value = String(option.value).toLowerCase();
|
|
597
|
-
return label.includes(q) || hint.includes(q) || value.includes(q);
|
|
598
|
-
});
|
|
599
|
-
};
|
|
600
|
-
const normalizeCursor = (filtered) => {
|
|
601
|
-
if (filtered.length === 0) {
|
|
602
|
-
cursor = 0;
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
if (cursor >= filtered.length) cursor = filtered.length - 1;
|
|
606
|
-
if (cursor < 0) cursor = 0;
|
|
607
|
-
if (filtered[cursor]?.disabled) {
|
|
608
|
-
const next = filtered.findIndex((o) => !o.disabled);
|
|
609
|
-
cursor = next >= 0 ? next : 0;
|
|
610
|
-
}
|
|
611
|
-
};
|
|
612
|
-
const render = () => {
|
|
613
|
-
const filtered = getFiltered();
|
|
614
|
-
normalizeCursor(filtered);
|
|
615
|
-
if (renderedLines > 0) clearRenderedLines(renderedLines);
|
|
616
|
-
const lines = [];
|
|
617
|
-
const suffix = opts.filterable && query ? ` ${ansi2.dim(`(${query})`)}` : "";
|
|
618
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)}`);
|
|
619
|
-
lines.push(` ${ansi2.cyan("\u25C6")} ${opts.message}${suffix}`);
|
|
620
|
-
if (filtered.length === 0) {
|
|
621
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.dim("No matches found")}`);
|
|
622
|
-
} else {
|
|
623
|
-
const start = Math.max(0, Math.min(cursor - 3, Math.max(0, filtered.length - maxVisible)));
|
|
624
|
-
const visible = filtered.slice(start, start + maxVisible);
|
|
625
|
-
for (let i = 0; i < visible.length; i += 1) {
|
|
626
|
-
const option = visible[i];
|
|
627
|
-
const active = start + i === cursor;
|
|
628
|
-
const disabled = option.disabled === true;
|
|
629
|
-
const selectedMark = opts.allowMultiple ? selected.has(option.value) ? ansi2.green("\u25C6") : ansi2.dim("\u25C7") : active ? ansi2.cyan("\u25C6") : ansi2.dim("\u25C7");
|
|
630
|
-
const label = optionLabel(option);
|
|
631
|
-
const value = disabled ? ansi2.dim(label) : label;
|
|
632
|
-
const hint = option.hint ? ` ${ansi2.dim(`\u2014 ${option.hint}`)}` : "";
|
|
633
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${selectedMark} ${value}${hint}`);
|
|
634
|
-
}
|
|
635
|
-
if (filtered.length > maxVisible) {
|
|
636
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.dim(`${filtered.length} options`)}`);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
if (opts.filterable && query.length === 0 && opts.placeholder) {
|
|
640
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.dim(opts.placeholder)}`);
|
|
641
|
-
} else if (opts.allowMultiple) {
|
|
642
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.dim("Space to toggle, Enter to confirm")}`);
|
|
643
|
-
} else {
|
|
644
|
-
lines.push(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.dim("Use arrows and press Enter")}`);
|
|
645
|
-
}
|
|
646
|
-
stdout.write(lines.join("\n"));
|
|
647
|
-
renderedLines = lines.length;
|
|
648
|
-
};
|
|
649
|
-
const cleanup = () => {
|
|
650
|
-
if (renderedLines > 0) clearRenderedLines(renderedLines);
|
|
651
|
-
stdin.setRawMode(previousRawMode);
|
|
652
|
-
stdin.removeListener("keypress", onKeypress);
|
|
653
|
-
restoreKeypressListeners();
|
|
654
|
-
if (!previousRawMode) {
|
|
655
|
-
stdin.pause();
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
const commitSingleLine = (text) => {
|
|
659
|
-
if (opts.commitLabel === null) return;
|
|
660
|
-
const label = opts.commitLabel ?? opts.message;
|
|
661
|
-
console.log(` ${ansi2.green("\u25C6")} ${label}: ${text}`);
|
|
662
|
-
};
|
|
663
|
-
const onKeypress = (str, key) => {
|
|
664
|
-
const filtered = getFiltered();
|
|
665
|
-
const current = filtered[cursor];
|
|
666
|
-
if (key.name === "escape" || key.ctrl && key.name === "c") {
|
|
667
|
-
cleanup();
|
|
668
|
-
resolver({ value: null, cancelled: true });
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
if (key.name === "return") {
|
|
672
|
-
if (opts.allowMultiple) {
|
|
673
|
-
if (opts.required && selected.size === 0) return;
|
|
674
|
-
cleanup();
|
|
675
|
-
const values = Array.from(selected);
|
|
676
|
-
const labels = opts.options.filter((o) => values.includes(o.value)).map((o) => optionLabel(o)).join(", ");
|
|
677
|
-
commitSingleLine(labels || "none");
|
|
678
|
-
resolver({ value: values, cancelled: false });
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
if (!current || current.disabled) return;
|
|
682
|
-
cleanup();
|
|
683
|
-
commitSingleLine(optionLabel(current));
|
|
684
|
-
resolver({ value: current.value, cancelled: false });
|
|
685
|
-
return;
|
|
686
|
-
}
|
|
687
|
-
if (opts.allowMultiple && key.name === "space") {
|
|
688
|
-
if (!current || current.disabled) return;
|
|
689
|
-
if (selected.has(current.value)) selected.delete(current.value);
|
|
690
|
-
else selected.add(current.value);
|
|
691
|
-
render();
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
if (key.name === "up") {
|
|
695
|
-
if (filtered.length === 0) return;
|
|
696
|
-
let next = cursor - 1;
|
|
697
|
-
while (next >= 0 && filtered[next]?.disabled) next -= 1;
|
|
698
|
-
if (next >= 0) cursor = next;
|
|
699
|
-
render();
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
702
|
-
if (key.name === "down") {
|
|
703
|
-
if (filtered.length === 0) return;
|
|
704
|
-
let next = cursor + 1;
|
|
705
|
-
while (next < filtered.length && filtered[next]?.disabled) next += 1;
|
|
706
|
-
if (next < filtered.length) cursor = next;
|
|
707
|
-
render();
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
if (opts.filterable && key.name === "backspace") {
|
|
711
|
-
if (query.length > 0) {
|
|
712
|
-
query = query.slice(0, -1);
|
|
713
|
-
render();
|
|
714
|
-
}
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
if (opts.filterable && str && !key.ctrl && !key.meta && str >= " " && str !== "\x7F") {
|
|
718
|
-
query += str;
|
|
719
|
-
cursor = 0;
|
|
720
|
-
render();
|
|
721
|
-
}
|
|
722
|
-
};
|
|
723
|
-
let resolver;
|
|
724
|
-
const done = new Promise((resolve) => {
|
|
725
|
-
resolver = resolve;
|
|
726
|
-
});
|
|
727
|
-
stdin.on("keypress", onKeypress);
|
|
728
|
-
render();
|
|
729
|
-
return done;
|
|
730
|
-
}
|
|
731
|
-
async function promptText(opts) {
|
|
732
|
-
if (!stdin.isTTY || !stdout.isTTY) {
|
|
733
|
-
return opts.defaultValue ?? opts.initialValue ?? "";
|
|
734
|
-
}
|
|
735
|
-
stdin.resume();
|
|
736
|
-
stdin.ref?.();
|
|
737
|
-
const restoreKeypressListeners = suspendStdinKeypressListeners();
|
|
738
|
-
const rl = readline.createInterface({ input: stdin, output: stdout, terminal: true });
|
|
739
|
-
console.log(` ${ansi2.dim(FLOW_PIPE)}`);
|
|
740
|
-
const question = ` ${ansi2.cyan("\u25C6")} ${opts.message}${opts.placeholder ? ` ${ansi2.dim(`(${opts.placeholder})`)}` : ""}: `;
|
|
741
|
-
const previousRawMode = stdin.isRaw;
|
|
742
|
-
if (previousRawMode) stdin.setRawMode(false);
|
|
743
|
-
const value = await new Promise((resolve) => {
|
|
744
|
-
rl.on("SIGINT", () => resolve(null));
|
|
745
|
-
rl.question(question, (answer) => resolve(answer));
|
|
746
|
-
});
|
|
747
|
-
rl.close();
|
|
748
|
-
restoreKeypressListeners();
|
|
749
|
-
if (previousRawMode) stdin.setRawMode(true);
|
|
750
|
-
if (opts.clearAfterSubmit) {
|
|
751
|
-
clearRenderedLines(2);
|
|
752
|
-
}
|
|
753
|
-
if (value === null) {
|
|
754
|
-
printCancel(opts.cancelMessage);
|
|
755
|
-
return null;
|
|
756
|
-
}
|
|
757
|
-
if (!value.trim() && opts.defaultValue !== void 0) return opts.defaultValue;
|
|
758
|
-
if (!value.trim() && opts.initialValue !== void 0) return opts.initialValue;
|
|
759
|
-
return value;
|
|
760
|
-
}
|
|
761
|
-
async function promptConfirm(opts) {
|
|
762
|
-
const defaultYes = opts.initialValue ?? true;
|
|
763
|
-
const suffix = defaultYes ? "[Y/n]" : "[y/N]";
|
|
764
|
-
const answer = await promptText({
|
|
765
|
-
message: `${opts.message} ${suffix}`,
|
|
766
|
-
cancelMessage: opts.cancelMessage
|
|
767
|
-
});
|
|
768
|
-
if (answer === null) return null;
|
|
769
|
-
const normalized = answer.trim().toLowerCase();
|
|
770
|
-
if (!normalized) return defaultYes;
|
|
771
|
-
if (normalized === "y" || normalized === "yes") return true;
|
|
772
|
-
if (normalized === "n" || normalized === "no") return false;
|
|
773
|
-
return defaultYes;
|
|
774
|
-
}
|
|
775
|
-
async function promptSelect(opts) {
|
|
776
|
-
const result = await runListPrompt({
|
|
777
|
-
message: opts.message,
|
|
778
|
-
options: opts.options,
|
|
779
|
-
initialValue: opts.initialValue,
|
|
780
|
-
commitLabel: opts.commitLabel ?? "Selected"
|
|
781
|
-
});
|
|
782
|
-
if (result.cancelled) {
|
|
783
|
-
printCancel(opts.cancelMessage);
|
|
784
|
-
return null;
|
|
785
|
-
}
|
|
786
|
-
return result.value;
|
|
787
|
-
}
|
|
788
|
-
async function promptAutocomplete(opts) {
|
|
789
|
-
const result = await runListPrompt({
|
|
790
|
-
message: opts.message,
|
|
791
|
-
options: opts.options,
|
|
792
|
-
initialValue: opts.initialValue,
|
|
793
|
-
placeholder: opts.placeholder,
|
|
794
|
-
filterable: true,
|
|
795
|
-
commitLabel: opts.commitLabel ?? "Selected"
|
|
796
|
-
});
|
|
797
|
-
if (result.cancelled) {
|
|
798
|
-
printCancel(opts.cancelMessage);
|
|
799
|
-
return null;
|
|
800
|
-
}
|
|
801
|
-
return result.value;
|
|
802
|
-
}
|
|
803
|
-
async function promptMultiselect(opts) {
|
|
804
|
-
const result = await runListPrompt({
|
|
805
|
-
message: opts.message,
|
|
806
|
-
options: opts.options,
|
|
807
|
-
allowMultiple: true,
|
|
808
|
-
required: opts.required,
|
|
809
|
-
commitLabel: "Selected"
|
|
810
|
-
});
|
|
811
|
-
if (result.cancelled) {
|
|
812
|
-
printCancel(opts.cancelMessage);
|
|
813
|
-
return null;
|
|
814
|
-
}
|
|
815
|
-
return result.value;
|
|
816
|
-
}
|
|
817
|
-
async function runWithSpinner(label, doneLabel, fn) {
|
|
818
|
-
if (!stdout.isTTY) return fn();
|
|
819
|
-
const spinFrames = ["\u2B16", "\u2B18", "\u2B17", "\u2B19"];
|
|
820
|
-
let tick = 0;
|
|
821
|
-
const render = () => {
|
|
822
|
-
readline.clearLine(stdout, 0);
|
|
823
|
-
readline.cursorTo(stdout, 0);
|
|
824
|
-
const spin = spinFrames[tick % spinFrames.length];
|
|
825
|
-
stdout.write(` ${ansi2.dim(FLOW_PIPE)} ${ansi2.purple(spin)} ${label}`);
|
|
826
|
-
tick += 1;
|
|
827
|
-
};
|
|
828
|
-
render();
|
|
829
|
-
const timer = setInterval(render, 160);
|
|
830
|
-
try {
|
|
831
|
-
const result = await fn();
|
|
832
|
-
clearInterval(timer);
|
|
833
|
-
readline.clearLine(stdout, 0);
|
|
834
|
-
readline.cursorTo(stdout, 0);
|
|
835
|
-
stdout.write(` ${ansi2.green("\u25C6")} ${doneLabel}
|
|
836
|
-
`);
|
|
837
|
-
return result;
|
|
838
|
-
} catch (err) {
|
|
839
|
-
clearInterval(timer);
|
|
840
|
-
readline.clearLine(stdout, 0);
|
|
841
|
-
readline.cursorTo(stdout, 0);
|
|
842
|
-
stdout.write(` ${ansi2.red("\u2717")} ${label}
|
|
843
|
-
`);
|
|
844
|
-
throw err;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// src/lib/ui.ts
|
|
849
|
-
import Table from "cli-table3";
|
|
850
|
-
var ansi3 = {
|
|
851
|
-
green: esc("32"),
|
|
852
|
-
red: esc("31"),
|
|
853
|
-
dim: esc("2"),
|
|
854
|
-
cyan: esc("36"),
|
|
855
|
-
bold: esc("1"),
|
|
856
|
-
yellow: esc("33"),
|
|
857
|
-
// Alchemy brand colors
|
|
858
|
-
brand: rgb(54, 63, 249),
|
|
859
|
-
// Primary #363FF9
|
|
860
|
-
brandSecondary: rgb(139, 92, 246)
|
|
861
|
-
// Secondary #8B5CF6
|
|
862
|
-
};
|
|
863
|
-
var stripAnsi = (s) => s.replace(/\x1B\[[0-9;]*m/g, "");
|
|
864
|
-
function wrap(fn) {
|
|
865
|
-
return (s) => isJSONMode() ? s : fn(s);
|
|
866
|
-
}
|
|
867
|
-
var green = wrap(ansi3.green);
|
|
868
|
-
var red = wrap(ansi3.red);
|
|
869
|
-
var dim = wrap(ansi3.dim);
|
|
870
|
-
var cyan = wrap(ansi3.cyan);
|
|
871
|
-
var bold = wrap(ansi3.bold);
|
|
872
|
-
var yellow = wrap(ansi3.yellow);
|
|
873
|
-
var brand = wrap(ansi3.brand);
|
|
874
|
-
var suppressBrandedHelp = false;
|
|
875
|
-
function setBrandedHelpSuppressed(suppressed) {
|
|
876
|
-
suppressBrandedHelp = suppressed;
|
|
877
|
-
}
|
|
878
|
-
function successBadge() {
|
|
879
|
-
return isJSONMode() ? "Success" : ansi3.green("\u2713");
|
|
880
|
-
}
|
|
881
|
-
function failBadge() {
|
|
882
|
-
return isJSONMode() ? "Failed" : ansi3.red("\u2717");
|
|
883
|
-
}
|
|
884
|
-
async function withSpinner(label, doneLabel, fn) {
|
|
885
|
-
if (isJSONMode() || quiet) return fn();
|
|
886
|
-
return runWithSpinner(label, doneLabel, fn);
|
|
887
|
-
}
|
|
888
|
-
function printKeyValueBox(pairs) {
|
|
889
|
-
if (isJSONMode()) return;
|
|
890
|
-
if (pairs.length === 0) {
|
|
891
|
-
console.log(` ${ansi3.brand("\u250C\u2500\u2500\u2510")}`);
|
|
892
|
-
console.log(` ${ansi3.brand("\u2514\u2500\u2500\u2518")}`);
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
895
|
-
const keyWidth = Math.max(...pairs.map(([k]) => stripAnsi(k).length));
|
|
896
|
-
const contentRows = pairs.map(([key, value]) => {
|
|
897
|
-
const visibleKeyLen = stripAnsi(key).length;
|
|
898
|
-
const paddedKey = key + " ".repeat(Math.max(0, keyWidth - visibleKeyLen));
|
|
899
|
-
return `${ansi3.dim(paddedKey)} ${value}`;
|
|
900
|
-
});
|
|
901
|
-
const contentWidth = Math.max(...contentRows.map((row) => stripAnsi(row).length));
|
|
902
|
-
const top = `\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`;
|
|
903
|
-
const bottom = `\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`;
|
|
904
|
-
console.log(` ${ansi3.dim(top)}`);
|
|
905
|
-
for (const row of contentRows) {
|
|
906
|
-
const visibleLen = stripAnsi(row).length;
|
|
907
|
-
const padded = row + " ".repeat(Math.max(0, contentWidth - visibleLen));
|
|
908
|
-
console.log(` ${ansi3.dim("\u2502")} ${padded} ${ansi3.dim("\u2502")}`);
|
|
909
|
-
}
|
|
910
|
-
console.log(` ${ansi3.dim(bottom)}`);
|
|
911
|
-
}
|
|
912
|
-
function emptyState(message) {
|
|
913
|
-
if (isJSONMode()) return;
|
|
914
|
-
console.log(`
|
|
915
|
-
${ansi3.dim(`\u25CB ${message}`)}`);
|
|
916
|
-
}
|
|
917
|
-
function printSyntaxJSON(obj) {
|
|
918
|
-
if (isJSONMode()) {
|
|
919
|
-
console.log(JSON.stringify(obj));
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
const raw = JSON.stringify(obj, null, 2);
|
|
923
|
-
const highlighted = raw.replace(
|
|
924
|
-
/("(?:\\.|[^"\\])*")\s*(:)?|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b|\bnull\b)/g,
|
|
925
|
-
(match, str, colon, num, lit) => {
|
|
926
|
-
if (str && colon) return ansi3.brand(str) + colon;
|
|
927
|
-
if (str) return ansi3.green(str);
|
|
928
|
-
if (num) return ansi3.cyan(num);
|
|
929
|
-
if (lit) return ansi3.yellow(lit);
|
|
930
|
-
return match;
|
|
931
|
-
}
|
|
932
|
-
);
|
|
933
|
-
console.log(highlighted);
|
|
934
|
-
}
|
|
935
|
-
function printTable(headers, rows) {
|
|
936
|
-
if (isJSONMode()) {
|
|
937
|
-
const objects = rows.map(
|
|
938
|
-
(row) => Object.fromEntries(headers.map((h, i) => [h, row[i] ?? null]))
|
|
939
|
-
);
|
|
940
|
-
console.log(JSON.stringify(objects, null, 2));
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
const table = new Table({
|
|
944
|
-
head: headers.map((h) => ansi3.brand(ansi3.bold(h))),
|
|
945
|
-
chars: {
|
|
946
|
-
top: "\u2500",
|
|
947
|
-
"top-mid": "\u252C",
|
|
948
|
-
"top-left": "\u250C",
|
|
949
|
-
"top-right": "\u2510",
|
|
950
|
-
bottom: "\u2500",
|
|
951
|
-
"bottom-mid": "\u2534",
|
|
952
|
-
"bottom-left": "\u2514",
|
|
953
|
-
"bottom-right": "\u2518",
|
|
954
|
-
left: "\u2502",
|
|
955
|
-
"left-mid": "\u251C",
|
|
956
|
-
mid: "\u2500",
|
|
957
|
-
"mid-mid": "\u253C",
|
|
958
|
-
right: "\u2502",
|
|
959
|
-
"right-mid": "\u2524",
|
|
960
|
-
middle: "\u2502"
|
|
961
|
-
},
|
|
962
|
-
style: {
|
|
963
|
-
head: [],
|
|
964
|
-
border: [],
|
|
965
|
-
"padding-left": 1,
|
|
966
|
-
"padding-right": 1
|
|
967
|
-
}
|
|
968
|
-
});
|
|
969
|
-
for (let i = 0; i < rows.length; i++) {
|
|
970
|
-
const row = i % 2 === 1 ? rows[i].map((cell) => ansi3.dim(cell)) : rows[i];
|
|
971
|
-
table.push(row);
|
|
972
|
-
}
|
|
973
|
-
const output = table.toString();
|
|
974
|
-
const dimBorders = output.replace(
|
|
975
|
-
/[┌┐└┘┬┴├┤┼─│]/g,
|
|
976
|
-
(ch) => ansi3.dim(ch)
|
|
977
|
-
);
|
|
978
|
-
console.log(dimBorders);
|
|
979
|
-
}
|
|
980
|
-
function weiToEth(wei) {
|
|
981
|
-
const divisor = 10n ** 18n;
|
|
982
|
-
const whole = wei / divisor;
|
|
983
|
-
const remainder = wei % divisor;
|
|
984
|
-
if (remainder === 0n) return `${whole}.0`;
|
|
985
|
-
const remStr = remainder.toString().padStart(18, "0").replace(/0+$/, "");
|
|
986
|
-
return `${whole}.${remStr}`;
|
|
987
|
-
}
|
|
988
|
-
function timeAgo(hexTimestamp) {
|
|
989
|
-
const seconds = parseInt(hexTimestamp, 16);
|
|
990
|
-
if (isNaN(seconds)) return hexTimestamp;
|
|
991
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
992
|
-
const diff = now - seconds;
|
|
993
|
-
if (diff < 0) return "in the future";
|
|
994
|
-
if (diff < 60) return `${diff} seconds ago`;
|
|
995
|
-
if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`;
|
|
996
|
-
if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`;
|
|
997
|
-
if (diff < 2592e3) return `${Math.floor(diff / 86400)} days ago`;
|
|
998
|
-
return `${Math.floor(diff / 2592e3)} months ago`;
|
|
999
|
-
}
|
|
1000
|
-
var EXPLORER_MAP = {
|
|
1001
|
-
"eth-mainnet": "https://etherscan.io",
|
|
1002
|
-
"eth-sepolia": "https://sepolia.etherscan.io",
|
|
1003
|
-
"eth-holesky": "https://holesky.etherscan.io",
|
|
1004
|
-
"polygon-mainnet": "https://polygonscan.com",
|
|
1005
|
-
"polygon-amoy": "https://amoy.polygonscan.com",
|
|
1006
|
-
"arb-mainnet": "https://arbiscan.io",
|
|
1007
|
-
"arb-sepolia": "https://sepolia.arbiscan.io",
|
|
1008
|
-
"opt-mainnet": "https://optimistic.etherscan.io",
|
|
1009
|
-
"opt-sepolia": "https://sepolia-optimism.etherscan.io",
|
|
1010
|
-
"base-mainnet": "https://basescan.org",
|
|
1011
|
-
"base-sepolia": "https://sepolia.basescan.org"
|
|
1012
|
-
};
|
|
1013
|
-
function etherscanTxURL(hash, network) {
|
|
1014
|
-
const base = EXPLORER_MAP[network];
|
|
1015
|
-
if (!base) return void 0;
|
|
1016
|
-
return `${base}/tx/${hash}`;
|
|
1017
|
-
}
|
|
1018
|
-
function brandedHelp(options) {
|
|
1019
|
-
if (isJSONMode() || quiet) return "";
|
|
1020
|
-
if (suppressBrandedHelp && !options?.force) return "";
|
|
1021
|
-
const lerp = (a, b, t) => Math.round(a + (b - a) * t);
|
|
1022
|
-
const gradientAt = (t) => {
|
|
1023
|
-
const c0 = { r: 5, g: 213, b: 255 };
|
|
1024
|
-
const c1 = { r: 54, g: 63, b: 249 };
|
|
1025
|
-
const c2 = { r: 85, g: 51, b: 255 };
|
|
1026
|
-
if (t <= 0.723958) {
|
|
1027
|
-
const p2 = t / 0.723958;
|
|
1028
|
-
return rgb(
|
|
1029
|
-
lerp(c0.r, c1.r, p2),
|
|
1030
|
-
lerp(c0.g, c1.g, p2),
|
|
1031
|
-
lerp(c0.b, c1.b, p2)
|
|
1032
|
-
);
|
|
1033
|
-
}
|
|
1034
|
-
const p = (t - 0.723958) / (1 - 0.723958);
|
|
1035
|
-
return rgb(
|
|
1036
|
-
lerp(c1.r, c2.r, p),
|
|
1037
|
-
lerp(c1.g, c2.g, p),
|
|
1038
|
-
lerp(c1.b, c2.b, p)
|
|
1039
|
-
);
|
|
1040
|
-
};
|
|
1041
|
-
const markLines = [
|
|
1042
|
-
" \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
1043
|
-
"\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D",
|
|
1044
|
-
"\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ",
|
|
1045
|
-
"\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ",
|
|
1046
|
-
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 ",
|
|
1047
|
-
"\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D "
|
|
1048
|
-
];
|
|
1049
|
-
const logo = markLines.map((line, i) => gradientAt(i / (markLines.length - 1))(line)).join("\n");
|
|
1050
|
-
return "\n" + logo + "\n";
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
// src/lib/interaction.ts
|
|
1054
|
-
import { stdin as stdin2, stdout as stdout2 } from "process";
|
|
1055
|
-
function isTruthy(value) {
|
|
1056
|
-
if (!value) return false;
|
|
1057
|
-
const normalized = value.trim().toLowerCase();
|
|
1058
|
-
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1059
|
-
}
|
|
1060
|
-
function isNonInteractiveEnv() {
|
|
1061
|
-
return isTruthy(process.env.ALCHEMY_NON_INTERACTIVE);
|
|
1062
|
-
}
|
|
1063
|
-
function isInteractiveAllowed(program) {
|
|
1064
|
-
if (!stdin2.isTTY || !stdout2.isTTY) return false;
|
|
1065
|
-
if (isJSONMode()) return false;
|
|
1066
|
-
if (isNonInteractiveEnv()) return false;
|
|
1067
|
-
if (program && program.opts().interactive === false) return false;
|
|
1068
|
-
return true;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// src/lib/update-check.ts
|
|
1072
|
-
import { execFileSync } from "child_process";
|
|
1073
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1074
|
-
import { dirname as dirname2 } from "path";
|
|
1075
|
-
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1076
|
-
var UPDATE_INSTALL_COMMAND = "npm i -g @alchemy/cli";
|
|
1077
|
-
function cachePath() {
|
|
1078
|
-
return configPath().replace(/config\.json$/, ".update-check");
|
|
1079
|
-
}
|
|
1080
|
-
function readCache() {
|
|
1081
|
-
try {
|
|
1082
|
-
return JSON.parse(readFileSync2(cachePath(), "utf-8"));
|
|
1083
|
-
} catch {
|
|
1084
|
-
return null;
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
function writeCache(cache) {
|
|
1088
|
-
try {
|
|
1089
|
-
const p = cachePath();
|
|
1090
|
-
mkdirSync2(dirname2(p), { recursive: true });
|
|
1091
|
-
writeFileSync2(p, JSON.stringify(cache), { mode: 384 });
|
|
1092
|
-
} catch {
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
function fetchLatestVersion() {
|
|
1096
|
-
try {
|
|
1097
|
-
const result = execFileSync("npm", ["view", "@alchemy/cli", "version"], {
|
|
1098
|
-
encoding: "utf-8",
|
|
1099
|
-
timeout: 5e3,
|
|
1100
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1101
|
-
});
|
|
1102
|
-
return result.trim() || null;
|
|
1103
|
-
} catch {
|
|
1104
|
-
return null;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
function semverLT(a, b) {
|
|
1108
|
-
const pa = a.split(".").map(Number);
|
|
1109
|
-
const pb = b.split(".").map(Number);
|
|
1110
|
-
for (let i = 0; i < 3; i++) {
|
|
1111
|
-
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return true;
|
|
1112
|
-
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return false;
|
|
1113
|
-
}
|
|
1114
|
-
return false;
|
|
1115
|
-
}
|
|
1116
|
-
function currentVersion() {
|
|
1117
|
-
return true ? "0.4.0" : "0.0.0";
|
|
1118
|
-
}
|
|
1119
|
-
function toUpdateStatus(latestVersion, checkedAt) {
|
|
1120
|
-
const current = currentVersion();
|
|
1121
|
-
return {
|
|
1122
|
-
currentVersion: current,
|
|
1123
|
-
latestVersion,
|
|
1124
|
-
updateAvailable: latestVersion ? semverLT(current, latestVersion) : false,
|
|
1125
|
-
installCommand: UPDATE_INSTALL_COMMAND,
|
|
1126
|
-
checkedAt
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
function getUpdateStatus() {
|
|
1130
|
-
const cache = readCache();
|
|
1131
|
-
if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {
|
|
1132
|
-
return toUpdateStatus(cache.latest, cache.checkedAt);
|
|
1133
|
-
}
|
|
1134
|
-
const latest = fetchLatestVersion();
|
|
1135
|
-
if (latest) {
|
|
1136
|
-
const checkedAt = Date.now();
|
|
1137
|
-
writeCache({ latest, checkedAt });
|
|
1138
|
-
return toUpdateStatus(latest, checkedAt);
|
|
1139
|
-
}
|
|
1140
|
-
if (cache) {
|
|
1141
|
-
return toUpdateStatus(cache.latest, cache.checkedAt);
|
|
1142
|
-
}
|
|
1143
|
-
return toUpdateStatus(null, null);
|
|
1144
|
-
}
|
|
1145
|
-
function getAvailableUpdate() {
|
|
1146
|
-
const current = currentVersion();
|
|
1147
|
-
const cache = readCache();
|
|
1148
|
-
if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {
|
|
1149
|
-
return semverLT(current, cache.latest) ? cache.latest : null;
|
|
1150
|
-
}
|
|
1151
|
-
const latest = fetchLatestVersion();
|
|
1152
|
-
if (latest) {
|
|
1153
|
-
writeCache({ latest, checkedAt: Date.now() });
|
|
1154
|
-
return semverLT(current, latest) ? latest : null;
|
|
1155
|
-
}
|
|
1156
|
-
return null;
|
|
1157
|
-
}
|
|
1158
|
-
function getUpdateNoticeLines(latest) {
|
|
1159
|
-
const yellow2 = esc("33");
|
|
1160
|
-
const bold2 = esc("1");
|
|
1161
|
-
const dim2 = esc("2");
|
|
1162
|
-
return [
|
|
1163
|
-
` ${yellow2("Update available")} ${dim2(currentVersion())} \u2192 ${bold2(latest)}`,
|
|
1164
|
-
` Run ${bold2(UPDATE_INSTALL_COMMAND)} to update`
|
|
1165
|
-
];
|
|
1166
|
-
}
|
|
1167
|
-
function printUpdateNotice(latest) {
|
|
1168
|
-
process.stderr.write(`
|
|
1169
|
-
${getUpdateNoticeLines(latest).join("\n")}
|
|
1170
|
-
|
|
1171
|
-
`);
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
export {
|
|
1175
|
-
noColor,
|
|
1176
|
-
setNoColor,
|
|
1177
|
-
identity,
|
|
1178
|
-
esc,
|
|
1179
|
-
rgb,
|
|
1180
|
-
bgRgb,
|
|
1181
|
-
redactSensitiveText,
|
|
1182
|
-
quiet,
|
|
1183
|
-
verbose,
|
|
1184
|
-
timeout,
|
|
1185
|
-
setFlags,
|
|
1186
|
-
isJSONMode,
|
|
1187
|
-
printJSON,
|
|
1188
|
-
printHuman,
|
|
1189
|
-
debug,
|
|
1190
|
-
formatCommanderError,
|
|
1191
|
-
ErrorCode,
|
|
1192
|
-
EXIT_CODES,
|
|
1193
|
-
CLIError,
|
|
1194
|
-
errAuthRequired,
|
|
1195
|
-
errAccessKeyRequired,
|
|
1196
|
-
errInvalidAPIKey,
|
|
1197
|
-
errNetworkNotEnabled,
|
|
1198
|
-
errNetwork,
|
|
1199
|
-
errRPC,
|
|
1200
|
-
errInvalidArgs,
|
|
1201
|
-
errNotFound,
|
|
1202
|
-
errRateLimited,
|
|
1203
|
-
errInvalidAccessKey,
|
|
1204
|
-
errAccessDenied,
|
|
1205
|
-
errAppRequired,
|
|
1206
|
-
errWalletKeyRequired,
|
|
1207
|
-
errAdminAPI,
|
|
1208
|
-
errSetupRequired,
|
|
1209
|
-
setReplMode,
|
|
1210
|
-
exitWithError,
|
|
1211
|
-
maskIf,
|
|
1212
|
-
KEY_MAP,
|
|
1213
|
-
configDir,
|
|
1214
|
-
load,
|
|
1215
|
-
save,
|
|
1216
|
-
get,
|
|
1217
|
-
toMap,
|
|
1218
|
-
promptText,
|
|
1219
|
-
promptConfirm,
|
|
1220
|
-
promptSelect,
|
|
1221
|
-
promptAutocomplete,
|
|
1222
|
-
promptMultiselect,
|
|
1223
|
-
green,
|
|
1224
|
-
red,
|
|
1225
|
-
dim,
|
|
1226
|
-
bold,
|
|
1227
|
-
yellow,
|
|
1228
|
-
brand,
|
|
1229
|
-
setBrandedHelpSuppressed,
|
|
1230
|
-
successBadge,
|
|
1231
|
-
failBadge,
|
|
1232
|
-
withSpinner,
|
|
1233
|
-
printKeyValueBox,
|
|
1234
|
-
emptyState,
|
|
1235
|
-
printSyntaxJSON,
|
|
1236
|
-
printTable,
|
|
1237
|
-
weiToEth,
|
|
1238
|
-
timeAgo,
|
|
1239
|
-
etherscanTxURL,
|
|
1240
|
-
brandedHelp,
|
|
1241
|
-
isInteractiveAllowed,
|
|
1242
|
-
getUpdateStatus,
|
|
1243
|
-
getAvailableUpdate,
|
|
1244
|
-
getUpdateNoticeLines,
|
|
1245
|
-
printUpdateNotice
|
|
1246
|
-
};
|