@bankr/cli 0.3.13 → 0.3.32

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.
@@ -31,15 +31,13 @@ export async function statusCommand(jobId) {
31
31
  console.log();
32
32
  output.error(status.error);
33
33
  }
34
- if (status.transactions && status.transactions.length > 0) {
34
+ if (status.transactions?.length) {
35
35
  console.log();
36
36
  output.dim(`${status.transactions.length} transaction(s) attached.`);
37
37
  }
38
38
  }
39
39
  catch (err) {
40
- spin.fail("Failed to fetch job status");
41
- output.error(err.message);
42
- process.exit(1);
40
+ output.failWith(spin, "Failed to fetch job status", err);
43
41
  }
44
42
  }
45
43
  //# sourceMappingURL=status.js.map
@@ -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");
@@ -27,24 +28,20 @@ function displayResult(result) {
27
28
  export async function submitCommand(opts) {
28
29
  // Validate required fields
29
30
  if (!opts.to) {
30
- output.error("--to is required");
31
- process.exit(1);
31
+ output.fatal("--to is required");
32
32
  }
33
33
  if (!opts.chainId) {
34
- output.error("--chain-id is required");
35
- process.exit(1);
34
+ output.fatal("--chain-id is required");
36
35
  }
37
36
  const chainId = parseInt(opts.chainId, 10);
38
37
  if (isNaN(chainId)) {
39
- output.error("--chain-id must be a number");
40
- process.exit(1);
38
+ output.fatal("--chain-id must be a number");
41
39
  }
42
40
  let nonce;
43
41
  if (opts.nonce) {
44
42
  nonce = parseInt(opts.nonce, 10);
45
43
  if (isNaN(nonce)) {
46
- output.error("--nonce must be a number");
47
- process.exit(1);
44
+ output.fatal("--nonce must be a number");
48
45
  }
49
46
  }
50
47
  const request = {
@@ -73,8 +70,7 @@ export async function submitCommand(opts) {
73
70
  }
74
71
  catch (err) {
75
72
  spinner.stop();
76
- output.error(err.message);
77
- process.exit(1);
73
+ output.fatal(getErrorMessage(err));
78
74
  }
79
75
  }
80
76
  // Alternative: submit from JSON
@@ -84,32 +80,26 @@ export async function submitJsonCommand(json, opts) {
84
80
  transaction = JSON.parse(json);
85
81
  }
86
82
  catch {
87
- output.error("Invalid JSON. Expected: {to, chainId, value?, data?}");
88
- process.exit(1);
83
+ output.fatal("Invalid JSON. Expected: {to, chainId, value?, data?}");
89
84
  }
90
85
  if (!transaction ||
91
86
  typeof transaction !== "object" ||
92
87
  Array.isArray(transaction)) {
93
- output.error("Invalid JSON. Expected object: {to, chainId, value?, data?}");
94
- process.exit(1);
88
+ output.fatal("Invalid JSON. Expected object: {to, chainId, value?, data?}");
95
89
  }
96
90
  // Validate required fields
97
91
  if (!transaction.to) {
98
- output.error("Transaction must have 'to' field");
99
- process.exit(1);
92
+ output.fatal("Transaction must have 'to' field");
100
93
  }
101
94
  if (transaction.chainId === undefined) {
102
- output.error("Transaction must have 'chainId' field");
103
- process.exit(1);
95
+ output.fatal("Transaction must have 'chainId' field");
104
96
  }
105
97
  if (typeof transaction.chainId !== "number" || isNaN(transaction.chainId)) {
106
- output.error("Transaction 'chainId' must be a number");
107
- process.exit(1);
98
+ output.fatal("Transaction 'chainId' must be a number");
108
99
  }
109
100
  if (transaction.nonce !== undefined &&
110
101
  (typeof transaction.nonce !== "number" || isNaN(transaction.nonce))) {
111
- output.error("Transaction 'nonce' must be a number");
112
- process.exit(1);
102
+ output.fatal("Transaction 'nonce' must be a number");
113
103
  }
114
104
  const request = {
115
105
  transaction,
@@ -127,8 +117,7 @@ export async function submitJsonCommand(json, opts) {
127
117
  }
128
118
  catch (err) {
129
119
  spinner.stop();
130
- output.error(err.message);
131
- process.exit(1);
120
+ output.fatal(getErrorMessage(err));
132
121
  }
133
122
  }
134
123
  //# sourceMappingURL=submit.js.map
@@ -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 { ZERO_ADDRESS, resolveTokenSymbol } from "../lib/tokens.js";
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,26 +14,24 @@ 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
- const isNative = upper === nativeSymbol.toUpperCase() ||
16
- input.toLowerCase() === ZERO_ADDRESS;
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: ZERO_ADDRESS, symbol: nativeSymbol };
20
+ return { address: zeroAddress, symbol: nativeSymbol };
19
21
  }
