@bankr/cli 0.3.12 → 0.3.23
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 +28 -10
- package/dist/cli.js +31 -8
- package/dist/commands/balances.js +2 -1
- package/dist/commands/cancel.js +2 -1
- package/dist/commands/club.js +4 -3
- package/dist/commands/fees.js +83 -45
- package/dist/commands/files.js +14 -13
- package/dist/commands/launch.d.ts +5 -0
- package/dist/commands/launch.js +76 -7
- package/dist/commands/llm.d.ts +2 -0
- package/dist/commands/llm.js +264 -44
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.js +41 -30
- package/dist/commands/portfolio.js +3 -2
- package/dist/commands/profile.js +6 -5
- package/dist/commands/prompt.js +19 -6
- package/dist/commands/sign.js +2 -1
- package/dist/commands/sounds.js +4 -3
- package/dist/commands/status.js +3 -2
- package/dist/commands/submit.js +3 -2
- package/dist/commands/swap.js +9 -7
- package/dist/commands/tokens.js +3 -2
- package/dist/commands/transfer.js +8 -6
- package/dist/commands/update.js +2 -1
- package/dist/commands/webhooks.js +15 -10
- package/dist/commands/whoami.js +3 -2
- package/dist/commands/x402.d.ts +3 -0
- package/dist/commands/x402.js +75 -30
- package/dist/lib/api.d.ts +18 -1
- package/dist/lib/api.js +32 -41
- package/dist/lib/errors.d.ts +7 -0
- package/dist/lib/errors.js +9 -0
- package/dist/lib/explorer.d.ts +7 -0
- package/dist/lib/explorer.js +14 -0
- package/dist/lib/output.d.ts +1 -0
- package/dist/lib/output.js +6 -0
- package/dist/lib/passthrough.d.ts +21 -0
- package/dist/lib/passthrough.js +26 -0
- package/dist/lib/tokens.d.ts +0 -5
- package/dist/lib/tokens.js +0 -5
- package/package.json +1 -1
package/dist/commands/login.js
CHANGED
|
@@ -4,6 +4,7 @@ import open from "open";
|
|
|
4
4
|
import { isAddress } from "viem";
|
|
5
5
|
import { CLI_USER_AGENT, DEFAULT_API_URL, getApiUrl, getConfigPath, readConfig, writeConfig, } from "../lib/config.js";
|
|
6
6
|
import * as output from "../lib/output.js";
|
|
7
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
7
8
|
const DEFAULT_DASHBOARD_URL = "https://bankr.bot/api-keys";
|
|
8
9
|
const MAX_OTP_ATTEMPTS = 3;
|
|
9
10
|
const INVALID_CODE_STATUSES = [400, 401, 422];
|
|
@@ -45,6 +46,16 @@ async function sendPrivyOtp(privyConfig, email) {
|
|
|
45
46
|
throw new Error(`Failed to send verification code: ${body || res.status}`);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
/** The auth headers every authenticated CLI call sends — one place, so a new
|
|
50
|
+
* endpoint can't silently omit the access token and go unrevocable again. */
|
|
51
|
+
export function authHeaders(tokens) {
|
|
52
|
+
return {
|
|
53
|
+
"Content-Type": "application/json",
|
|
54
|
+
"User-Agent": CLI_USER_AGENT,
|
|
55
|
+
"privy-id-token": tokens.identityToken,
|
|
56
|
+
"x-access-token": tokens.accessToken,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
48
59
|
async function verifyPrivyOtp(privyConfig, email, code) {
|
|
49
60
|
const res = await fetch("https://auth.privy.io/api/v1/passwordless/authenticate", {
|
|
50
61
|
method: "POST",
|
|
@@ -66,14 +77,10 @@ async function verifyPrivyOtp(privyConfig, email, code) {
|
|
|
66
77
|
}
|
|
67
78
|
return (await res.json());
|
|
68
79
|
}
|
|
69
|
-
async function callGenerateWallet(apiUrl,
|
|
80
|
+
async function callGenerateWallet(apiUrl, tokens) {
|
|
70
81
|
const res = await fetch(`${apiUrl}/cli/generate-wallet`, {
|
|
71
82
|
method: "POST",
|
|
72
|
-
headers:
|
|
73
|
-
"Content-Type": "application/json",
|
|
74
|
-
"User-Agent": CLI_USER_AGENT,
|
|
75
|
-
"privy-id-token": identityToken,
|
|
76
|
-
},
|
|
83
|
+
headers: authHeaders(tokens),
|
|
77
84
|
});
|
|
78
85
|
const body = (await res.json());
|
|
79
86
|
if (!res.ok) {
|
|
@@ -81,28 +88,20 @@ async function callGenerateWallet(apiUrl, identityToken) {
|
|
|
81
88
|
}
|
|
82
89
|
return body;
|
|
83
90
|
}
|
|
84
|
-
async function callAcceptTerms(apiUrl,
|
|
91
|
+
async function callAcceptTerms(apiUrl, tokens) {
|
|
85
92
|
const res = await fetch(`${apiUrl}/user/accept-terms`, {
|
|
86
93
|
method: "POST",
|
|
87
|
-
headers:
|
|
88
|
-
"Content-Type": "application/json",
|
|
89
|
-
"User-Agent": CLI_USER_AGENT,
|
|
90
|
-
"privy-id-token": identityToken,
|
|
91
|
-
},
|
|
94
|
+
headers: authHeaders(tokens),
|
|
92
95
|
});
|
|
93
96
|
if (!res.ok) {
|
|
94
97
|
const body = (await res.json().catch(() => ({})));
|
|
95
98
|
throw new Error(body.message || body.error || `Accept terms failed (${res.status})`);
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
|
-
async function callGenerateApiKey(apiUrl,
|
|
101
|
+
async function callGenerateApiKey(apiUrl, tokens, opts) {
|
|
99
102
|
const res = await fetch(`${apiUrl}/api-keys`, {
|
|
100
103
|
method: "POST",
|
|
101
|
-
headers:
|
|
102
|
-
"Content-Type": "application/json",
|
|
103
|
-
"User-Agent": CLI_USER_AGENT,
|
|
104
|
-
"privy-id-token": identityToken,
|
|
105
|
-
},
|
|
104
|
+
headers: authHeaders(tokens),
|
|
106
105
|
body: JSON.stringify(opts),
|
|
107
106
|
});
|
|
108
107
|
const body = (await res.json());
|
|
@@ -127,7 +126,7 @@ async function sendOtpWithSpinner(privyConfig, email) {
|
|
|
127
126
|
}
|
|
128
127
|
catch (err) {
|
|
129
128
|
spin.fail("Failed to send verification code");
|
|
130
|
-
fatal(err
|
|
129
|
+
fatal(getErrorMessage(err));
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
async function verifyOtpWithSpinner(privyConfig, email, code) {
|
|
@@ -138,7 +137,7 @@ async function verifyOtpWithSpinner(privyConfig, email, code) {
|
|
|
138
137
|
return result;
|
|
139
138
|
}
|
|
140
139
|
catch (err) {
|
|
141
|
-
const errMsg = err
|
|
140
|
+
const errMsg = getErrorMessage(err);
|
|
142
141
|
spin.fail("Verification failed");
|
|
143
142
|
fatal(errMsg === "INVALID_CODE" ? "Invalid verification code." : errMsg);
|
|
144
143
|
}
|
|
@@ -162,7 +161,13 @@ async function authenticateWithEmail(apiUrl, providedEmail, providedCode) {
|
|
|
162
161
|
// Headless: code already provided, verify directly
|
|
163
162
|
if (providedCode) {
|
|
164
163
|
const result = await verifyOtpWithSpinner(privyConfig, email, providedCode.trim());
|
|
165
|
-
return {
|
|
164
|
+
return {
|
|
165
|
+
tokens: {
|
|
166
|
+
identityToken: result.identity_token,
|
|
167
|
+
accessToken: result.token,
|
|
168
|
+
},
|
|
169
|
+
email,
|
|
170
|
+
};
|
|
166
171
|
}
|
|
167
172
|
// Interactive: send OTP, then prompt for code with retries
|
|
168
173
|
await sendOtpWithSpinner(privyConfig, email);
|
|
@@ -176,10 +181,16 @@ async function authenticateWithEmail(apiUrl, providedEmail, providedCode) {
|
|
|
176
181
|
try {
|
|
177
182
|
const result = await verifyPrivyOtp(privyConfig, email, code.trim());
|
|
178
183
|
verifySpin.succeed("Email verified");
|
|
179
|
-
return {
|
|
184
|
+
return {
|
|
185
|
+
tokens: {
|
|
186
|
+
identityToken: result.identity_token,
|
|
187
|
+
accessToken: result.token,
|
|
188
|
+
},
|
|
189
|
+
email,
|
|
190
|
+
};
|
|
180
191
|
}
|
|
181
192
|
catch (err) {
|
|
182
|
-
const errMsg = err
|
|
193
|
+
const errMsg = getErrorMessage(err);
|
|
183
194
|
if (errMsg === "INVALID_CODE") {
|
|
184
195
|
if (attempt < MAX_OTP_ATTEMPTS - 1) {
|
|
185
196
|
verifySpin.fail("Invalid code, please try again");
|
|
@@ -197,17 +208,17 @@ async function authenticateWithEmail(apiUrl, providedEmail, providedCode) {
|
|
|
197
208
|
// ── Email login flow ────────────────────────────────────────────────
|
|
198
209
|
async function emailLoginFlow(apiUrl, opts) {
|
|
199
210
|
// Step 1: Authenticate via email OTP
|
|
200
|
-
const {
|
|
211
|
+
const { tokens } = await authenticateWithEmail(apiUrl, opts.email, opts.code);
|
|
201
212
|
// Step 2: Generate/resolve wallet
|
|
202
213
|
const walletSpin = output.spinner("Setting up wallet...");
|
|
203
214
|
let wallet;
|
|
204
215
|
try {
|
|
205
|
-
wallet = await callGenerateWallet(apiUrl,
|
|
216
|
+
wallet = await callGenerateWallet(apiUrl, tokens);
|
|
206
217
|
walletSpin.stop();
|
|
207
218
|
}
|
|
208
219
|
catch (err) {
|
|
209
220
|
walletSpin.fail("Wallet setup failed");
|
|
210
|
-
fatal(err
|
|
221
|
+
fatal(getErrorMessage(err));
|
|
211
222
|
}
|
|
212
223
|
// Show wallet info
|
|
213
224
|
output.blank();
|
|
@@ -241,12 +252,12 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
241
252
|
}
|
|
242
253
|
const termsSpin = output.spinner("Accepting terms...");
|
|
243
254
|
try {
|
|
244
|
-
await callAcceptTerms(apiUrl,
|
|
255
|
+
await callAcceptTerms(apiUrl, tokens);
|
|
245
256
|
termsSpin.succeed("Terms accepted");
|
|
246
257
|
}
|
|
247
258
|
catch (err) {
|
|
248
259
|
termsSpin.fail("Failed to accept terms");
|
|
249
|
-
fatal(err
|
|
260
|
+
fatal(getErrorMessage(err));
|
|
250
261
|
}
|
|
251
262
|
}
|
|
252
263
|
// Step 4: Generate API key
|
|
@@ -281,7 +292,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
281
292
|
const keySpin = output.spinner("Generating API key...");
|
|
282
293
|
let apiKeyResult;
|
|
283
294
|
try {
|
|
284
|
-
apiKeyResult = await callGenerateApiKey(apiUrl,
|
|
295
|
+
apiKeyResult = await callGenerateApiKey(apiUrl, tokens, {
|
|
285
296
|
name: keyName.trim(),
|
|
286
297
|
walletApiEnabled: enableWallet,
|
|
287
298
|
agentApiEnabled: enableAgent,
|
|
@@ -295,7 +306,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
295
306
|
}
|
|
296
307
|
catch (err) {
|
|
297
308
|
keySpin.fail("Failed to generate API key");
|
|
298
|
-
fatal(err
|
|
309
|
+
fatal(getErrorMessage(err));
|
|
299
310
|
}
|
|
300
311
|
// Show result
|
|
301
312
|
output.blank();
|
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { getPortfolio, } from "../lib/api.js";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
4
|
import { formatUsd, formatBalance } from "../lib/output.js";
|
|
5
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
5
6
|
import { CHAIN_LABELS, VALID_CHAINS } from "../lib/chains.js";
|
|
6
7
|
const BRAND = chalk.hex("#FF613D");
|
|
7
8
|
const DIM = chalk.dim;
|
|
@@ -78,7 +79,7 @@ export async function portfolioCommand(opts) {
|
|
|
78
79
|
spin.succeed("Portfolio loaded");
|
|
79
80
|
}
|
|
80
81
|
catch (err) {
|
|
81
|
-
spin.fail(`Failed to fetch portfolio: ${err
|
|
82
|
+
spin.fail(`Failed to fetch portfolio: ${getErrorMessage(err)}`);
|
|
82
83
|
process.exit(1);
|
|
83
84
|
}
|
|
84
85
|
// JSON output mode
|
|
@@ -109,7 +110,7 @@ export async function portfolioCommand(opts) {
|
|
|
109
110
|
printChainBalances(chain, chainData, !!includePnl);
|
|
110
111
|
}
|
|
111
112
|
// Print NFTs
|
|
112
|
-
if (includeNfts && data.nfts
|
|
113
|
+
if (includeNfts && data.nfts?.length) {
|
|
113
114
|
console.log();
|
|
114
115
|
console.log();
|
|
115
116
|
console.log(` ${BRAND.bold("NFTs")} ${DIM(`${data.nfts.length} item(s)`)}`);
|
package/dist/commands/profile.js
CHANGED
|
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
|
|
2
2
|
import { input, confirm, select } from "@inquirer/prompts";
|
|
3
3
|
import { getOwnProfiles, createProfile, updateProfile, deleteProfile, addProjectUpdate, } from "../lib/api.js";
|
|
4
4
|
import * as output from "../lib/output.js";
|
|
5
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
5
6
|
const BRAND = chalk.hex("#FF613D");
|
|
6
7
|
const DIM = chalk.dim;
|
|
7
8
|
function printProfile(profile, json) {
|
|
@@ -74,7 +75,7 @@ export async function profileViewCommand(opts) {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
catch (err) {
|
|
77
|
-
const msg = err
|
|
78
|
+
const msg = getErrorMessage(err);
|
|
78
79
|
if (msg.includes("404")) {
|
|
79
80
|
output.info("No profiles found. Create one with: bankr profile create");
|
|
80
81
|
}
|
|
@@ -132,7 +133,7 @@ export async function profileCreateCommand(opts) {
|
|
|
132
133
|
printProfile(profile, !!opts.json);
|
|
133
134
|
}
|
|
134
135
|
catch (err) {
|
|
135
|
-
output.error(err
|
|
136
|
+
output.error(getErrorMessage(err));
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
139
|
export async function profileUpdateCommand(opts) {
|
|
@@ -163,7 +164,7 @@ export async function profileUpdateCommand(opts) {
|
|
|
163
164
|
printProfile(profile, !!opts.json);
|
|
164
165
|
}
|
|
165
166
|
catch (err) {
|
|
166
|
-
output.error(err
|
|
167
|
+
output.error(getErrorMessage(err));
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
export async function profileDeleteCommand(opts) {
|
|
@@ -187,7 +188,7 @@ export async function profileDeleteCommand(opts) {
|
|
|
187
188
|
output.success("Profile deleted.");
|
|
188
189
|
}
|
|
189
190
|
catch (err) {
|
|
190
|
-
output.error(err
|
|
191
|
+
output.error(getErrorMessage(err));
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
export async function profileAddUpdateCommand(opts) {
|
|
@@ -221,7 +222,7 @@ export async function profileAddUpdateCommand(opts) {
|
|
|
221
222
|
}
|
|
222
223
|
}
|
|
223
224
|
catch (err) {
|
|
224
|
-
output.error(err
|
|
225
|
+
output.error(getErrorMessage(err));
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
//# sourceMappingURL=profile.js.map
|
package/dist/commands/prompt.js
CHANGED
|
@@ -2,11 +2,13 @@ import { ApiError, pollJob, submitPrompt } from "../lib/api.js";
|
|
|
2
2
|
import { emitCESP } from "../lib/cesp/engine.js";
|
|
3
3
|
import { getLastThreadId, requireApiKey, setLastThreadId, } from "../lib/config.js";
|
|
4
4
|
import * as output from "../lib/output.js";
|
|
5
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
5
6
|
/** Valid Max Mode model IDs — hardcoded because CLI is standalone (no monorepo imports).
|
|
6
7
|
* Must be manually kept in sync with models in the LLM gateway DB. */
|
|
7
8
|
const VALID_MAX_MODE_MODELS = new Set([
|
|
8
9
|
// Claude (Vertex AI)
|
|
9
10
|
"claude-fable-5",
|
|
11
|
+
"claude-opus-5",
|
|
10
12
|
"claude-opus-4.8",
|
|
11
13
|
"claude-opus-4.7",
|
|
12
14
|
"claude-opus-4.6",
|
|
@@ -15,28 +17,39 @@ const VALID_MAX_MODE_MODELS = new Set([
|
|
|
15
17
|
"claude-sonnet-4.6",
|
|
16
18
|
"claude-sonnet-4.5",
|
|
17
19
|
"claude-haiku-4.5",
|
|
18
|
-
// Gemini (Vertex AI)
|
|
20
|
+
// Gemini (Vertex AI) — gemini-3-pro deliberately absent: removed 2026-03-09,
|
|
21
|
+
// both provider slugs retired. Don't re-add on a sync pass.
|
|
22
|
+
"gemini-3.6-flash",
|
|
23
|
+
"gemini-3.5-flash-lite",
|
|
19
24
|
"gemini-3.1-pro",
|
|
20
|
-
"gemini-3-pro",
|
|
21
25
|
"gemini-2.5-pro",
|
|
22
26
|
// OpenAI (OpenRouter)
|
|
27
|
+
"gpt-5.6-sol",
|
|
28
|
+
"gpt-5.6-terra",
|
|
29
|
+
"gpt-5.6-luna",
|
|
30
|
+
"gpt-5.5",
|
|
23
31
|
"gpt-5.4",
|
|
24
32
|
"gpt-5.4-mini",
|
|
25
33
|
"gpt-5.2",
|
|
26
34
|
"gpt-5-mini",
|
|
27
35
|
// Grok (OpenRouter)
|
|
28
|
-
"grok-4.
|
|
36
|
+
"grok-4.6",
|
|
37
|
+
"grok-4.5",
|
|
38
|
+
"grok-4.3",
|
|
29
39
|
// DeepSeek (OpenRouter)
|
|
30
40
|
"deepseek-v3.2",
|
|
31
41
|
// Qwen (OpenRouter)
|
|
32
42
|
"qwen3-coder",
|
|
43
|
+
"qwen3.8-max",
|
|
33
44
|
"qwen3.7-max",
|
|
34
45
|
"qwen3.7-plus",
|
|
46
|
+
"qwen3.7-flash",
|
|
35
47
|
"qwen3.5-plus",
|
|
36
48
|
// MiniMax (direct)
|
|
37
49
|
"minimax-m2.5",
|
|
38
50
|
"minimax-m2.7",
|
|
39
51
|
// Other (OpenRouter)
|
|
52
|
+
"kimi-k3",
|
|
40
53
|
"kimi-k2.7-code",
|
|
41
54
|
"kimi-k2.6",
|
|
42
55
|
"kimi-k2.5",
|
|
@@ -95,7 +108,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
else {
|
|
98
|
-
output.error(err
|
|
111
|
+
output.error(getErrorMessage(err));
|
|
99
112
|
}
|
|
100
113
|
process.exit(1);
|
|
101
114
|
}
|
|
@@ -121,7 +134,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
121
134
|
if (result.response) {
|
|
122
135
|
console.log(result.response);
|
|
123
136
|
}
|
|
124
|
-
if (result.transactions
|
|
137
|
+
if (result.transactions?.length) {
|
|
125
138
|
console.log();
|
|
126
139
|
output.dim(`${result.transactions.length} transaction(s) returned. Use the web app to review and execute.`);
|
|
127
140
|
}
|
|
@@ -141,7 +154,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
141
154
|
catch (err) {
|
|
142
155
|
spin.fail("Error while polling");
|
|
143
156
|
emitCESP("resource.limit");
|
|
144
|
-
output.error(err
|
|
157
|
+
output.error(getErrorMessage(err));
|
|
145
158
|
process.exit(1);
|
|
146
159
|
}
|
|
147
160
|
}
|
package/dist/commands/sign.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sign } from "../lib/api.js";
|
|
2
2
|
import { emitCESP } from "../lib/cesp/engine.js";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
4
5
|
export async function signCommand(opts) {
|
|
5
6
|
const request = {
|
|
6
7
|
signatureType: opts.type,
|
|
@@ -63,7 +64,7 @@ export async function signCommand(opts) {
|
|
|
63
64
|
catch (err) {
|
|
64
65
|
spinner.stop();
|
|
65
66
|
emitCESP("task.error");
|
|
66
|
-
output.error(err
|
|
67
|
+
output.error(getErrorMessage(err));
|
|
67
68
|
process.exit(1);
|
|
68
69
|
}
|
|
69
70
|
}
|
package/dist/commands/sounds.js
CHANGED
|
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { readConfig, writeConfig } from "../lib/config.js";
|
|
7
7
|
import { DEFAULT_SOUND_CONFIG, emitCESP, getPacksDir, listInstalledPacks, } from "../lib/cesp/engine.js";
|
|
8
8
|
import * as output from "../lib/output.js";
|
|
9
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
9
10
|
const execFileAsync = promisify(execFile);
|
|
10
11
|
const REGISTRY_URL = "https://peonping.github.io/registry/index.json";
|
|
11
12
|
function getSoundConfig() {
|
|
@@ -164,7 +165,7 @@ export async function soundsInstallCommand(packName) {
|
|
|
164
165
|
}
|
|
165
166
|
catch (err) {
|
|
166
167
|
spin.fail("Failed to fetch registry");
|
|
167
|
-
output.error(err
|
|
168
|
+
output.error(getErrorMessage(err));
|
|
168
169
|
process.exit(1);
|
|
169
170
|
}
|
|
170
171
|
// Download and extract
|
|
@@ -218,7 +219,7 @@ export async function soundsInstallCommand(packName) {
|
|
|
218
219
|
}
|
|
219
220
|
catch (err) {
|
|
220
221
|
spin2.fail("Install failed");
|
|
221
|
-
output.error(err
|
|
222
|
+
output.error(getErrorMessage(err));
|
|
222
223
|
process.exit(1);
|
|
223
224
|
}
|
|
224
225
|
}
|
|
@@ -232,7 +233,7 @@ export async function soundsSearchCommand(query) {
|
|
|
232
233
|
}
|
|
233
234
|
catch (err) {
|
|
234
235
|
spin.fail("Failed to fetch registry");
|
|
235
|
-
output.error(err
|
|
236
|
+
output.error(getErrorMessage(err));
|
|
236
237
|
process.exit(1);
|
|
237
238
|
}
|
|
238
239
|
// Filter by query if provided
|
package/dist/commands/status.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getJobStatus } from "../lib/api.js";
|
|
2
2
|
import { requireApiKey } from "../lib/config.js";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
4
5
|
export async function statusCommand(jobId) {
|
|
5
6
|
requireApiKey();
|
|
6
7
|
const spin = output.spinner("Fetching job status...");
|
|
@@ -31,14 +32,14 @@ export async function statusCommand(jobId) {
|
|
|
31
32
|
console.log();
|
|
32
33
|
output.error(status.error);
|
|
33
34
|
}
|
|
34
|
-
if (status.transactions
|
|
35
|
+
if (status.transactions?.length) {
|
|
35
36
|
console.log();
|
|
36
37
|
output.dim(`${status.transactions.length} transaction(s) attached.`);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
catch (err) {
|
|
40
41
|
spin.fail("Failed to fetch job status");
|
|
41
|
-
output.error(err
|
|
42
|
+
output.error(getErrorMessage(err));
|
|
42
43
|
process.exit(1);
|
|
43
44
|
}
|
|
44
45
|
}
|
package/dist/commands/submit.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { submit } from "../lib/api.js";
|
|
2
2
|
import { emitCESP } from "../lib/cesp/engine.js";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
4
5
|
function displayResult(result) {
|
|
5
6
|
if (!result.success) {
|
|
6
7
|
emitCESP("task.error");
|
|
@@ -73,7 +74,7 @@ export async function submitCommand(opts) {
|
|
|
73
74
|
}
|
|
74
75
|
catch (err) {
|
|
75
76
|
spinner.stop();
|
|
76
|
-
output.error(err
|
|
77
|
+
output.error(getErrorMessage(err));
|
|
77
78
|
process.exit(1);
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -127,7 +128,7 @@ export async function submitJsonCommand(json, opts) {
|
|
|
127
128
|
}
|
|
128
129
|
catch (err) {
|
|
129
130
|
spinner.stop();
|
|
130
|
-
output.error(err
|
|
131
|
+
output.error(getErrorMessage(err));
|
|
131
132
|
process.exit(1);
|
|
132
133
|
}
|
|
133
134
|
}
|
package/dist/commands/swap.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { getSwapQuote, executeSwap } from "../lib/api.js";
|
|
2
2
|
import * as output from "../lib/output.js";
|
|
3
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
3
4
|
import { NATIVE_SYMBOLS, VALID_CHAINS } from "../lib/chains.js";
|
|
4
|
-
import {
|
|
5
|
+
import { zeroAddress } from "viem";
|
|
6
|
+
import { resolveTokenSymbol } from "../lib/tokens.js";
|
|
5
7
|
/**
|
|
6
8
|
* Resolve a token symbol or address to a contract address for swapping.
|
|
7
9
|
* - The chain's native ticker (ETH/POL/BNB) or the zero address → native, sent
|
|
@@ -12,10 +14,10 @@ async function resolveSwapToken(tokenInput, chain) {
|
|
|
12
14
|
const input = tokenInput.trim();
|
|
13
15
|
const nativeSymbol = NATIVE_SYMBOLS[chain] ?? "ETH";
|
|
14
16
|
const upper = input.toUpperCase();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
// viem's zeroAddress is already lowercase, so compare against the lowercased input.
|
|
18
|
+
const isNative = upper === nativeSymbol.toUpperCase() || input.toLowerCase() === zeroAddress;
|
|
17
19
|
if (isNative) {
|
|
18
|
-
return { address:
|
|
20
|
+
return { address: zeroAddress, symbol: nativeSymbol };
|
|
19
21
|
}
|
|
20
22
|
return resolveTokenSymbol(input, chain);
|
|
21
23
|
}
|
|
@@ -45,7 +47,7 @@ export async function swapCommand(opts) {
|
|
|
45
47
|
resolveSpin.stop();
|
|
46
48
|
}
|
|
47
49
|
catch (err) {
|
|
48
|
-
resolveSpin.fail(err
|
|
50
|
+
resolveSpin.fail(getErrorMessage(err));
|
|
49
51
|
process.exit(1);
|
|
50
52
|
}
|
|
51
53
|
// Quote
|
|
@@ -62,7 +64,7 @@ export async function swapCommand(opts) {
|
|
|
62
64
|
quoteSpin.stop();
|
|
63
65
|
}
|
|
64
66
|
catch (err) {
|
|
65
|
-
quoteSpin.fail(`Quote failed: ${err
|
|
67
|
+
quoteSpin.fail(`Quote failed: ${getErrorMessage(err)}`);
|
|
66
68
|
process.exit(1);
|
|
67
69
|
}
|
|
68
70
|
output.blank();
|
|
@@ -100,7 +102,7 @@ export async function swapCommand(opts) {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
catch (err) {
|
|
103
|
-
swapSpin.fail(`Swap failed: ${err
|
|
105
|
+
swapSpin.fail(`Swap failed: ${getErrorMessage(err)}`);
|
|
104
106
|
process.exit(1);
|
|
105
107
|
}
|
|
106
108
|
}
|
package/dist/commands/tokens.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { searchTokens } from "../lib/api.js";
|
|
2
2
|
import * as output from "../lib/output.js";
|
|
3
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
3
4
|
export async function tokensSearchCommand(query, opts) {
|
|
4
5
|
const spin = output.spinner(`Searching tokens for "${query}"...`);
|
|
5
6
|
try {
|
|
@@ -22,7 +23,7 @@ export async function tokensSearchCommand(query, opts) {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
catch (err) {
|
|
25
|
-
spin.fail(`Search failed: ${err
|
|
26
|
+
spin.fail(`Search failed: ${getErrorMessage(err)}`);
|
|
26
27
|
process.exit(1);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -53,7 +54,7 @@ export async function tokensInfoCommand(address, opts) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
catch (err) {
|
|
56
|
-
spin.fail(`Failed to fetch token info: ${err
|
|
57
|
+
spin.fail(`Failed to fetch token info: ${getErrorMessage(err)}`);
|
|
57
58
|
process.exit(1);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { transfer, resolveRecipient } from "../lib/api.js";
|
|
2
2
|
import * as output from "../lib/output.js";
|
|
3
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
3
4
|
import { NATIVE_SYMBOLS } from "../lib/chains.js";
|
|
4
|
-
import { isAddress } from "viem";
|
|
5
|
-
import {
|
|
5
|
+
import { isAddress, zeroAddress } from "viem";
|
|
6
|
+
import { resolveTokenSymbol } from "../lib/tokens.js";
|
|
6
7
|
function looksLikeEnsName(value) {
|
|
7
8
|
const v = value.trim().toLowerCase();
|
|
8
9
|
return v.endsWith(".eth") || v.endsWith(".cb.id");
|
|
@@ -30,7 +31,7 @@ async function resolveTransferRecipient(raw) {
|
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
catch (err) {
|
|
33
|
-
spin.fail(`ENS resolution failed for "${value}": ${err
|
|
34
|
+
spin.fail(`ENS resolution failed for "${value}": ${getErrorMessage(err)}`);
|
|
34
35
|
process.exit(1);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -47,7 +48,8 @@ export async function transferCommand(opts) {
|
|
|
47
48
|
let tokenAddress;
|
|
48
49
|
let tokenLabel;
|
|
49
50
|
if (isNative) {
|
|
50
|
-
|
|
51
|
+
// Zero address = native-token sentinel; the API detects + sanitizes it.
|
|
52
|
+
tokenAddress = zeroAddress;
|
|
51
53
|
tokenLabel = NATIVE_SYMBOLS[chain] ?? "ETH";
|
|
52
54
|
}
|
|
53
55
|
else {
|
|
@@ -64,7 +66,7 @@ export async function transferCommand(opts) {
|
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
catch (err) {
|
|
67
|
-
spin.fail(err
|
|
69
|
+
spin.fail(getErrorMessage(err));
|
|
68
70
|
process.exit(1);
|
|
69
71
|
}
|
|
70
72
|
}
|
|
@@ -86,7 +88,7 @@ export async function transferCommand(opts) {
|
|
|
86
88
|
output.label("Tx Hash", result.txHash ?? "unknown");
|
|
87
89
|
}
|
|
88
90
|
catch (err) {
|
|
89
|
-
spin.fail(`Transfer failed: ${err
|
|
91
|
+
spin.fail(`Transfer failed: ${getErrorMessage(err)}`);
|
|
90
92
|
process.exit(1);
|
|
91
93
|
}
|
|
92
94
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
|
+
import { getErrorMessage } from "../lib/errors.js";
|
|
4
5
|
const PACKAGE_NAME = "@bankr/cli";
|
|
5
6
|
/**
|
|
6
7
|
* Compare two semver version strings.
|
|
@@ -79,7 +80,7 @@ export async function updateCommand(opts) {
|
|
|
79
80
|
}
|
|
80
81
|
catch (err) {
|
|
81
82
|
spin.fail();
|
|
82
|
-
output.error(err
|
|
83
|
+
output.error(getErrorMessage(err));
|
|
83
84
|
process.exit(1);
|
|
84
85
|
}
|
|
85
86
|
const cmp = compareSemver(current, latest);
|