@bankr/cli 0.2.6 → 0.2.8

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/cli.js CHANGED
@@ -22,7 +22,7 @@ import { submitCommand, submitJsonCommand } from "./commands/submit.js";
22
22
  import { updateCommand } from "./commands/update.js";
23
23
  import { whoamiCommand } from "./commands/whoami.js";
24
24
  import { tokensSearchCommand, tokensInfoCommand } from "./commands/tokens.js";
25
- import { x402InitCommand, x402AddCommand, x402ConfigureCommand, x402DeployCommand, x402ListCommand, x402PauseResumeCommand, x402DeleteCommand, x402RevenueCommand, x402EnvSetCommand, x402EnvListCommand, x402EnvUnsetCommand, x402SearchCommand, } from "./commands/x402.js";
25
+ import { x402InitCommand, x402AddCommand, x402ConfigureCommand, x402DeployCommand, x402ListCommand, x402PauseResumeCommand, x402DeleteCommand, x402RevenueCommand, x402EnvSetCommand, x402EnvListCommand, x402EnvUnsetCommand, x402SearchCommand, x402SchemaCommand, x402CallCommand, } from "./commands/x402.js";
26
26
  import { profileViewCommand, profileCreateCommand, profileUpdateCommand, profileDeleteCommand, profileAddUpdateCommand, } from "./commands/profile.js";
27
27
  import * as output from "./lib/output.js";
28
28
  import { checkForUpdate } from "./lib/updateCheck.js";
@@ -774,6 +774,21 @@ x402Cmd
774
774
  .description("Search the x402 service marketplace (no auth required)")
775
775
  .option("--raw", "Output raw JSON (unformatted)")
776
776
  .action(async (query, opts) => x402SearchCommand(query, { raw: opts.raw }));
777
+ x402Cmd
778
+ .command("schema <url>")
779
+ .description("View input/output schema for a Bankr x402 endpoint (no auth required)")
780
+ .option("--raw", "Output raw JSON (unformatted)")
781
+ .action(async (url, opts) => x402SchemaCommand(url, opts));
782
+ x402Cmd
783
+ .command("call <url>")
784
+ .description("Call an x402-protected endpoint with automatic USDC payment")
785
+ .option("-X, --method <method>", "HTTP method (GET, POST, PUT, DELETE)", "GET")
786
+ .option("-d, --body <json>", "JSON request body")
787
+ .option("--max-payment <usd>", "Maximum payment in USD (default: 1, max: 10)", "1")
788
+ .option("-i, --interactive", "Fetch endpoint schema and prompt for input values")
789
+ .option("-y, --yes", "Skip payment confirmation")
790
+ .option("--raw", "Output raw JSON (unformatted)")
791
+ .action(async (url, opts) => x402CallCommand(url, opts));
777
792
  // Default: treat unrecognized arguments as a prompt
778
793
  program
779
794
  .arguments("[text...]")
@@ -59,6 +59,17 @@ export declare function x402EnvListCommand(): Promise<void>;
59
59
  * bankr x402 env unset KEY
60
60
  */
61
61
  export declare function x402EnvUnsetCommand(key: string): Promise<void>;
62
+ export declare function x402SchemaCommand(url: string, opts?: {
63
+ raw?: boolean;
64
+ }): Promise<void>;
65
+ export declare function x402CallCommand(url: string, opts?: {
66
+ method?: string;
67
+ body?: string;
68
+ maxPayment?: string;
69
+ yes?: boolean;
70
+ raw?: boolean;
71
+ interactive?: boolean;
72
+ }): Promise<void>;
62
73
  export declare function x402SearchCommand(queryParts: string[], opts?: {
63
74
  raw?: boolean;
64
75
  }): Promise<void>;
@@ -15,7 +15,7 @@
15
15
  * bankr x402 env list — List env var names
16
16
  * bankr x402 env unset KEY — Remove env var
17
17
  */
