@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.
- package/README.md +34 -10
- package/dist/cli.js +34 -18
- package/dist/commands/balances.js +3 -3
- package/dist/commands/cancel.js +1 -3
- package/dist/commands/club.js +6 -16
- package/dist/commands/config.js +1 -2
- package/dist/commands/fees.js +79 -64
- package/dist/commands/files.js +17 -39
- package/dist/commands/launch.d.ts +4 -0
- package/dist/commands/launch.js +56 -18
- package/dist/commands/llm.d.ts +10 -0
- package/dist/commands/llm.js +510 -99
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.js +57 -57
- package/dist/commands/portfolio.js +4 -4
- package/dist/commands/profile.js +6 -5
- package/dist/commands/prompt.js +36 -26
- package/dist/commands/sign.js +9 -16
- package/dist/commands/sounds.js +6 -15
- package/dist/commands/status.js +2 -4
- package/dist/commands/submit.js +13 -24
- package/dist/commands/swap.js +11 -11
- package/dist/commands/tokens.js +4 -4
- package/dist/commands/transfer.js +10 -10
- package/dist/commands/update.js +2 -2
- package/dist/commands/webhooks.js +27 -67
- package/dist/commands/whoami.js +4 -4
- package/dist/commands/x402.d.ts +3 -0
- package/dist/commands/x402.js +95 -115
- package/dist/lib/api.d.ts +17 -3
- package/dist/lib/api.js +34 -43
- package/dist/lib/explorer.js +1 -0
- package/dist/lib/output.d.ts +5 -0
- package/dist/lib/output.js +18 -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/x402.js
CHANGED
|
@@ -19,14 +19,20 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import chalk from "chalk";
|
|
21
21
|
import { input, select, confirm } from "@inquirer/prompts";
|
|
22
|
+
import { authHeaders, handleResponse } from "../lib/api.js";
|
|
22
23
|
import * as output from "../lib/output.js";
|
|
23
|
-
import {
|
|
24
|
-
import { getApiUrl, requireApiKey, CLI_USER_AGENT } from "../lib/config.js";
|
|
24
|
+
import { getApiUrl } from "../lib/config.js";
|
|
25
25
|
// ── Config file helpers ─────────────────────────────────────────────────
|
|
26
26
|
const CONFIG_FILENAME = "bankr.x402.json";
|
|
27
27
|
function findProjectRoot() {
|
|
28
28
|
return process.cwd();
|
|
29
29
|
}
|
|
30
|
+
// Config values come from user-edited JSON cast without validation, so fields
|
|
31
|
+
// feeding select() defaults are plain strings; narrow them to the offered
|
|
32
|
+
// choices (select's default must match the literal union of choice values).
|
|
33
|
+
function pickDefault(value, allowed) {
|
|
34
|
+
return allowed.find((v) => v === value);
|
|
35
|
+
}
|
|
30
36
|
function loadConfigFile(projectRoot) {
|
|
31
37
|
const candidates = [
|
|
32
38
|
join(projectRoot, CONFIG_FILENAME),
|
|
@@ -38,8 +44,7 @@ function loadConfigFile(projectRoot) {
|
|
|
38
44
|
return JSON.parse(readFileSync(p, "utf-8"));
|
|
39
45
|
}
|
|
40
46
|
catch {
|
|
41
|
-
output.
|
|
42
|
-
process.exit(1);
|
|
47
|
+
output.fatal(`Failed to parse ${p}. Check that it is valid JSON.`);
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
}
|
|
@@ -49,24 +54,6 @@ function saveConfigFile(projectRoot, config) {
|
|
|
49
54
|
const configPath = join(projectRoot, CONFIG_FILENAME);
|
|
50
55
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
51
56
|
}
|
|
52
|
-
// ── API helpers ─────────────────────────────────────────────────────────
|
|
53
|
-
function authHeaders() {
|
|
54
|
-
return {
|
|
55
|
-
"X-API-Key": requireApiKey(),
|
|
56
|
-
"Content-Type": "application/json",
|
|
57
|
-
"User-Agent": CLI_USER_AGENT,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
async function handleResponse(res) {
|
|
61
|
-
if (!res.ok) {
|
|
62
|
-
const body = (await res
|
|
63
|
-
.json()
|
|
64
|
-
.catch(() => ({ message: res.statusText })));
|
|
65
|
-
const msg = body.message || body.error || res.statusText;
|
|
66
|
-
throw new Error(`API error (${res.status}): ${msg}`);
|
|
67
|
-
}
|
|
68
|
-
return res.json();
|
|
69
|
-
}
|
|
70
57
|
// ── Default handler template ────────────────────────────────────────────
|
|
71
58
|
const HANDLER_TEMPLATE = `/**
|
|
72
59
|
* x402 service handler.
|
|
@@ -138,19 +125,16 @@ function validateServiceName(name) {
|
|
|
138
125
|
export async function x402AddCommand(name) {
|
|
139
126
|
const nameError = validateServiceName(name);
|
|
140
127
|
if (nameError) {
|
|
141
|
-
output.
|
|
142
|
-
process.exit(1);
|
|
128
|
+
output.fatal(nameError);
|
|
143
129
|
}
|
|
144
130
|
const root = findProjectRoot();
|
|
145
131
|
const x402Dir = join(root, "x402");
|
|
146
132
|
if (!existsSync(x402Dir)) {
|
|
147
|
-
output.
|
|
148
|
-
process.exit(1);
|
|
133
|
+
output.fatal("No x402/ directory found. Run 'bankr x402 init' first.");
|
|
149
134
|
}
|
|
150
135
|
const serviceDir = join(x402Dir, name);
|
|
151
136
|
if (existsSync(serviceDir)) {
|
|
152
|
-
output.
|
|
153
|
-
process.exit(1);
|
|
137
|
+
output.fatal(`Service "${name}" already exists at x402/${name}/`);
|
|
154
138
|
}
|
|
155
139
|
// Ask for method
|
|
156
140
|
const method = await select({
|
|
@@ -238,9 +222,7 @@ export default async function handler(req: Request): Promise<Response> {
|
|
|
238
222
|
};
|
|
239
223
|
// Add to config
|
|
240
224
|
let config = loadConfigFile(root);
|
|
241
|
-
|
|
242
|
-
config = { services: {} };
|
|
243
|
-
}
|
|
225
|
+
config || (config = { services: {} });
|
|
244
226
|
config.services[name] = {
|
|
245
227
|
price: "0.001",
|
|
246
228
|
description: `${name} service`,
|
|
@@ -258,9 +240,7 @@ export default async function handler(req: Request): Promise<Response> {
|
|
|
258
240
|
export async function x402ConfigureCommand(name) {
|
|
259
241
|
const root = findProjectRoot();
|
|
260
242
|
let config = loadConfigFile(root);
|
|
261
|
-
|
|
262
|
-
config = { services: {} };
|
|
263
|
-
}
|
|
243
|
+
config || (config = { services: {} });
|
|
264
244
|
const existing = config.services[name] ?? { price: "0.001" };
|
|
265
245
|
const description = await input({
|
|
266
246
|
message: "Service description:",
|
|
@@ -273,12 +253,14 @@ export async function x402ConfigureCommand(name) {
|
|
|
273
253
|
theme: output.bankrTheme,
|
|
274
254
|
});
|
|
275
255
|
const currency = "USDC";
|
|
256
|
+
const networkDefault = pickDefault(existing.network, ["base"]) ?? "base";
|
|
276
257
|
const network = await select({
|
|
277
258
|
message: "Network:",
|
|
278
259
|
choices: [{ name: "Base", value: "base" }],
|
|
279
|
-
default:
|
|
260
|
+
default: networkDefault,
|
|
280
261
|
theme: output.bankrTheme,
|
|
281
262
|
});
|
|
263
|
+
const methodDefault = pickDefault(existing.methods?.[0], ["GET", "POST", "*"]) ?? "GET";
|
|
282
264
|
const method = await select({
|
|
283
265
|
message: "HTTP method:",
|
|
284
266
|
choices: [
|
|
@@ -286,7 +268,7 @@ export async function x402ConfigureCommand(name) {
|
|
|
286
268
|
{ name: "POST — JSON body", value: "POST" },
|
|
287
269
|
{ name: "Any — accept all methods", value: "*" },
|
|
288
270
|
],
|
|
289
|
-
default:
|
|
271
|
+
default: methodDefault,
|
|
290
272
|
theme: output.bankrTheme,
|
|
291
273
|
});
|
|
292
274
|
const paymentScheme = await select({
|
|
@@ -323,14 +305,11 @@ export async function x402DeployCommand(name) {
|
|
|
323
305
|
const root = findProjectRoot();
|
|
324
306
|
const x402Dir = join(root, "x402");
|
|
325
307
|
if (!existsSync(x402Dir)) {
|
|
326
|
-
output.
|
|
327
|
-
process.exit(1);
|
|
308
|
+
output.fatal("No x402/ directory found. Run 'bankr x402 init' first.");
|
|
328
309
|
}
|
|
329
310
|
// Load or bootstrap config
|
|
330
311
|
let config = loadConfigFile(root);
|
|
331
|
-
|
|
332
|
-
config = { services: {} };
|
|
333
|
-
}
|
|
312
|
+
config || (config = { services: {} });
|
|
334
313
|
// Discover services
|
|
335
314
|
const { readdirSync, statSync } = await import("node:fs");
|
|
336
315
|
const entries = readdirSync(x402Dir);
|
|
@@ -343,21 +322,18 @@ export async function x402DeployCommand(name) {
|
|
|
343
322
|
}
|
|
344
323
|
}
|
|
345
324
|
if (services.length === 0) {
|
|
346
|
-
output.
|
|
347
|
-
process.exit(1);
|
|
325
|
+
output.fatal("No services found. Run 'bankr x402 add <name>' first.");
|
|
348
326
|
}
|
|
349
327
|
// Filter to single service if name provided
|
|
350
328
|
const toDeploy = name ? services.filter((s) => s === name) : services;
|
|
351
329
|
if (name && toDeploy.length === 0) {
|
|
352
|
-
output.
|
|
353
|
-
process.exit(1);
|
|
330
|
+
output.fatal(`Service "${name}" not found in x402/`);
|
|
354
331
|
}
|
|
355
332
|
// Validate service names and ensure config entries
|
|
356
333
|
for (const svc of toDeploy) {
|
|
357
334
|
const nameError = validateServiceName(svc);
|
|
358
335
|
if (nameError) {
|
|
359
|
-
output.
|
|
360
|
-
process.exit(1);
|
|
336
|
+
output.fatal(nameError);
|
|
361
337
|
}
|
|
362
338
|
if (!config.services[svc]) {
|
|
363
339
|
config.services[svc] = {
|
|
@@ -422,9 +398,7 @@ export async function x402DeployCommand(name) {
|
|
|
422
398
|
}
|
|
423
399
|
}
|
|
424
400
|
catch (err) {
|
|
425
|
-
|
|
426
|
-
output.error(getErrorMessage(err));
|
|
427
|
-
process.exit(1);
|
|
401
|
+
output.failWith(spin, "Deploy failed", err);
|
|
428
402
|
}
|
|
429
403
|
}
|
|
430
404
|
/**
|
|
@@ -452,9 +426,7 @@ export async function x402ListCommand() {
|
|
|
452
426
|
}
|
|
453
427
|
}
|
|
454
428
|
catch (err) {
|
|
455
|
-
|
|
456
|
-
output.error(getErrorMessage(err));
|
|
457
|
-
process.exit(1);
|
|
429
|
+
output.failWith(spin, "Failed to list endpoints", err);
|
|
458
430
|
}
|
|
459
431
|
}
|
|
460
432
|
/**
|
|
@@ -473,9 +445,7 @@ export async function x402PauseResumeCommand(name, action) {
|
|
|
473
445
|
spin.succeed(`${name} ${action === "pause" ? "paused" : "resumed"}`);
|
|
474
446
|
}
|
|
475
447
|
catch (err) {
|
|
476
|
-
|
|
477
|
-
output.error(getErrorMessage(err));
|
|
478
|
-
process.exit(1);
|
|
448
|
+
output.failWith(spin, `Failed to ${action} ${name}`, err);
|
|
479
449
|
}
|
|
480
450
|
}
|
|
481
451
|
/**
|
|
@@ -499,9 +469,7 @@ export async function x402DeleteCommand(name) {
|
|
|
499
469
|
spin.succeed(`${name} deleted`);
|
|
500
470
|
}
|
|
501
471
|
catch (err) {
|
|
502
|
-
|
|
503
|
-
output.error(getErrorMessage(err));
|
|
504
|
-
process.exit(1);
|
|
472
|
+
output.failWith(spin, `Failed to delete ${name}`, err);
|
|
505
473
|
}
|
|
506
474
|
}
|
|
507
475
|
/**
|
|
@@ -533,9 +501,7 @@ export async function x402RevenueCommand(name) {
|
|
|
533
501
|
console.log();
|
|
534
502
|
}
|
|
535
503
|
catch (err) {
|
|
536
|
-
|
|
537
|
-
output.error(getErrorMessage(err));
|
|
538
|
-
process.exit(1);
|
|
504
|
+
output.failWith(spin, "Failed to fetch revenue", err);
|
|
539
505
|
}
|
|
540
506
|
}
|
|
541
507
|
/**
|
|
@@ -544,14 +510,12 @@ export async function x402RevenueCommand(name) {
|
|
|
544
510
|
export async function x402EnvSetCommand(keyValue) {
|
|
545
511
|
const eqIdx = keyValue.indexOf("=");
|
|
546
512
|
if (eqIdx === -1) {
|
|
547
|
-
output.
|
|
548
|
-
process.exit(1);
|
|
513
|
+
output.fatal("Usage: bankr x402 env set KEY=VALUE");
|
|
549
514
|
}
|
|
550
515
|
const key = keyValue.slice(0, eqIdx);
|
|
551
516
|
const value = keyValue.slice(eqIdx + 1);
|
|
552
517
|
if (!key) {
|
|
553
|
-
output.
|
|
554
|
-
process.exit(1);
|
|
518
|
+
output.fatal("Key cannot be empty");
|
|
555
519
|
}
|
|
556
520
|
const spin = output.spinner(`Setting ${key}...`);
|
|
557
521
|
try {
|
|
@@ -564,9 +528,7 @@ export async function x402EnvSetCommand(keyValue) {
|
|
|
564
528
|
spin.succeed(`Set ${key}`);
|
|
565
529
|
}
|
|
566
530
|
catch (err) {
|
|
567
|
-
|
|
568
|
-
output.error(getErrorMessage(err));
|
|
569
|
-
process.exit(1);
|
|
531
|
+
output.failWith(spin, `Failed to set ${key}`, err);
|
|
570
532
|
}
|
|
571
533
|
}
|
|
572
534
|
/**
|
|
@@ -589,9 +551,7 @@ export async function x402EnvListCommand() {
|
|
|
589
551
|
}
|
|
590
552
|
}
|
|
591
553
|
catch (err) {
|
|
592
|
-
|
|
593
|
-
output.error(getErrorMessage(err));
|
|
594
|
-
process.exit(1);
|
|
554
|
+
output.failWith(spin, "Failed to list env vars", err);
|
|
595
555
|
}
|
|
596
556
|
}
|
|
597
557
|
/**
|
|
@@ -608,9 +568,7 @@ export async function x402EnvUnsetCommand(key) {
|
|
|
608
568
|
spin.succeed(`Removed ${key}`);
|
|
609
569
|
}
|
|
610
570
|
catch (err) {
|
|
611
|
-
|
|
612
|
-
output.error(getErrorMessage(err));
|
|
613
|
-
process.exit(1);
|
|
571
|
+
output.failWith(spin, `Failed to remove ${key}`, err);
|
|
614
572
|
}
|
|
615
573
|
}
|
|
616
574
|
// ── Schema display helpers ──────────────────────────────────────────────
|
|
@@ -766,34 +724,28 @@ function printServiceFormatted(svc, rank, total) {
|
|
|
766
724
|
// ── Schema ────────────────────────────────────────────────────────────
|
|
767
725
|
export async function x402SchemaCommand(url, opts = {}) {
|
|
768
726
|
if (!url) {
|
|
769
|
-
output.
|
|
770
|
-
process.exit(1);
|
|
727
|
+
output.fatal("Usage: bankr x402 schema <url>\n Example: bankr x402 schema https://x402.bankr.bot/0xabc.../my-service");
|
|
771
728
|
}
|
|
772
729
|
let parsed;
|
|
773
730
|
try {
|
|
774
731
|
parsed = new URL(url);
|
|
775
732
|
}
|
|
776
733
|
catch {
|
|
777
|
-
output.
|
|
778
|
-
process.exit(1);
|
|
779
|
-
return; // unreachable but makes TS happy
|
|
734
|
+
output.fatal("Invalid URL");
|
|
780
735
|
}
|
|
781
736
|
if (!parsed.hostname.endsWith("x402.bankr.bot")) {
|
|
782
|
-
output.
|
|
783
|
-
process.exit(1);
|
|
737
|
+
output.fatal("Schema lookup is only available for Bankr-hosted endpoints (x402.bankr.bot).");
|
|
784
738
|
}
|
|
785
739
|
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
786
740
|
if (parts.length < 2) {
|
|
787
|
-
output.
|
|
788
|
-
process.exit(1);
|
|
741
|
+
output.fatal("Invalid Bankr x402 URL. Expected: https://x402.bankr.bot/<address>/<service>");
|
|
789
742
|
}
|
|
790
743
|
const spin = output.spinner("Fetching endpoint schema...");
|
|
791
744
|
try {
|
|
792
745
|
const res = await fetch(`${getApiUrl()}/x402/endpoints/schema/${parts[0]}/${parts[1]}`);
|
|
793
746
|
if (res.status === 404) {
|
|
794
747
|
spin.fail("Endpoint not found");
|
|
795
|
-
output.
|
|
796
|
-
process.exit(1);
|
|
748
|
+
output.fatal(`No active endpoint found for ${parts[0]}/${parts[1]}`);
|
|
797
749
|
}
|
|
798
750
|
const result = await handleResponse(res);
|
|
799
751
|
spin.stop();
|
|
@@ -875,9 +827,7 @@ export async function x402SchemaCommand(url, opts = {}) {
|
|
|
875
827
|
console.log();
|
|
876
828
|
}
|
|
877
829
|
catch (err) {
|
|
878
|
-
|
|
879
|
-
output.error(getErrorMessage(err));
|
|
880
|
-
process.exit(1);
|
|
830
|
+
output.failWith(spin, "Schema lookup failed", err);
|
|
881
831
|
}
|
|
882
832
|
}
|
|
883
833
|
async function fetchSchemaForInteractive(url) {
|
|
@@ -999,19 +949,44 @@ async function fetchSchemaForInteractive(url) {
|
|
|
999
949
|
return null;
|
|
1000
950
|
}
|
|
1001
951
|
// ── Call ──────────────────────────────────────────────────────────────
|
|
952
|
+
// The caller's --max-payment is the only value ever sent as the payment cap;
|
|
953
|
+
// an endpoint-advertised price may never raise it — fail closed instead.
|
|
954
|
+
// Exported for tests.
|
|
955
|
+
export function checkAdvertisedPrice(advertisedUsd, callerCapUsd) {
|
|
956
|
+
if (advertisedUsd !== null && advertisedUsd > callerCapUsd) {
|
|
957
|
+
return `Endpoint requires $${advertisedUsd} but --max-payment is $${callerCapUsd}. Re-run with a higher --max-payment (up to 10) to allow it.`;
|
|
958
|
+
}
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
// Advertised prices that are non-positive, unparseable, or token-denominated
|
|
962
|
+
// (non-USD currency) are treated as unknown: only a USD value can safely feed
|
|
963
|
+
// the USD cap clamp or the fail-closed comparison. Exported for tests.
|
|
964
|
+
export function parseAdvertisedPrice(price, currency) {
|
|
965
|
+
const upper = currency.toUpperCase();
|
|
966
|
+
if (upper !== "USDC" && upper !== "USD")
|
|
967
|
+
return null;
|
|
968
|
+
const parsed = parseFloat(price);
|
|
969
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
970
|
+
}
|
|
971
|
+
// The cap we send: never above the caller's --max-payment, and never above the
|
|
972
|
+
// advertised price the user was shown and confirmed. Exported for tests.
|
|
973
|
+
export function outboundMaxPayment(callerCapUsd, advertisedUsd) {
|
|
974
|
+
return advertisedUsd !== null
|
|
975
|
+
? Math.min(advertisedUsd, callerCapUsd)
|
|
976
|
+
: callerCapUsd;
|
|
977
|
+
}
|
|
1002
978
|
export async function x402CallCommand(url, opts = {}) {
|
|
1003
979
|
if (!url) {
|
|
1004
|
-
output.
|
|
1005
|
-
process.exit(1);
|
|
980
|
+
output.fatal("Usage: bankr x402 call <url> [--method POST] [--body '{}']");
|
|
1006
981
|
}
|
|
1007
982
|
let method = opts.method?.toUpperCase() ?? "GET";
|
|
1008
983
|
const maxPaymentUsd = opts.maxPayment ? parseFloat(opts.maxPayment) : 1;
|
|
1009
984
|
let requestBody = opts.body;
|
|
1010
985
|
if (isNaN(maxPaymentUsd) || maxPaymentUsd <= 0 || maxPaymentUsd > 10) {
|
|
1011
|
-
output.
|
|
1012
|
-
process.exit(1);
|
|
986
|
+
output.fatal("--max-payment must be between 0 and 10 (USD)");
|
|
1013
987
|
}
|
|
1014
|
-
//
|
|
988
|
+
// Endpoint-advertised price. Shown at confirm time; the outbound cap is
|
|
989
|
+
// clamped to min(advertised, caller's maxPaymentUsd) — see outboundMaxPayment.
|
|
1015
990
|
let resolvedPrice = null;
|
|
1016
991
|
if (opts.interactive) {
|
|
1017
992
|
const schema = await fetchSchemaForInteractive(url);
|
|
@@ -1025,7 +1000,11 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1025
1000
|
console.log(` ${chalk.dim("Price")} ${chalk.green(`$${schema.price} ${schema.currency}`)}`);
|
|
1026
1001
|
console.log();
|
|
1027
1002
|
// Use the endpoint's actual price and preferred method
|
|
1028
|
-
resolvedPrice =
|
|
1003
|
+
resolvedPrice = parseAdvertisedPrice(schema.price, schema.currency);
|
|
1004
|
+
const capError = checkAdvertisedPrice(resolvedPrice, maxPaymentUsd);
|
|
1005
|
+
if (capError) {
|
|
1006
|
+
output.fatal(capError);
|
|
1007
|
+
}
|
|
1029
1008
|
if (schema.methods.length > 0) {
|
|
1030
1009
|
method = schema.methods.includes("POST") ? "POST" : schema.methods[0];
|
|
1031
1010
|
}
|
|
@@ -1041,7 +1020,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1041
1020
|
: `${key} ${chalk.dim(`(${typedProp.type}, optional)`)}`;
|
|
1042
1021
|
const hint = typedProp.description ?? "";
|
|
1043
1022
|
// Enum fields → select prompt
|
|
1044
|
-
if (typedProp.enum
|
|
1023
|
+
if (typedProp.enum?.length) {
|
|
1045
1024
|
const selected = await select({
|
|
1046
1025
|
message: `${label}${hint ? ` — ${chalk.dim(hint)}` : ""}`,
|
|
1047
1026
|
choices: typedProp.enum.map((v) => ({
|
|
@@ -1066,8 +1045,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1066
1045
|
if (typedProp.type === "number" || typedProp.type === "integer") {
|
|
1067
1046
|
const num = Number(answer);
|
|
1068
1047
|
if (isNaN(num)) {
|
|
1069
|
-
output.
|
|
1070
|
-
process.exit(1);
|
|
1048
|
+
output.fatal(`Invalid number for ${key}: "${answer}"`);
|
|
1071
1049
|
}
|
|
1072
1050
|
values[key] = num;
|
|
1073
1051
|
}
|
|
@@ -1098,6 +1076,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1098
1076
|
// No schema available — fallback: prompt for method and body
|
|
1099
1077
|
output.warn("No schema found for this endpoint. Falling back to manual input.");
|
|
1100
1078
|
console.log();
|
|
1079
|
+
const manualMethodDefault = pickDefault(method, ["GET", "POST", "PUT", "DELETE"]) ?? "GET";
|
|
1101
1080
|
method = await select({
|
|
1102
1081
|
message: "HTTP method",
|
|
1103
1082
|
choices: [
|
|
@@ -1106,7 +1085,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1106
1085
|
{ name: "PUT", value: "PUT" },
|
|
1107
1086
|
{ name: "DELETE", value: "DELETE" },
|
|
1108
1087
|
],
|
|
1109
|
-
default:
|
|
1088
|
+
default: manualMethodDefault,
|
|
1110
1089
|
theme: output.bankrTheme,
|
|
1111
1090
|
});
|
|
1112
1091
|
if (method === "POST" || method === "PUT") {
|
|
@@ -1120,8 +1099,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1120
1099
|
requestBody = bodyInput;
|
|
1121
1100
|
}
|
|
1122
1101
|
catch {
|
|
1123
|
-
output.
|
|
1124
|
-
process.exit(1);
|
|
1102
|
+
output.fatal("Invalid JSON body");
|
|
1125
1103
|
}
|
|
1126
1104
|
}
|
|
1127
1105
|
}
|
|
@@ -1144,13 +1122,21 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1144
1122
|
}
|
|
1145
1123
|
console.log();
|
|
1146
1124
|
}
|
|
1147
|
-
//
|
|
1148
|
-
|
|
1125
|
+
// Probe the endpoint to show the actual price before confirming. Skipped in
|
|
1126
|
+
// non-interactive mode, where the confirm is suppressed — --ni matches --yes.
|
|
1127
|
+
if (!opts.interactive &&
|
|
1128
|
+
!opts.yes &&
|
|
1129
|
+
!output.isNonInteractive() &&
|
|
1130
|
+
resolvedPrice === null) {
|
|
1149
1131
|
const spin = output.spinner("Checking endpoint price...");
|
|
1150
1132
|
const schema = await fetchSchemaForInteractive(url);
|
|
1151
1133
|
spin.stop();
|
|
1152
1134
|
if (schema) {
|
|
1153
|
-
resolvedPrice =
|
|
1135
|
+
resolvedPrice = parseAdvertisedPrice(schema.price, schema.currency);
|
|
1136
|
+
const capError = checkAdvertisedPrice(resolvedPrice, maxPaymentUsd);
|
|
1137
|
+
if (capError) {
|
|
1138
|
+
output.fatal(capError);
|
|
1139
|
+
}
|
|
1154
1140
|
}
|
|
1155
1141
|
}
|
|
1156
1142
|
if (!opts.yes && !opts.interactive && !output.isNonInteractive()) {
|
|
@@ -1185,7 +1171,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1185
1171
|
url,
|
|
1186
1172
|
method,
|
|
1187
1173
|
body: requestBody,
|
|
1188
|
-
maxPaymentUsd:
|
|
1174
|
+
maxPaymentUsd: outboundMaxPayment(maxPaymentUsd, resolvedPrice),
|
|
1189
1175
|
}),
|
|
1190
1176
|
});
|
|
1191
1177
|
const result = await handleResponse(res);
|
|
@@ -1195,8 +1181,7 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1195
1181
|
return;
|
|
1196
1182
|
}
|
|
1197
1183
|
if (!result.success) {
|
|
1198
|
-
output.
|
|
1199
|
-
process.exit(1);
|
|
1184
|
+
output.fatal(result.error ?? "Call failed");
|
|
1200
1185
|
}
|
|
1201
1186
|
// Show endpoint schema info (Bankr-hosted endpoints only)
|
|
1202
1187
|
if (result.endpointSchema) {
|
|
@@ -1229,17 +1214,14 @@ export async function x402CallCommand(url, opts = {}) {
|
|
|
1229
1214
|
console.log();
|
|
1230
1215
|
}
|
|
1231
1216
|
catch (err) {
|
|
1232
|
-
|
|
1233
|
-
output.error(getErrorMessage(err));
|
|
1234
|
-
process.exit(1);
|
|
1217
|
+
output.failWith(spin, "Call failed", err);
|
|
1235
1218
|
}
|
|
1236
1219
|
}
|
|
1237
1220
|
// ── Search ────────────────────────────────────────────────────────────
|
|
1238
1221
|
export async function x402SearchCommand(queryParts, opts = {}) {
|
|
1239
1222
|
const query = queryParts.join(" ").trim();
|
|
1240
1223
|
if (!query) {
|
|
1241
|
-
output.
|
|
1242
|
-
process.exit(1);
|
|
1224
|
+
output.fatal("Usage: bankr x402 search <query>");
|
|
1243
1225
|
}
|
|
1244
1226
|
const spin = output.spinner("Searching services...");
|
|
1245
1227
|
try {
|
|
@@ -1276,9 +1258,7 @@ export async function x402SearchCommand(queryParts, opts = {}) {
|
|
|
1276
1258
|
}
|
|
1277
1259
|
}
|
|
1278
1260
|
catch (err) {
|
|
1279
|
-
|
|
1280
|
-
output.error(getErrorMessage(err));
|
|
1281
|
-
process.exit(1);
|
|
1261
|
+
output.failWith(spin, "Search failed", err);
|
|
1282
1262
|
}
|
|
1283
1263
|
}
|
|
1284
1264
|
//# sourceMappingURL=x402.js.map
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export interface JobStatusResponse {
|
|
|
43
43
|
richData?: unknown[];
|
|
44
44
|
cancellable?: boolean;
|
|
45
45
|
}
|
|
46
|
+
export declare function authHeaders(): Record<string, string>;
|
|
47
|
+
export declare function handleResponse<T>(res: Response): Promise<T>;
|
|
46
48
|
export interface ApiErrorBody {
|
|
47
49
|
error: string;
|
|
48
50
|
message: string;
|
|
@@ -69,7 +71,11 @@ export declare function getUserInfo(): Promise<UserInfoResponse>;
|
|
|
69
71
|
export interface TokenBalanceInfo {
|
|
70
72
|
network: string;
|
|
71
73
|
token: {
|
|
72
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Wire shape of `GET /wallet/portfolio`: an exact decimal string.
|
|
76
|
+
* Coerce with `Number(...)` before arithmetic or comparison.
|
|
77
|
+
*/
|
|
78
|
+
balance: string;
|
|
73
79
|
balanceUSD: number;
|
|
74
80
|
baseToken: {
|
|
75
81
|
name: string;
|
|
@@ -192,7 +198,7 @@ export interface SubmitResponse {
|
|
|
192
198
|
export declare function submit(request: SubmitRequest): Promise<SubmitResponse>;
|
|
193
199
|
export type FeeRecipientType = "wallet" | "x" | "farcaster" | "ens";
|
|
194
200
|
/** Chains the deploy endpoint accepts (mirrors the API's zod enum). */
|
|
195
|
-
export type LaunchChain = "base" | "robinhood";
|
|
201
|
+
export type LaunchChain = "base" | "robinhood" | "arbitrum";
|
|
196
202
|
export interface DeployTokenRequest {
|
|
197
203
|
tokenName: string;
|
|
198
204
|
tokenSymbol?: string;
|
|
@@ -206,6 +212,11 @@ export interface DeployTokenRequest {
|
|
|
206
212
|
value: string;
|
|
207
213
|
};
|
|
208
214
|
simulateOnly?: boolean;
|
|
215
|
+
/** Turn off the default 15% creator vesting (100% of supply sold into the pool). */
|
|
216
|
+
disableVesting?: boolean;
|
|
217
|
+
/** Collect all creator fees in the pool's quote token (e.g. WETH) instead of
|
|
218
|
+
* a mix of the launched token and the quote token. */
|
|
219
|
+
quoteOnlyFees?: boolean;
|
|
209
220
|
}
|
|
210
221
|
export interface DeployTokenResponse {
|
|
211
222
|
success: boolean;
|
|
@@ -225,7 +236,7 @@ export interface CreatorFeesTokenResult {
|
|
|
225
236
|
tokenAddress: string;
|
|
226
237
|
name: string;
|
|
227
238
|
symbol: string;
|
|
228
|
-
/** Launch chain ("base" | "robinhood"); absent on older API versions → base. */
|
|
239
|
+
/** Launch chain ("base" | "robinhood" | "arbitrum"); absent on older API versions → base. */
|
|
229
240
|
chain?: string;
|
|
230
241
|
poolId: string;
|
|
231
242
|
initializer?: string;
|
|
@@ -264,6 +275,9 @@ export interface BeneficiaryFeesResponse {
|
|
|
264
275
|
totalLaunches: number;
|
|
265
276
|
poolsWithShares: number;
|
|
266
277
|
tokens: CreatorFeesTokenResult[];
|
|
278
|
+
/** Server stopped the scan early — more claimable fees may exist. */
|
|
279
|
+
truncated?: boolean;
|
|
280
|
+
scanned?: number;
|
|
267
281
|
}
|
|
268
282
|
export interface DopplerClaimTxResponse {
|
|
269
283
|
to: string;
|