20
22
  return resolveTokenSymbol(input, chain);
21
23
  }
22
24
  export async function swapCommand(opts) {
23
25
  const chain = opts.chain ?? "base";
24
26
  if (!VALID_CHAINS.has(chain) || chain === "solana") {
25
- output.error(`Unsupported chain "${chain}". Swaps support EVM chains: base, polygon, mainnet, unichain, worldchain, arbitrum, bnb.`);
26
- process.exit(1);
27
+ output.fatal(`Unsupported chain "${chain}". Swaps support EVM chains: base, polygon, mainnet, unichain, worldchain, arbitrum, bnb.`);
27
28
  }
28
29
  // Validate amount client-side so a bad value gives a clear error instead of a
29
30
  // generic 500 from the API's parseUnits(amount, decimals). Number() alone
30
31
  // accepts "1e-3" / "0x10" / "Infinity" that parseUnits rejects, so require a
31
32
  // plain decimal string.
32
33
  if (!/^\d*\.?\d+$/.test(opts.amount) || Number(opts.amount) <= 0) {
33
- output.error(`Invalid amount "${opts.amount}". Provide a positive decimal number, e.g. --amount 0.5.`);
34
- process.exit(1);
34
+ output.fatal(`Invalid amount "${opts.amount}". Provide a positive decimal number, e.g. --amount 0.5.`);
35
35
  }
36
36
  // Resolve from/to tokens (symbol → address, native → zero address)
37
37
  let fromToken;
@@ -45,7 +45,7 @@ export async function swapCommand(opts) {
45
45
  resolveSpin.stop();
46
46
  }
47
47
  catch (err) {
48
- resolveSpin.fail(err.message);
48
+ resolveSpin.fail(getErrorMessage(err));
49
49
  process.exit(1);
50
50
  }
51
51
  // Quote
@@ -62,7 +62,7 @@ export async function swapCommand(opts) {
62
62
  quoteSpin.stop();
63
63
  }
64
64
  catch (err) {
65
- quoteSpin.fail(`Quote failed: ${err.message}`);
65
+ quoteSpin.fail(`Quote failed: ${getErrorMessage(err)}`);
66
66
  process.exit(1);
67
67
  }
68
68
  output.blank();
@@ -100,7 +100,7 @@ export async function swapCommand(opts) {
100
100
  }
101
101
  }
102
102
  catch (err) {
103
- swapSpin.fail(`Swap failed: ${err.message}`);
103
+ swapSpin.fail(`Swap failed: ${getErrorMessage(err)}`);
104
104
  process.exit(1);
105
105
  }
106
106
  }