18
- import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
18
+ 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";
@@ -203,6 +203,22 @@ export default async function handler(req: Request): Promise<Response> {
203
203
  }
204
204
  `;
205
205
  writeFileSync(join(serviceDir, "index.ts"), handlerContent);
206
+ // Ask about npm dependencies
207
+ const useDeps = await confirm({
208
+ message: "Will this service use npm packages?",
209
+ default: false,
210
+ theme: output.bankrTheme,
211
+ });
212
+ if (useDeps) {
213
+ const pkg = {
214
+ name: `x402-${name}`,
215
+ private: true,
216
+ dependencies: {},
217
+ };
218
+ writeFileSync(join(serviceDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
219
+ output.success(`Created x402/${name}/package.json`);
220
+ output.info(`Add packages with: cd x402/${name} && bun add <package>`);
221
+ }
206
222
  // Build JSON Schema scaffold
207
223
  const schema = {
208
224
  input: {
@@ -356,7 +372,22 @@ export async function x402DeployCommand(name) {
356
372
  process.exit(1);
357
373
  }
358
374
  const source = readFileSync(entrypoint, "utf-8");
359
- bundles.push({ name: svc, source });
375
+ // Read package.json dependencies if present
376
+ let dependencies;
377
+ const pkgPath = join(x402Dir, svc, "package.json");
378
+ if (existsSync(pkgPath)) {
379
+ try {
380
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
381
+ if (pkg.dependencies && Object.keys(pkg.dependencies).length > 0) {
382
+ dependencies = pkg.dependencies;
383
+ }
384
+ }
385
+ catch {
386
+ spin.fail(`Invalid package.json in x402/${svc}/`);
387
+ process.exit(1);
388
+ }
389
+ }
390
+ bundles.push({ name: svc, source, dependencies });
360
391
  }
361
392
  // Deploy via API (server-side build + deploy)
362
393
  const res = await fetch(`${getApiUrl()}/x402/endpoints/deploy`, {
@@ -367,6 +398,7 @@ export async function x402DeployCommand(name) {
367
398
  bundles: bundles.map((b) => ({
368
399
  name: b.name,
369
400
  source: b.source,
401
+ ...(b.dependencies && { dependencies: b.dependencies }),
370
402
  })),
371
403
  }),
372
404
  });
@@ -709,6 +741,446 @@ function printServiceFormatted(svc) {
709
741
  console.log(` ${chalk.dim("─".repeat(60))}`);
710
742
  console.log("");
711
743
  }
744
+ // ── Schema ────────────────────────────────────────────────────────────
745
+ export async function x402SchemaCommand(url, opts = {}) {
746
+ if (!url) {
747
+ output.error("Usage: bankr x402 schema <url>\n Example: bankr x402 schema https://x402.bankr.bot/0xabc.../my-service");
748
+ process.exit(1);
749
+ }
750
+ let parsed;
751
+ try {
752
+ parsed = new URL(url);
753
+ }
754
+ catch {
755
+ output.error("Invalid URL");
756
+ process.exit(1);
757
+ return; // unreachable but makes TS happy
758
+ }
759
+ if (!parsed.hostname.endsWith("x402.bankr.bot")) {
760
+ output.error("Schema lookup is only available for Bankr-hosted endpoints (x402.bankr.bot).");
761
+ process.exit(1);
762
+ }
763
+ const parts = parsed.pathname.split("/").filter(Boolean);
764
+ if (parts.length < 2) {
765
+ output.error("Invalid Bankr x402 URL. Expected: https://x402.bankr.bot/<address>/<service>");
766
+ process.exit(1);
767
+ }
768
+ const spin = output.spinner("Fetching endpoint schema...");
769
+ try {
770
+ const res = await fetch(`${getApiUrl()}/x402/endpoints/schema/${parts[0]}/${parts[1]}`);
771
+ if (res.status === 404) {
772
+ spin.fail("Endpoint not found");
773
+ output.error(`No active endpoint found for ${parts[0]}/${parts[1]}`);
774
+ process.exit(1);
775
+ }
776
+ const result = await handleResponse(res);
777
+ spin.stop();
778
+ if (opts.raw) {
779
+ console.log(JSON.stringify(result, null, 2));
780
+ return;
781
+ }
782
+ // Header
783
+ console.log();
784
+ console.log(` ${chalk.bold(result.name)}`);
785
+ if (result.description) {
786
+ console.log(` ${chalk.dim(result.description)}`);
787
+ }
788
+ console.log();
789
+ // Metadata
790
+ console.log(` ${chalk.dim("URL")} ${url}`);
791
+ console.log(` ${chalk.dim("Method")} ${chalk.bold(result.methods.join(", ") || "GET")}`);
792
+ console.log(` ${chalk.dim("Price")} ${chalk.green(`$${result.price} ${result.currency}`)}`);
793
+ console.log(` ${chalk.dim("Network")} ${result.network}`);
794
+ // Input schema
795
+ if (result.schema?.input) {
796
+ console.log();
797
+ const isGet = result.methods.includes("GET") && !result.methods.includes("POST");
798
+ const label = isGet ? "Input (query params)" : "Input (JSON body)";
799
+ console.log(` ${chalk.bold(label)}`);
800
+ if (isJsonSchema(result.schema.input)) {
801
+ for (const line of renderJsonSchemaProps(result.schema.input)) {
802
+ console.log(line);
803
+ }
804
+ }
805
+ else {
806
+ for (const line of renderLegacySchema(result.schema.input)) {
807
+ console.log(line);
808
+ }
809
+ }
810
+ // Example
811
+ if (isJsonSchema(result.schema.input) &&
812
+ result.schema.input.properties) {
813
+ const props = Object.entries(result.schema.input.properties);
814
+ console.log();
815
+ if (isGet) {
816
+ const qs = props.map(([k, p]) => `${k}=<${p.type}>`).join("&");
817
+ console.log(` ${chalk.dim("Example")} ${chalk.dim("GET")} ${url}?${qs}`);
818
+ }
819
+ else {
820
+ const bodyObj = {};
821
+ for (const [k, p] of props)
822
+ bodyObj[k] = `<${p.type}>`;
823
+ console.log(` ${chalk.dim("Example")} ${chalk.dim(result.methods[0] || "POST")} ${url}`);
824
+ console.log(` ${chalk.dim(JSON.stringify(bodyObj))}`);
825
+ }
826
+ }
827
+ }
828
+ // Output schema
829
+ if (result.schema?.output) {
830
+ console.log();
831
+ console.log(` ${chalk.bold("Output")}`);
832
+ if (isJsonSchema(result.schema.output)) {
833
+ for (const line of renderJsonSchemaProps(result.schema.output)) {
834
+ console.log(line);
835
+ }
836
+ }
837
+ else {
838
+ for (const line of renderLegacySchema(result.schema.output)) {
839
+ console.log(line);
840
+ }
841
+ }
842
+ }
843
+ if (!result.schema?.input && !result.schema?.output) {
844
+ console.log();
845
+ console.log(` ${chalk.dim("No input/output schema defined for this endpoint.")}`);
846
+ }
847
+ // Tags
848
+ if (result.tags?.length) {
849
+ console.log();
850
+ console.log(` ${result.tags.map((t) => chalk.dim(`#${t}`)).join(" ")}`);
851
+ }
852
+ console.log(` ${chalk.dim("─".repeat(60))}`);
853
+ console.log();
854
+ }
855
+ catch (err) {
856
+ spin.fail("Schema lookup failed");
857
+ output.error(err instanceof Error ? err.message : String(err));
858
+ process.exit(1);
859
+ }
860
+ }
861
+ async function fetchSchemaForInteractive(url) {
862
+ let parsed;
863
+ try {
864
+ parsed = new URL(url);
865
+ }
866
+ catch {
867
+ return null;
868
+ }
869
+ const isBankr = parsed.hostname.endsWith("x402.bankr.bot");
870
+ const parts = parsed.pathname.split("/").filter(Boolean);
871
+ // Strategy 1: Direct schema API (works once deployed)
872
+ if (isBankr && parts.length >= 2) {
873
+ try {
874
+ const res = await fetch(`${getApiUrl()}/x402/endpoints/schema/${parts[0]}/${parts[1]}`);
875
+ if (res.ok) {
876
+ const data = (await res.json());
877
+ if (data.success) {
878
+ const rawInput = data.schema?.input;
879
+ const inputSchema = rawInput && isJsonSchema(rawInput)
880
+ ? rawInput
881
+ : null;
882
+ return {
883
+ name: data.name,
884
+ description: data.description,
885
+ methods: data.methods,
886
+ price: data.price,
887
+ currency: data.currency,
888
+ inputSchema,
889
+ };
890
+ }
891
+ }
892
+ }
893
+ catch {
894
+ // Fall through to next strategy
895
+ }
896
+ }
897
+ // Strategy 2: Discover API (already deployed, searches by service name)
898
+ if (isBankr && parts.length >= 2) {
899
+ try {
900
+ const serviceName = parts[parts.length - 1];
901
+ const discoverRes = await fetch(`${getApiUrl()}/x402/endpoints/discover?${new URLSearchParams({ q: serviceName, limit: "5" })}`);
902
+ if (discoverRes.ok) {
903
+ const discoverData = (await discoverRes.json());
904
+ // Match by slug or URL path
905
+ const slug = `${parts[0]}/${parts[1]}`;
906
+ const match = discoverData.services?.find((s) => s.slug === slug || s.slug.endsWith(`/${serviceName}`));
907
+ if (match) {
908
+ const route = match.routes?.[0];
909
+ const { input: rawInput } = resolveSchemas(route?.schema);
910
+ const inputSchema = rawInput && isJsonSchema(rawInput)
911
+ ? rawInput
912
+ : null;
913
+ return {
914
+ name: match.name,
915
+ description: match.description,
916
+ methods: route?.methods?.filter((m) => m !== "*") ?? ["GET"],
917
+ price: route?.price ?? "?",
918
+ currency: route?.currency ?? "USDC",
919
+ inputSchema,
920
+ };
921
+ }
922
+ }
923
+ }
924
+ catch {
925
+ // Fall through to next strategy
926
+ }
927
+ }
928
+ // Strategy 3: Probe endpoint for 402 response to get price info
929
+ try {
930
+ const probeRes = await fetch(url, { method: "GET" });
931
+ if (probeRes.status === 402) {
932
+ const paymentHeader = probeRes.headers.get("payment-required") ??
933
+ probeRes.headers.get("x-payment-required");
934
+ if (paymentHeader) {
935
+ const decoded = Buffer.from(paymentHeader, "base64").toString("utf-8");
936
+ const requirements = JSON.parse(decoded);
937
+ const accept = requirements.accepts?.[0] ?? requirements;
938
+ const amountAtomic = BigInt(accept.maxAmountRequired ?? "0");
939
+ const amountUsd = Number(amountAtomic) / 1000000;
940
+ // Extract service name from URL path
941
+ const serviceName = parts[parts.length - 1] ?? "endpoint";
942
+ return {
943
+ name: serviceName,
944
+ description: "",
945
+ methods: ["GET"],
946
+ price: amountUsd.toFixed(6),
947
+ currency: "USDC",
948
+ inputSchema: null,
949
+ };
950
+ }
951
+ }
952
+ }
953
+ catch {
954
+ // Fall through
955
+ }
956
+ return null;
957
+ }
958
+ // ── Call ──────────────────────────────────────────────────────────────
959
+ export async function x402CallCommand(url, opts = {}) {
960
+ if (!url) {
961
+ output.error("Usage: bankr x402 call <url> [--method POST] [--body '{}']");
962
+ process.exit(1);
963
+ }
964
+ let method = opts.method?.toUpperCase() ?? "GET";
965
+ const maxPaymentUsd = opts.maxPayment ? parseFloat(opts.maxPayment) : 1;
966
+ let requestBody = opts.body;
967
+ if (isNaN(maxPaymentUsd) || maxPaymentUsd <= 0 || maxPaymentUsd > 10) {
968
+ output.error("--max-payment must be between 0 and 10 (USD)");
969
+ process.exit(1);
970
+ }
971
+ // Interactive mode: fetch schema and prompt for input values
972
+ let resolvedPrice = null;
973
+ if (opts.interactive) {
974
+ const schema = await fetchSchemaForInteractive(url);
975
+ if (schema) {
976
+ // Full schema available — show endpoint info and prompt for fields
977
+ console.log();
978
+ console.log(` ${chalk.bold(schema.name)}`);
979
+ if (schema.description) {
980
+ console.log(` ${chalk.dim(schema.description)}`);
981
+ }
982
+ console.log(` ${chalk.dim("Price")} ${chalk.green(`$${schema.price} ${schema.currency}`)}`);
983
+ console.log();
984
+ // Use the endpoint's actual price and preferred method
985
+ resolvedPrice = parseFloat(schema.price);
986
+ if (schema.methods.length > 0) {
987
+ method = schema.methods.includes("POST") ? "POST" : schema.methods[0];
988
+ }
989
+ // Prompt for each input field
990
+ if (schema.inputSchema && schema.inputSchema.properties) {
991
+ const required = new Set(schema.inputSchema.required ?? []);
992
+ const values = {};
993
+ for (const [key, prop] of Object.entries(schema.inputSchema.properties)) {
994
+ const typedProp = prop;
995
+ const isRequired = required.has(key);
996
+ const label = isRequired
997
+ ? `${chalk.bold(key)} ${chalk.dim(`(${typedProp.type})`)}`
998
+ : `${key} ${chalk.dim(`(${typedProp.type}, optional)`)}`;
999
+ const hint = typedProp.description ?? "";
1000
+ // Enum fields → select prompt
1001
+ if (typedProp.enum && typedProp.enum.length > 0) {
1002
+ const selected = await select({
1003
+ message: `${label}${hint ? ` — ${chalk.dim(hint)}` : ""}`,
1004
+ choices: typedProp.enum.map((v) => ({
1005
+ name: String(v),
1006
+ value: String(v),
1007
+ })),
1008
+ });
1009
+ values[key] =
1010
+ typedProp.type === "number" || typedProp.type === "integer"
1011
+ ? Number(selected)
1012
+ : selected;
1013
+ }
1014
+ else {
1015
+ // Text input
1016
+ const answer = await input({
1017
+ message: `${label}${hint ? ` — ${chalk.dim(hint)}` : ""}`,
1018
+ required: isRequired,
1019
+ });
1020
+ if (answer === "" && !isRequired)
1021
+ continue;
1022
+ // Coerce types
1023
+ if (typedProp.type === "number" || typedProp.type === "integer") {
1024
+ const num = Number(answer);
1025
+ if (isNaN(num)) {
1026
+ output.error(`Invalid number for ${key}: "${answer}"`);
1027
+ process.exit(1);
1028
+ }
1029
+ values[key] = num;
1030
+ }
1031
+ else if (typedProp.type === "boolean") {
1032
+ values[key] = answer.toLowerCase() === "true" || answer === "1";
1033
+ }
1034
+ else {
1035
+ values[key] = answer;
1036
+ }
1037
+ }
1038
+ }
1039
+ if (Object.keys(values).length > 0) {
1040
+ if (method === "GET") {
1041
+ // Append as query params
1042
+ const params = new URLSearchParams();
1043
+ for (const [k, v] of Object.entries(values)) {
1044
+ params.set(k, String(v));
1045
+ }
1046
+ url = `${url}${url.includes("?") ? "&" : "?"}${params.toString()}`;
1047
+ }
1048
+ else {
1049
+ requestBody = JSON.stringify(values);
1050
+ }
1051
+ }
1052
+ }
1053
+ }
1054
+ else {
1055
+ // No schema available — fallback: prompt for method and body
1056
+ output.warn("No schema found for this endpoint. Falling back to manual input.");
1057
+ console.log();
1058
+ method = await select({
1059
+ message: "HTTP method",
1060
+ choices: [
1061
+ { name: "GET", value: "GET" },
1062
+ { name: "POST", value: "POST" },
1063
+ { name: "PUT", value: "PUT" },
1064
+ { name: "DELETE", value: "DELETE" },
1065
+ ],
1066
+ default: method,
1067
+ theme: output.bankrTheme,
1068
+ });
1069
+ if (method === "POST" || method === "PUT") {
1070
+ const bodyInput = await input({
1071
+ message: "JSON body (or leave empty)",
1072
+ theme: output.bankrTheme,
1073
+ });
1074
+ if (bodyInput.trim()) {
1075
+ try {
1076
+ JSON.parse(bodyInput);
1077
+ requestBody = bodyInput;
1078
+ }
1079
+ catch {
1080
+ output.error("Invalid JSON body");
1081
+ process.exit(1);
1082
+ }
1083
+ }
1084
+ }
1085
+ else {
1086
+ const qsInput = await input({
1087
+ message: "Query params (key=val&key2=val2, or leave empty)",
1088
+ theme: output.bankrTheme,
1089
+ });
1090
+ if (qsInput.trim()) {
1091
+ url = `${url}${url.includes("?") ? "&" : "?"}${qsInput}`;
1092
+ }
1093
+ }
1094
+ }
1095
+ // Show what we're about to send
1096
+ console.log(` ${chalk.dim("─".repeat(60))}`);
1097
+ console.log(` ${chalk.dim("Method")} ${method}`);
1098
+ console.log(` ${chalk.dim("URL")} ${url}`);
1099
+ if (requestBody) {
1100
+ console.log(` ${chalk.dim("Body")} ${requestBody}`);
1101
+ }
1102
+ console.log();
1103
+ }
1104
+ // Confirm payment unless --yes
1105
+ if (!opts.yes && !opts.interactive) {
1106
+ const confirmed = await confirm({
1107
+ message: `Call ${chalk.bold(url)} with up to ${chalk.green(`$${maxPaymentUsd} USDC`)} payment?`,
1108
+ default: true,
1109
+ });
1110
+ if (!confirmed) {
1111
+ output.info("Cancelled.");
1112
+ return;
1113
+ }
1114
+ }
1115
+ else if (opts.interactive) {
1116
+ const confirmed = await confirm({
1117
+ message: `Submit with ${chalk.green(`$${resolvedPrice ?? maxPaymentUsd} USDC`)} payment?`,
1118
+ default: true,
1119
+ });
1120
+ if (!confirmed) {
1121
+ output.info("Cancelled.");
1122
+ return;
1123
+ }
1124
+ }
1125
+ const spin = output.spinner(`Calling ${method} ${url}...`);
1126
+ try {
1127
+ const res = await fetch(`${getApiUrl()}/wallet/x402-pay`, {
1128
+ method: "POST",
1129
+ headers: authHeaders(),
1130
+ body: JSON.stringify({
1131
+ url,
1132
+ method,
1133
+ body: requestBody,
1134
+ maxPaymentUsd: resolvedPrice ?? maxPaymentUsd,
1135
+ }),
1136
+ });
1137
+ const result = await handleResponse(res);
1138
+ spin.stop();
1139
+ if (opts.raw) {
1140
+ console.log(JSON.stringify(result, null, 2));
1141
+ return;
1142
+ }
1143
+ if (!result.success) {
1144
+ output.error(result.error ?? "Call failed");
1145
+ process.exit(1);
1146
+ }
1147
+ // Show endpoint schema info (Bankr-hosted endpoints only)
1148
+ if (result.endpointSchema) {
1149
+ const ep = result.endpointSchema;
1150
+ console.log();
1151
+ console.log(` ${chalk.dim("Endpoint")} ${chalk.bold(ep.name)} — ${ep.description}`);
1152
+ if (ep.schema?.input) {
1153
+ console.log(` ${chalk.dim("Input")} ${chalk.dim(JSON.stringify(ep.schema.input))}`);
1154
+ }
1155
+ if (ep.schema?.output) {
1156
+ console.log(` ${chalk.dim("Output")} ${chalk.dim(JSON.stringify(ep.schema.output))}`);
1157
+ }
1158
+ }
1159
+ // Show payment info
1160
+ if (result.paymentMade) {
1161
+ console.log();
1162
+ console.log(` ${chalk.green("Paid")} ${chalk.bold(`$${result.paymentMade.amountUsd.toFixed(4)}`)} USDC on ${result.paymentMade.network}`);
1163
+ }
1164
+ // Show response
1165
+ console.log();
1166
+ console.log(` ${chalk.dim("Status")} ${result.status}`);
1167
+ console.log(` ${chalk.dim("Response")}`);
1168
+ console.log();
1169
+ if (typeof result.response === "string") {
1170
+ console.log(` ${result.response}`);
1171
+ }
1172
+ else {
1173
+ console.log(JSON.stringify(result.response, null, 2));
1174
+ }
1175
+ console.log();
1176
+ }
1177
+ catch (err) {
1178
+ spin.fail("Call failed");
1179
+ output.error(err instanceof Error ? err.message : String(err));
1180
+ process.exit(1);
1181
+ }
1182
+ }
1183
+ // ── Search ────────────────────────────────────────────────────────────
712
1184
  export async function x402SearchCommand(queryParts, opts = {}) {
713
1185
  const query = queryParts.join(" ").trim();
714
1186
  if (!query) {
package/dist/lib/api.d.ts CHANGED
@@ -381,5 +381,24 @@ export interface TransferResponse {
381
381
  error?: string;
382
382
  }
383
383
  export declare function transfer(request: TransferRequest): Promise<TransferResponse>;
384
+ export interface X402PayRequest {
385
+ url: string;
386
+ method?: string;
387
+ body?: string;
388
+ headers?: Record<string, string>;
389
+ maxPaymentUsd?: number;
390
+ }
391
+ export interface X402PayResponse {
392
+ success: boolean;
393
+ status?: number;
394
+ response?: unknown;
395
+ paymentMade?: {
396
+ amountUsd: number;
397
+ network: string;
398
+ payTo: string;
399
+ };
400
+ error?: string;
401
+ }
402
+ export declare function x402Pay(request: X402PayRequest): Promise<X402PayResponse>;
384
403
  export declare function buildPublicClaimTxs(beneficiaryAddress: string, tokenAddresses: string[]): Promise<BuildClaimResponse>;
385
404
  //# sourceMappingURL=api.d.ts.map
package/dist/lib/api.js CHANGED
@@ -280,6 +280,14 @@ export async function transfer(request) {
280
280
  });
281
281
  return handleResponse(res);
282
282
  }
283
+ export async function x402Pay(request) {
284
+ const res = await fetch(`${getApiUrl()}/wallet/x402-pay`, {
285
+ method: "POST",
286
+ headers: authHeaders(),
287
+ body: JSON.stringify(request),
288
+ });
289
+ return handleResponse(res);
290
+ }
283
291
  export async function buildPublicClaimTxs(beneficiaryAddress, tokenAddresses) {
284
292
  const res = await fetch(`${getApiUrl()}/public/doppler/build-claim`, {
285
293
  method: "POST",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bankr/cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Official CLI for the Bankr AI agent platform",
5
5
  "type": "module",
6
6
  "bin": {