@@ -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.message}`);
26
+ spin.fail(`Search failed: ${getErrorMessage(err)}`);
26
27
  process.exit(1);
27
28
  }
28
29
  }
@@ -37,8 +38,7 @@ export async function tokensInfoCommand(address, opts) {
37
38
  const token = res.tokens.find((t) => t.address.toLowerCase() === addressLower) ??
38
39
  res.tokens[0];
39
40
  if (!token) {
40
- output.error("Token not found. Check the address and try again.");
41
- process.exit(1);
41
+ output.fatal("Token not found. Check the address and try again.");
42
42
  }
43
43
  console.log();
44
44
  output.label("Name", token.name);
@@ -53,7 +53,7 @@ export async function tokensInfoCommand(address, opts) {
53
53
  }
54
54
  }
55
55
  catch (err) {
56
- spin.fail(`Failed to fetch token info: ${err.message}`);
56
+ spin.fail(`Failed to fetch token info: ${getErrorMessage(err)}`);
57
57
  process.exit(1);
58
58
  }
59
59
  }
@@ -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 { ZERO_ADDRESS, resolveTokenSymbol } from "../lib/tokens.js";
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");
@@ -13,8 +14,7 @@ async function resolveTransferRecipient(raw) {
13
14
  return { address: value, label: value };
14
15
  }
15
16
  if (!looksLikeEnsName(value)) {
16
- output.error(`Invalid recipient "${value}". Expected a 0x address or an ENS name (e.g. vitalik.eth, name.base.eth, name.cb.id).`);
17
- process.exit(1);
17
+ output.fatal(`Invalid recipient "${value}". Expected a 0x address or an ENS name (e.g. vitalik.eth, name.base.eth, name.cb.id).`);
18
18
  }
19
19
  const spin = output.spinner(`Resolving ENS name "${value}"...`);
20
20
  try {
@@ -30,7 +30,7 @@ async function resolveTransferRecipient(raw) {
30
30
  };
31
31
  }
32
32
  catch (err) {
33
- spin.fail(`ENS resolution failed for "${value}": ${err.message}`);
33
+ spin.fail(`ENS resolution failed for "${value}": ${getErrorMessage(err)}`);
34
34
  process.exit(1);
35
35
  }
36
36
  }
@@ -38,8 +38,7 @@ export async function transferCommand(opts) {
38
38
  const isNative = opts.native ?? false;
39
39
  const chain = opts.chain ?? "base";
40
40
  if (!isNative && !opts.token) {
41
- output.error("Token required for ERC20 transfers. Use --token <symbol or address> or --native.");
42
- process.exit(1);
41
+ output.fatal("Token required for ERC20 transfers. Use --token <symbol or address> or --native.");
43
42
  }
44
43
  const recipient = await resolveTransferRecipient(opts.to);
45
44
  const recipientAddress = recipient.address;
@@ -47,7 +46,8 @@ export async function transferCommand(opts) {
47
46
  let tokenAddress;
48
47
  let tokenLabel;
49
48
  if (isNative) {
50
- tokenAddress = ZERO_ADDRESS;
49
+ // Zero address = native-token sentinel; the API detects + sanitizes it.
50
+ tokenAddress = zeroAddress;
51
51
  tokenLabel = NATIVE_SYMBOLS[chain] ?? "ETH";
52
52
  }
53
53
  else {
@@ -64,7 +64,7 @@ export async function transferCommand(opts) {
64
64
  }
65
65
  }
66
66
  catch (err) {
67
- spin.fail(err.message);
67
+ spin.fail(getErrorMessage(err));
68
68
  process.exit(1);
69
69
  }
70
70
  }
@@ -86,7 +86,7 @@ export async function transferCommand(opts) {
86
86
  output.label("Tx Hash", result.txHash ?? "unknown");
87
87
  }
88
88
  catch (err) {
89
- spin.fail(`Transfer failed: ${err.message}`);
89
+ spin.fail(`Transfer failed: ${getErrorMessage(err)}`);
90
90
  process.exit(1);
91
91
  }
92
92
  }
@@ -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,8 +80,7 @@ export async function updateCommand(opts) {
79
80
  }
80
81
  catch (err) {
81
82
  spin.fail();
82
- output.error(err.message);
83
- process.exit(1);
83
+ output.fatal(getErrorMessage(err));
84
84
  }
85
85
  const cmp = compareSemver(current, latest);
86
86
  if (cmp === 0) {
@@ -16,9 +16,9 @@
16
16
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
17
  import { join } from "node:path";
18
18
  import { confirm } from "@inquirer/prompts";
19
+ import { authHeaders, handleResponse } from "../lib/api.js";
19
20
  import * as output from "../lib/output.js";
20
- import { getErrorMessage } from "../lib/errors.js";
21
- import { getApiUrl, requireApiKey, CLI_USER_AGENT } from "../lib/config.js";
21
+ import { getApiUrl } from "../lib/config.js";
22
22
  // ── Config file ─────────────────────────────────────────────────────────
23
23
  const CONFIG_FILENAME = "bankr.webhooks.json";
24
24
  const WEBHOOKS_DIR = "webhooks";
@@ -36,8 +36,7 @@ function loadConfigFile(projectRoot) {
36
36
  return JSON.parse(readFileSync(p, "utf-8"));
37
37
  }
38
38
  catch {
39
- output.error(`Failed to parse ${p}. Check that it is valid JSON.`);
40
- process.exit(1);
39
+ output.fatal(`Failed to parse ${p}. Check that it is valid JSON.`);
41
40
  }
42
41
  }
43
42
  }
@@ -46,23 +45,6 @@ function loadConfigFile(projectRoot) {
46
45
  function saveConfigFile(projectRoot, config) {
47
46
  writeFileSync(join(projectRoot, CONFIG_FILENAME), JSON.stringify(config, null, 2) + "\n");
48
47
  }
49
- function authHeaders() {
50
- return {
51
- "X-API-Key": requireApiKey(),
52
- "Content-Type": "application/json",
53
- "User-Agent": CLI_USER_AGENT,
54
- };
55
- }
56
- async function handleResponse(res) {
57
- if (!res.ok) {
58
- const body = (await res
59
- .json()
60
- .catch(() => ({ message: res.statusText })));
61
- const msg = body.message || body.error || res.statusText;
62
- throw new Error(`API error (${res.status}): ${msg}`);
63
- }
64
- return res.json();
65
- }
66
48
  const MAX_WEBHOOK_NAME_LENGTH = 47;
67
49
  const WEBHOOK_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
68
50
  function validateWebhookName(name) {
@@ -326,8 +308,7 @@ export default async function handler(req: Request): Promise<Response> {
326
308
  export async function webhooksAddCommand(name, options = {}) {
327
309
  const err = validateWebhookName(name);
328
310
  if (err) {
329
- output.error(err);
330
- process.exit(1);
311
+ output.fatal(err);
331
312
  }
332
313
  const providerInput = (options.provider ?? "generic").toLowerCase();
333
314
  const validProviders = [
@@ -337,20 +318,17 @@ export async function webhooksAddCommand(name, options = {}) {
337
318
  "generic",
338
319
  ];
339
320
  if (!validProviders.includes(providerInput)) {
340
- output.error(`Invalid provider "${providerInput}". Valid: ${validProviders.join(", ")}.`);
341
- process.exit(1);
321
+ output.fatal(`Invalid provider "${providerInput}". Valid: ${validProviders.join(", ")}.`);
342
322
  }
343
323
  const provider = providerInput;
344
324
  const root = findProjectRoot();
345
325
  const dir = join(root, WEBHOOKS_DIR);
346
326
  if (!existsSync(dir)) {
347
- output.error(`No ${WEBHOOKS_DIR}/ directory found. Run 'bankr webhooks init' first.`);
348
- process.exit(1);
327
+ output.fatal(`No ${WEBHOOKS_DIR}/ directory found. Run 'bankr webhooks init' first.`);
349
328
  }
350
329
  const serviceDir = join(dir, name);
351
330
  if (existsSync(serviceDir)) {
352
- output.error(`Webhook "${name}" already exists at ${WEBHOOKS_DIR}/${name}/`);
353
- process.exit(1);
331
+ output.fatal(`Webhook "${name}" already exists at ${WEBHOOKS_DIR}/${name}/`);
354
332
  }
355
333
  mkdirSync(serviceDir, { recursive: true });
356
334
  const { source, envHint } = handlerTemplate(name, provider);
@@ -397,8 +375,7 @@ export async function webhooksDeployCommand(name) {
397
375
  const root = findProjectRoot();
398
376
  const dir = join(root, WEBHOOKS_DIR);
399
377
  if (!existsSync(dir)) {
400
- output.error(`No ${WEBHOOKS_DIR}/ directory found. Run 'bankr webhooks init' first.`);
401
- process.exit(1);
378
+ output.fatal(`No ${WEBHOOKS_DIR}/ directory found. Run 'bankr webhooks init' first.`);
402
379
  }
403
380
  let config = loadConfigFile(root);
404
381
  if (!config)
@@ -413,19 +390,16 @@ export async function webhooksDeployCommand(name) {
413
390
  }
414
391
  }
415
392
  if (discovered.length === 0) {
416
- output.error("No webhooks found. Run 'bankr webhooks add <name>' first.");
417
- process.exit(1);
393
+ output.fatal("No webhooks found. Run 'bankr webhooks add <name>' first.");
418
394
  }
419
395
  const toDeploy = name ? discovered.filter((s) => s === name) : discovered;
420
396
  if (name && toDeploy.length === 0) {
421
- output.error(`Webhook "${name}" not found in ${WEBHOOKS_DIR}/`);
422
- process.exit(1);
397
+ output.fatal(`Webhook "${name}" not found in ${WEBHOOKS_DIR}/`);
423
398
  }
424
399
  for (const svc of toDeploy) {
425
400
  const nameError = validateWebhookName(svc);
426
401
  if (nameError) {
427
- output.error(nameError);
428
- process.exit(1);
402
+ output.fatal(nameError);
429
403
  }
430
404
  if (!config.webhooks[svc]) {
431
405
  config.webhooks[svc] = {
@@ -487,9 +461,7 @@ export async function webhooksDeployCommand(name) {
487
461
  output.info("Your handler code is responsible for verifying incoming signatures (Slack, GitHub, etc.). Provider-specific scaffolds include the verifier inline — `bankr webhooks add <name> --provider slack|github|stripe` to scaffold one.");
488
462
  }
489
463
  catch (err) {
490
- spin.fail("Deploy failed");
491
- output.error(getErrorMessage(err));
492
- process.exit(1);
464
+ output.failWith(spin, "Deploy failed", err);
493
465
  }
494
466
  }
495
467
  export async function webhooksListCommand() {
@@ -508,16 +480,16 @@ export async function webhooksListCommand() {
508
480
  const status = w.status === "active"
509
481
  ? output.fmt.success("active")
510
482
  : output.fmt.warn(w.status);
511
- const mode = w.readOnly ? output.fmt.dim("read-only") : output.fmt.warn("writes");
483
+ const mode = w.readOnly
484
+ ? output.fmt.dim("read-only")
485
+ : output.fmt.warn("writes");
512
486
  console.log(` ${output.fmt.brand(w.name)} ${status} v${w.version} ${mode} ${w.totalInvocations} invocations`);
513
487
  if (w.description)
514
488
  output.dim(` ${w.description}`);
515
489
  }
516
490
  }
517
491
  catch (err) {
518
- spin.fail("Failed to list webhooks");
519
- output.error(getErrorMessage(err));
520
- process.exit(1);
492
+ output.failWith(spin, "Failed to list webhooks", err);
521
493
  }
522
494
  }
523
495
  export async function webhooksPauseResumeCommand(name, action) {
@@ -533,9 +505,7 @@ export async function webhooksPauseResumeCommand(name, action) {
533
505
  spin.succeed(`${name} ${action === "pause" ? "paused" : "resumed"}`);
534
506
  }
535
507
  catch (err) {
536
- spin.fail(`Failed to ${action} ${name}`);
537
- output.error(getErrorMessage(err));
538
- process.exit(1);
508
+ output.failWith(spin, `Failed to ${action} ${name}`, err);
539
509
  }
540
510
  }
541
511
  export async function webhooksDeleteCommand(name) {
@@ -556,15 +526,15 @@ export async function webhooksDeleteCommand(name) {
556
526
  spin.succeed(`${name} deleted`);
557
527
  }
558
528
  catch (err) {
559
- spin.fail(`Failed to delete ${name}`);
560
- output.error(getErrorMessage(err));
561
- process.exit(1);
529
+ output.failWith(spin, `Failed to delete ${name}`, err);
562
530
  }
563
531
  }
564
532
  export async function webhooksLogsCommand(name) {
565
533
  const spin = output.spinner(`Fetching invocations for ${name}...`);
566
534
  try {
567
- const res = await fetch(`${getApiUrl()}/webhooks/${name}/logs?limit=25`, { headers: authHeaders() });
535
+ const res = await fetch(`${getApiUrl()}/webhooks/${name}/logs?limit=25`, {
536
+ headers: authHeaders(),
537
+ });
568
538
  const result = await handleResponse(res);
569
539
  spin.stop();
570
540
  if (result.logs.length === 0) {
@@ -582,23 +552,19 @@ export async function webhooksLogsCommand(name) {
582
552
  }
583
553
  }
584
554
  catch (err) {
585
- spin.fail("Failed to fetch logs");
586
- output.error(getErrorMessage(err));
587
- process.exit(1);
555
+ output.failWith(spin, "Failed to fetch logs", err);
588
556
  }
589
557
  }
590
558
  // ── Env vars ────────────────────────────────────────────────────────────
591
559
  export async function webhooksEnvSetCommand(keyValue) {
592
560
  const eqIdx = keyValue.indexOf("=");
593
561
  if (eqIdx === -1) {
594
- output.error("Usage: bankr webhooks env set KEY=VALUE");
595
- process.exit(1);
562
+ output.fatal("Usage: bankr webhooks env set KEY=VALUE");
596
563
  }
597
564
  const key = keyValue.slice(0, eqIdx);
598
565
  const value = keyValue.slice(eqIdx + 1);
599
566
  if (!key) {
600
- output.error("Key cannot be empty");
601
- process.exit(1);
567
+ output.fatal("Key cannot be empty");
602
568
  }
603
569
  const spin = output.spinner(`Setting ${key}...`);
604
570
  try {
@@ -611,9 +577,7 @@ export async function webhooksEnvSetCommand(keyValue) {
611
577
  spin.succeed(`Set ${key}`);
612
578
  }
613
579
  catch (err) {
614
- spin.fail(`Failed to set ${key}`);
615
- output.error(getErrorMessage(err));
616
- process.exit(1);
580
+ output.failWith(spin, `Failed to set ${key}`, err);
617
581
  }
618
582
  }
619
583
  export async function webhooksEnvListCommand() {
@@ -632,9 +596,7 @@ export async function webhooksEnvListCommand() {
632
596
  console.log(` ${n}`);
633
597
  }
634
598
  catch (err) {
635
- spin.fail("Failed to list env vars");
636
- output.error(getErrorMessage(err));
637
- process.exit(1);
599
+ output.failWith(spin, "Failed to list env vars", err);
638
600
  }
639
601
  }
640
602
  export async function webhooksEnvUnsetCommand(key) {
@@ -645,9 +607,7 @@ export async function webhooksEnvUnsetCommand(key) {
645
607
  spin.succeed(`Removed ${key}`);
646
608
  }
647
609
  catch (err) {
648
- spin.fail(`Failed to remove ${key}`);
649
- output.error(getErrorMessage(err));
650
- process.exit(1);
610
+ output.failWith(spin, `Failed to remove ${key}`, err);
651
611
  }
652
612
  }
653
613
  //# sourceMappingURL=webhooks.js.map
@@ -2,13 +2,13 @@ import { existsSync } from "fs";
2
2
  import { getApiKey, getApiUrl, getConfigPath, isCustomApiUrl, } from "../lib/config.js";
3
3
  import { getUserInfo } from "../lib/api.js";
4
4
  import * as output from "../lib/output.js";
5
+ import { getErrorMessage } from "../lib/errors.js";
5
6
  export async function whoamiCommand() {
6
7
  const apiKey = getApiKey();
7
8
  const apiUrl = getApiUrl();
8
9
  const configPath = getConfigPath();
9
10
  if (!apiKey) {
10
- output.error("Not authenticated. Run `bankr login` to set up your Bankr API key.");
11
- process.exit(1);
11
+ output.fatal("Not authenticated. Run `bankr login` to set up your Bankr API key.");
12
12
  }
13
13
  const source = process.env.BANKR_API_KEY ? "env (BANKR_API_KEY)" : configPath;
14
14
  output.label("Bankr API Key", output.maskApiKey(apiKey));
@@ -35,7 +35,7 @@ export async function whoamiCommand() {
35
35
  }
36
36
  }
37
37
  catch (err) {
38
- spin.fail(`Could not reach Bankr API: ${err.message}`);
38
+ spin.fail(`Could not reach Bankr API: ${getErrorMessage(err)}`);
39
39
  return;
40
40
  }
41
41
  // Fetch user profile info
@@ -69,7 +69,7 @@ export async function whoamiCommand() {
69
69
  output.label("Score", `${score}${rankStr}`);
70
70
  }
71
71
  catch (err) {
72
- profileSpin.fail(`Could not fetch account info: ${err.message}`);
72
+ profileSpin.fail(`Could not fetch account info: ${getErrorMessage(err)}`);
73
73
  }
74
74
  }
75
75
  //# sourceMappingURL=whoami.js.map
@@ -62,6 +62,9 @@ export declare function x402EnvUnsetCommand(key: string): Promise<void>;
62
62
  export declare function x402SchemaCommand(url: string, opts?: {
63
63
  raw?: boolean;
64
64
  }): Promise<void>;
65
+ export declare function checkAdvertisedPrice(advertisedUsd: number | null, callerCapUsd: number): string | null;
66
+ export declare function parseAdvertisedPrice(price: string, currency: string): number | null;
67
+ export declare function outboundMaxPayment(callerCapUsd: number, advertisedUsd: number | null): number;
65
68
  export declare function x402CallCommand(url: string, opts?: {
66
69
  method?: string;
67
70
  body?: string;