@bankr/cli 0.2.0 → 0.2.2
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 +60 -0
- package/dist/commands/llm.js +28 -16
- package/dist/commands/x402.d.ts +69 -0
- package/dist/commands/x402.js +636 -0
- package/dist/lib/chains.js +4 -0
- package/dist/lib/output.d.ts +2 -0
- package/dist/lib/output.js +2 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -22,6 +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
26
|
import { profileViewCommand, profileCreateCommand, profileUpdateCommand, profileDeleteCommand, profileAddUpdateCommand, } from "./commands/profile.js";
|
|
26
27
|
import * as output from "./lib/output.js";
|
|
27
28
|
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
@@ -712,6 +713,65 @@ program
|
|
|
712
713
|
.action(async (opts) => {
|
|
713
714
|
await updateCommand({ check: opts.check });
|
|
714
715
|
});
|
|
716
|
+
// ── x402 Endpoint Hosting ─────────────────────────────────────────────
|
|
717
|
+
const x402Cmd = program
|
|
718
|
+
.command("x402")
|
|
719
|
+
.description("Deploy and manage x402 paid API endpoints");
|
|
720
|
+
x402Cmd
|
|
721
|
+
.command("init")
|
|
722
|
+
.description("Scaffold x402/ folder and bankr.x402.json config")
|
|
723
|
+
.action(x402InitCommand);
|
|
724
|
+
x402Cmd
|
|
725
|
+
.command("add <name>")
|
|
726
|
+
.description("Add a new x402 service handler")
|
|
727
|
+
.action(x402AddCommand);
|
|
728
|
+
x402Cmd
|
|
729
|
+
.command("configure <name>")
|
|
730
|
+
.description("Interactively configure pricing and description")
|
|
731
|
+
.action(x402ConfigureCommand);
|
|
732
|
+
x402Cmd
|
|
733
|
+
.command("deploy [name]")
|
|
734
|
+
.description("Bundle and deploy services to Bankr")
|
|
735
|
+
.action(x402DeployCommand);
|
|
736
|
+
x402Cmd
|
|
737
|
+
.command("list")
|
|
738
|
+
.description("List your deployed x402 endpoints")
|
|
739
|
+
.action(x402ListCommand);
|
|
740
|
+
x402Cmd
|
|
741
|
+
.command("pause <name>")
|
|
742
|
+
.description("Pause a deployed endpoint")
|
|
743
|
+
.action(async (name) => x402PauseResumeCommand(name, "pause"));
|
|
744
|
+
x402Cmd
|
|
745
|
+
.command("resume <name>")
|
|
746
|
+
.description("Resume a paused endpoint")
|
|
747
|
+
.action(async (name) => x402PauseResumeCommand(name, "resume"));
|
|
748
|
+
x402Cmd
|
|
749
|
+
.command("delete <name>")
|
|
750
|
+
.description("Delete a deployed endpoint")
|
|
751
|
+
.action(x402DeleteCommand);
|
|
752
|
+
x402Cmd
|
|
753
|
+
.command("revenue [name]")
|
|
754
|
+
.description("View endpoint earnings breakdown")
|
|
755
|
+
.action(x402RevenueCommand);
|
|
756
|
+
const x402EnvCmd = x402Cmd
|
|
757
|
+
.command("env")
|
|
758
|
+
.description("Manage encrypted environment variables");
|
|
759
|
+
x402EnvCmd
|
|
760
|
+
.command("set <keyValue>")
|
|
761
|
+
.description("Set an env var (KEY=VALUE)")
|
|
762
|
+
.action(x402EnvSetCommand);
|
|
763
|
+
x402EnvCmd
|
|
764
|
+
.command("list")
|
|
765
|
+
.description("List env var names")
|
|
766
|
+
.action(x402EnvListCommand);
|
|
767
|
+
x402EnvCmd
|
|
768
|
+
.command("unset <key>")
|
|
769
|
+
.description("Remove an env var")
|
|
770
|
+
.action(x402EnvUnsetCommand);
|
|
771
|
+
x402Cmd
|
|
772
|
+
.command("search [query...]")
|
|
773
|
+
.description("Search the x402 service marketplace (no auth required)")
|
|
774
|
+
.action(async (query) => x402SearchCommand(query));
|
|
715
775
|
// Default: treat unrecognized arguments as a prompt
|
|
716
776
|
program
|
|
717
777
|
.arguments("[text...]")
|
package/dist/commands/llm.js
CHANGED
|
@@ -79,15 +79,6 @@ const GATEWAY_MODELS = [
|
|
|
79
79
|
input: IMAGE_INPUT,
|
|
80
80
|
cost: { input: 0.25, output: 1.5, cacheRead: 0.025, cacheWrite: 0.08333 },
|
|
81
81
|
},
|
|
82
|
-
{
|
|
83
|
-
id: "gemini-3-pro",
|
|
84
|
-
name: "Gemini 3 Pro",
|
|
85
|
-
owned_by: "google",
|
|
86
|
-
contextWindow: 1048576,
|
|
87
|
-
maxTokens: 65536,
|
|
88
|
-
input: IMAGE_INPUT,
|
|
89
|
-
cost: { input: 2.0, output: 12.0, cacheRead: 0.2, cacheWrite: 0.375 },
|
|
90
|
-
},
|
|
91
82
|
{
|
|
92
83
|
id: "gemini-3-flash",
|
|
93
84
|
name: "Gemini 3 Flash",
|
|
@@ -238,20 +229,29 @@ const GATEWAY_MODELS = [
|
|
|
238
229
|
id: "minimax-m2.5",
|
|
239
230
|
name: "MiniMax M2.5",
|
|
240
231
|
owned_by: "minimax",
|
|
241
|
-
contextWindow:
|
|
232
|
+
contextWindow: 204800,
|
|
242
233
|
maxTokens: 196608,
|
|
243
234
|
input: TEXT_INPUT,
|
|
244
|
-
cost: { input: 0.
|
|
235
|
+
cost: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 },
|
|
245
236
|
},
|
|
246
237
|
{
|
|
247
238
|
id: "minimax-m2.7",
|
|
248
239
|
name: "MiniMax M2.7",
|
|
249
240
|
owned_by: "minimax",
|
|
250
241
|
contextWindow: 204800,
|
|
251
|
-
maxTokens:
|
|
242
|
+
maxTokens: 196608,
|
|
252
243
|
input: TEXT_INPUT,
|
|
253
244
|
cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 },
|
|
254
245
|
},
|
|
246
|
+
{
|
|
247
|
+
id: "minimax-m2.7-highspeed",
|
|
248
|
+
name: "MiniMax M2.7 Highspeed",
|
|
249
|
+
owned_by: "minimax",
|
|
250
|
+
contextWindow: 204800,
|
|
251
|
+
maxTokens: 196608,
|
|
252
|
+
input: TEXT_INPUT,
|
|
253
|
+
cost: { input: 0.6, output: 2.4, cacheRead: 0.06, cacheWrite: 0 },
|
|
254
|
+
},
|
|
255
255
|
{
|
|
256
256
|
id: "glm-5",
|
|
257
257
|
name: "GLM-5",
|
|
@@ -261,6 +261,15 @@ const GATEWAY_MODELS = [
|
|
|
261
261
|
input: TEXT_INPUT,
|
|
262
262
|
cost: { input: 0.72, output: 2.3, cacheRead: 0, cacheWrite: 0 },
|
|
263
263
|
},
|
|
264
|
+
{
|
|
265
|
+
id: "glm-5-turbo",
|
|
266
|
+
name: "GLM-5 Turbo",
|
|
267
|
+
owned_by: "z-ai",
|
|
268
|
+
contextWindow: 202752,
|
|
269
|
+
maxTokens: 131072,
|
|
270
|
+
input: TEXT_INPUT,
|
|
271
|
+
cost: { input: 1.2, output: 4.0, cacheRead: 0.24, cacheWrite: 0 },
|
|
272
|
+
},
|
|
264
273
|
];
|
|
265
274
|
/** Fetch live model list from the gateway; falls back to hardcoded catalog. */
|
|
266
275
|
async function resolveModels() {
|
|
@@ -715,11 +724,12 @@ export async function setupOpenclawCommand(opts) {
|
|
|
715
724
|
const llmKey = getLlmKey();
|
|
716
725
|
const llmUrl = getLlmUrl();
|
|
717
726
|
const { models } = await resolveModels();
|
|
727
|
+
const activeModels = models.filter((m) => !m.deprecation);
|
|
718
728
|
const providerConfig = {
|
|
719
729
|
baseUrl: llmUrl,
|
|
720
730
|
apiKey: llmKey ?? "${BANKR_API_KEY}",
|
|
721
731
|
api: "openai-completions",
|
|
722
|
-
models:
|
|
732
|
+
models: activeModels.map((m) => ({
|
|
723
733
|
id: m.id,
|
|
724
734
|
name: m.name,
|
|
725
735
|
...(m.owned_by === "anthropic" ? { api: "anthropic-messages" } : {}),
|
|
@@ -753,8 +763,9 @@ export async function setupOpenCodeCommand(opts) {
|
|
|
753
763
|
const llmKey = getLlmKey();
|
|
754
764
|
const llmUrl = getLlmUrl();
|
|
755
765
|
const { models } = await resolveModels();
|
|
766
|
+
const activeModels = models.filter((m) => !m.deprecation);
|
|
756
767
|
const modelsObj = {};
|
|
757
|
-
for (const m of
|
|
768
|
+
for (const m of activeModels) {
|
|
758
769
|
modelsObj[m.id] = { name: m.name };
|
|
759
770
|
}
|
|
760
771
|
const bankrProvider = {
|
|
@@ -796,9 +807,10 @@ export async function setupCursorCommand() {
|
|
|
796
807
|
const llmUrl = getLlmUrl();
|
|
797
808
|
const token = llmKey ?? "<your-bankr-api-key>";
|
|
798
809
|
const { models } = await resolveModels();
|
|
810
|
+
const activeModels = models.filter((m) => !m.deprecation);
|
|
799
811
|
// Pick one model per provider as recommended examples
|
|
800
|
-
const recommendedIds = ["claude-opus-4.6", "gemini-3-pro", "gpt-5.2"];
|
|
801
|
-
const recommended = recommendedIds.filter((id) =>
|
|
812
|
+
const recommendedIds = ["claude-opus-4.6", "gemini-3.1-pro", "gpt-5.2"];
|
|
813
|
+
const recommended = recommendedIds.filter((id) => activeModels.some((m) => m.id === id));
|
|
802
814
|
output.brandBold("Cursor — Bankr LLM Gateway");
|
|
803
815
|
console.log();
|
|
804
816
|
output.info("In Cursor, go to Settings > Models and configure:");
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI commands for x402 endpoint hosting.
|
|
3
|
+
*
|
|
4
|
+
* bankr x402 init — Scaffold x402/ folder + bankr.x402.json
|
|
5
|
+
* bankr x402 add <name> — Add a new service
|
|
6
|
+
* bankr x402 configure <name> — Interactive pricing/description setup
|
|
7
|
+
* bankr x402 deploy [name] — Deploy all or a single service
|
|
8
|
+
* bankr x402 list — List deployed services
|
|
9
|
+
* bankr x402 logs <name> — View request logs (future)
|
|
10
|
+
* bankr x402 pause <name> — Pause a service
|
|
11
|
+
* bankr x402 resume <name> — Resume a service
|
|
12
|
+
* bankr x402 delete <name> — Delete a service
|
|
13
|
+
* bankr x402 revenue [name] — View earnings
|
|
14
|
+
* bankr x402 env set KEY=VALUE — Set encrypted env var
|
|
15
|
+
* bankr x402 env list — List env var names
|
|
16
|
+
* bankr x402 env unset KEY — Remove env var
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* bankr x402 init — Scaffold x402/ folder + bankr.x402.json
|
|
20
|
+
*/
|
|
21
|
+
export declare function x402InitCommand(): Promise<void>;
|
|
22
|
+
export declare function x402AddCommand(name: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* bankr x402 configure <name> — Interactive pricing/description setup
|
|
25
|
+
*/
|
|
26
|
+
export declare function x402ConfigureCommand(name: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* bankr x402 deploy [name] — Deploy services
|
|
29
|
+
*
|
|
30
|
+
* This bundles the handler(s) with Bun and uploads via the Bankr API.
|
|
31
|
+
* If no name is provided, deploys all services in x402/.
|
|
32
|
+
*/
|
|
33
|
+
export declare function x402DeployCommand(name?: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* bankr x402 list — List deployed services
|
|
36
|
+
*/
|
|
37
|
+
export declare function x402ListCommand(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* bankr x402 pause/resume <name>
|
|
40
|
+
*/
|
|
41
|
+
export declare function x402PauseResumeCommand(name: string, action: "pause" | "resume"): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* bankr x402 delete <name>
|
|
44
|
+
*/
|
|
45
|
+
export declare function x402DeleteCommand(name: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* bankr x402 revenue [name]
|
|
48
|
+
*/
|
|
49
|
+
export declare function x402RevenueCommand(name?: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* bankr x402 env set KEY=VALUE
|
|
52
|
+
*/
|
|
53
|
+
export declare function x402EnvSetCommand(keyValue: string): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* bankr x402 env list
|
|
56
|
+
*/
|
|
57
|
+
export declare function x402EnvListCommand(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* bankr x402 env unset KEY
|
|
60
|
+
*/
|
|
61
|
+
export declare function x402EnvUnsetCommand(key: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* bankr x402 search <query> — Search the x402 service marketplace
|
|
64
|
+
*
|
|
65
|
+
* Public — no auth required. Uses vector search + keyword matching
|
|
66
|
+
* to find relevant paid API services.
|
|
67
|
+
*/
|
|
68
|
+
export declare function x402SearchCommand(queryParts: string[]): Promise<void>;
|
|
69
|
+
//# sourceMappingURL=x402.d.ts.map
|
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI commands for x402 endpoint hosting.
|
|
3
|
+
*
|
|
4
|
+
* bankr x402 init — Scaffold x402/ folder + bankr.x402.json
|
|
5
|
+
* bankr x402 add <name> — Add a new service
|
|
6
|
+
* bankr x402 configure <name> — Interactive pricing/description setup
|
|
7
|
+
* bankr x402 deploy [name] — Deploy all or a single service
|
|
8
|
+
* bankr x402 list — List deployed services
|
|
9
|
+
* bankr x402 logs <name> — View request logs (future)
|
|
10
|
+
* bankr x402 pause <name> — Pause a service
|
|
11
|
+
* bankr x402 resume <name> — Resume a service
|
|
12
|
+
* bankr x402 delete <name> — Delete a service
|
|
13
|
+
* bankr x402 revenue [name] — View earnings
|
|
14
|
+
* bankr x402 env set KEY=VALUE — Set encrypted env var
|
|
15
|
+
* bankr x402 env list — List env var names
|
|
16
|
+
* bankr x402 env unset KEY — Remove env var
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { input, select, confirm } from "@inquirer/prompts";
|
|
21
|
+
import * as output from "../lib/output.js";
|
|
22
|
+
import { getApiUrl, requireApiKey, readConfig, CLI_USER_AGENT, } from "../lib/config.js";
|
|
23
|
+
// ── Config file helpers ─────────────────────────────────────────────────
|
|
24
|
+
const CONFIG_FILENAME = "bankr.x402.json";
|
|
25
|
+
function findProjectRoot() {
|
|
26
|
+
return process.cwd();
|
|
27
|
+
}
|
|
28
|
+
function loadConfigFile(projectRoot) {
|
|
29
|
+
const candidates = [
|
|
30
|
+
join(projectRoot, CONFIG_FILENAME),
|
|
31
|
+
join(projectRoot, "x402", CONFIG_FILENAME),
|
|
32
|
+
];
|
|
33
|
+
for (const p of candidates) {
|
|
34
|
+
if (existsSync(p)) {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
output.error(`Failed to parse ${p}. Check that it is valid JSON.`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function saveConfigFile(projectRoot, config) {
|
|
47
|
+
const configPath = join(projectRoot, CONFIG_FILENAME);
|
|
48
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
49
|
+
}
|
|
50
|
+
// ── API helpers ─────────────────────────────────────────────────────────
|
|
51
|
+
function authHeaders() {
|
|
52
|
+
const headers = {
|
|
53
|
+
"X-API-Key": requireApiKey(),
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
"User-Agent": CLI_USER_AGENT,
|
|
56
|
+
};
|
|
57
|
+
const config = readConfig();
|
|
58
|
+
if (config.partnerKey) {
|
|
59
|
+
headers["X-Partner-Key"] = config.partnerKey;
|
|
60
|
+
}
|
|
61
|
+
return headers;
|
|
62
|
+
}
|
|
63
|
+
async function handleResponse(res) {
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const body = (await res
|
|
66
|
+
.json()
|
|
67
|
+
.catch(() => ({ message: res.statusText })));
|
|
68
|
+
const msg = body.message || body.error || res.statusText;
|
|
69
|
+
throw new Error(`API error (${res.status}): ${msg}`);
|
|
70
|
+
}
|
|
71
|
+
return res.json();
|
|
72
|
+
}
|
|
73
|
+
// ── Default handler template ────────────────────────────────────────────
|
|
74
|
+
const HANDLER_TEMPLATE = `/**
|
|
75
|
+
* x402 service handler.
|
|
76
|
+
*
|
|
77
|
+
* Receives a standard Web Request, returns a standard Web Response.
|
|
78
|
+
* Bankr wraps the x402 payment layer around this — you just write the logic.
|
|
79
|
+
*
|
|
80
|
+
* Environment variables are available via process.env.
|
|
81
|
+
*/
|
|
82
|
+
export default async function handler(req: Request): Promise<Response> {
|
|
83
|
+
const url = new URL(req.url);
|
|
84
|
+
|
|
85
|
+
return Response.json({
|
|
86
|
+
message: "Hello from SERVICE_NAME!",
|
|
87
|
+
timestamp: new Date().toISOString(),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
// ── Commands ────────────────────────────────────────────────────────────
|
|
92
|
+
/**
|
|
93
|
+
* bankr x402 init — Scaffold x402/ folder + bankr.x402.json
|
|
94
|
+
*/
|
|
95
|
+
export async function x402InitCommand() {
|
|
96
|
+
const root = findProjectRoot();
|
|
97
|
+
const x402Dir = join(root, "x402");
|
|
98
|
+
if (existsSync(x402Dir)) {
|
|
99
|
+
output.warn("x402/ directory already exists");
|
|
100
|
+
const overwrite = await confirm({
|
|
101
|
+
message: "Re-initialize config?",
|
|
102
|
+
default: false,
|
|
103
|
+
theme: output.bankrTheme,
|
|
104
|
+
});
|
|
105
|
+
if (!overwrite)
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
mkdirSync(x402Dir, { recursive: true });
|
|
110
|
+
output.success(`Created x402/ directory`);
|
|
111
|
+
}
|
|
112
|
+
const existing = loadConfigFile(root);
|
|
113
|
+
if (!existing) {
|
|
114
|
+
const config = {
|
|
115
|
+
network: "base",
|
|
116
|
+
currency: "USDC",
|
|
117
|
+
services: {},
|
|
118
|
+
};
|
|
119
|
+
saveConfigFile(root, config);
|
|
120
|
+
output.success(`Created ${CONFIG_FILENAME}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
output.info(`${CONFIG_FILENAME} already exists, keeping it`);
|
|
124
|
+
}
|
|
125
|
+
output.info("Next: run 'bankr x402 add <name>' to create your first service");
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* bankr x402 add <name> — Add a new service with handler scaffold
|
|
129
|
+
*/
|
|
130
|
+
const MAX_SERVICE_NAME_LENGTH = 47; // bx4- (4) + hash (12) + - (1) = 17 overhead; 64 - 17 = 47
|
|
131
|
+
const SERVICE_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
132
|
+
function validateServiceName(name) {
|
|
133
|
+
if (!SERVICE_NAME_PATTERN.test(name)) {
|
|
134
|
+
return `Invalid service name "${name}". Use only letters, numbers, hyphens, and underscores.`;
|
|
135
|
+
}
|
|
136
|
+
if (name.length > MAX_SERVICE_NAME_LENGTH) {
|
|
137
|
+
return `Service name "${name}" is too long (${name.length} chars). Maximum is ${MAX_SERVICE_NAME_LENGTH} characters.`;
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
export async function x402AddCommand(name) {
|
|
142
|
+
const nameError = validateServiceName(name);
|
|
143
|
+
if (nameError) {
|
|
144
|
+
output.error(nameError);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
const root = findProjectRoot();
|
|
148
|
+
const x402Dir = join(root, "x402");
|
|
149
|
+
if (!existsSync(x402Dir)) {
|
|
150
|
+
output.error("No x402/ directory found. Run 'bankr x402 init' first.");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
const serviceDir = join(x402Dir, name);
|
|
154
|
+
if (existsSync(serviceDir)) {
|
|
155
|
+
output.error(`Service "${name}" already exists at x402/${name}/`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
// Ask for method
|
|
159
|
+
const method = await select({
|
|
160
|
+
message: "HTTP method:",
|
|
161
|
+
choices: [
|
|
162
|
+
{ name: "GET — query parameters in URL", value: "GET" },
|
|
163
|
+
{ name: "POST — JSON body", value: "POST" },
|
|
164
|
+
{ name: "Any — accept all methods", value: "*" },
|
|
165
|
+
],
|
|
166
|
+
default: "GET",
|
|
167
|
+
theme: output.bankrTheme,
|
|
168
|
+
});
|
|
169
|
+
// Create service directory and handler
|
|
170
|
+
mkdirSync(serviceDir, { recursive: true });
|
|
171
|
+
const isPost = method === "POST";
|
|
172
|
+
const handlerContent = isPost
|
|
173
|
+
? `/**
|
|
174
|
+
* ${name} — x402 service handler (POST with JSON body).
|
|
175
|
+
*/
|
|
176
|
+
export default async function handler(req: Request): Promise<Response> {
|
|
177
|
+
if (req.method !== "POST") {
|
|
178
|
+
return Response.json({ error: "POST required" }, { status: 405 });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const body = await req.json();
|
|
182
|
+
// TODO: validate body fields
|
|
183
|
+
|
|
184
|
+
return Response.json({
|
|
185
|
+
message: "Hello from ${name}!",
|
|
186
|
+
received: body,
|
|
187
|
+
timestamp: new Date().toISOString(),
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
`
|
|
191
|
+
: `/**
|
|
192
|
+
* ${name} — x402 service handler.
|
|
193
|
+
*/
|
|
194
|
+
export default async function handler(req: Request): Promise<Response> {
|
|
195
|
+
const url = new URL(req.url);
|
|
196
|
+
// const myParam = url.searchParams.get("myParam") ?? "default";
|
|
197
|
+
|
|
198
|
+
return Response.json({
|
|
199
|
+
message: "Hello from ${name}!",
|
|
200
|
+
timestamp: new Date().toISOString(),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
writeFileSync(join(serviceDir, "index.ts"), handlerContent);
|
|
205
|
+
// Build schema scaffold based on method
|
|
206
|
+
const schema = {};
|
|
207
|
+
if (isPost) {
|
|
208
|
+
schema.body = { field: "string" };
|
|
209
|
+
}
|
|
210
|
+
else if (method === "GET") {
|
|
211
|
+
schema.queryParams = { param: "string" };
|
|
212
|
+
}
|
|
213
|
+
schema.output = { result: "string" };
|
|
214
|
+
// Add to config
|
|
215
|
+
let config = loadConfigFile(root);
|
|
216
|
+
if (!config) {
|
|
217
|
+
config = { services: {} };
|
|
218
|
+
}
|
|
219
|
+
config.services[name] = {
|
|
220
|
+
price: "0.001",
|
|
221
|
+
description: `${name} service`,
|
|
222
|
+
methods: method === "*" ? undefined : [method],
|
|
223
|
+
schema,
|
|
224
|
+
};
|
|
225
|
+
saveConfigFile(root, config);
|
|
226
|
+
output.success(`Created x402/${name}/index.ts`);
|
|
227
|
+
output.info(`Default price: $0.001 USDC. Run 'bankr x402 configure ${name}' to customize.`);
|
|
228
|
+
output.info(`Edit the schema in bankr.x402.json to describe your ${isPost ? "body fields" : "query parameters"} for agent discovery.`);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* bankr x402 configure <name> — Interactive pricing/description setup
|
|
232
|
+
*/
|
|
233
|
+
export async function x402ConfigureCommand(name) {
|
|
234
|
+
const root = findProjectRoot();
|
|
235
|
+
let config = loadConfigFile(root);
|
|
236
|
+
if (!config) {
|
|
237
|
+
config = { services: {} };
|
|
238
|
+
}
|
|
239
|
+
const existing = config.services[name] ?? { price: "0.001" };
|
|
240
|
+
const description = await input({
|
|
241
|
+
message: "Service description:",
|
|
242
|
+
default: existing.description ?? `${name} service`,
|
|
243
|
+
theme: output.bankrTheme,
|
|
244
|
+
});
|
|
245
|
+
const price = await input({
|
|
246
|
+
message: "Price per request (USD):",
|
|
247
|
+
default: existing.price ?? "0.001",
|
|
248
|
+
theme: output.bankrTheme,
|
|
249
|
+
});
|
|
250
|
+
const currency = "USDC";
|
|
251
|
+
const network = await select({
|
|
252
|
+
message: "Network:",
|
|
253
|
+
choices: [
|
|
254
|
+
{ name: "Base", value: "base" },
|
|
255
|
+
{ name: "Base Sepolia (testnet)", value: "base-sepolia" },
|
|
256
|
+
],
|
|
257
|
+
default: existing.network ?? "base",
|
|
258
|
+
theme: output.bankrTheme,
|
|
259
|
+
});
|
|
260
|
+
const method = await select({
|
|
261
|
+
message: "HTTP method:",
|
|
262
|
+
choices: [
|
|
263
|
+
{ name: "GET — query parameters in URL", value: "GET" },
|
|
264
|
+
{ name: "POST — JSON body", value: "POST" },
|
|
265
|
+
{ name: "Any — accept all methods", value: "*" },
|
|
266
|
+
],
|
|
267
|
+
default: existing.methods?.[0] ?? "GET",
|
|
268
|
+
theme: output.bankrTheme,
|
|
269
|
+
});
|
|
270
|
+
config.services[name] = {
|
|
271
|
+
...existing,
|
|
272
|
+
description,
|
|
273
|
+
price,
|
|
274
|
+
currency,
|
|
275
|
+
network,
|
|
276
|
+
methods: method === "*" ? undefined : [method],
|
|
277
|
+
};
|
|
278
|
+
saveConfigFile(root, config);
|
|
279
|
+
output.success(`Updated config for "${name}"`);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* bankr x402 deploy [name] — Deploy services
|
|
283
|
+
*
|
|
284
|
+
* This bundles the handler(s) with Bun and uploads via the Bankr API.
|
|
285
|
+
* If no name is provided, deploys all services in x402/.
|
|
286
|
+
*/
|
|
287
|
+
export async function x402DeployCommand(name) {
|
|
288
|
+
const root = findProjectRoot();
|
|
289
|
+
const x402Dir = join(root, "x402");
|
|
290
|
+
if (!existsSync(x402Dir)) {
|
|
291
|
+
output.error("No x402/ directory found. Run 'bankr x402 init' first.");
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
// Load or bootstrap config
|
|
295
|
+
let config = loadConfigFile(root);
|
|
296
|
+
if (!config) {
|
|
297
|
+
config = { services: {} };
|
|
298
|
+
}
|
|
299
|
+
// Discover services
|
|
300
|
+
const { readdirSync, statSync } = await import("node:fs");
|
|
301
|
+
const entries = readdirSync(x402Dir);
|
|
302
|
+
const services = [];
|
|
303
|
+
for (const entry of entries) {
|
|
304
|
+
const entryPath = join(x402Dir, entry);
|
|
305
|
+
if (statSync(entryPath).isDirectory() &&
|
|
306
|
+
existsSync(join(entryPath, "index.ts"))) {
|
|
307
|
+
services.push(entry);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
if (services.length === 0) {
|
|
311
|
+
output.error("No services found. Run 'bankr x402 add <name>' first.");
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
// Filter to single service if name provided
|
|
315
|
+
const toDeploy = name ? services.filter((s) => s === name) : services;
|
|
316
|
+
if (name && toDeploy.length === 0) {
|
|
317
|
+
output.error(`Service "${name}" not found in x402/`);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
// Validate service names and ensure config entries
|
|
321
|
+
for (const svc of toDeploy) {
|
|
322
|
+
const nameError = validateServiceName(svc);
|
|
323
|
+
if (nameError) {
|
|
324
|
+
output.error(nameError);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
if (!config.services[svc]) {
|
|
328
|
+
config.services[svc] = {
|
|
329
|
+
price: "0.001",
|
|
330
|
+
description: `${svc} service`,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const spin = output.spinner(`Deploying ${toDeploy.length} service(s)...`);
|
|
335
|
+
try {
|
|
336
|
+
// Read raw TypeScript source for each service.
|
|
337
|
+
// Bundling + security wrapping happens server-side in the builder Lambda.
|
|
338
|
+
const bundles = [];
|
|
339
|
+
for (const svc of toDeploy) {
|
|
340
|
+
const entrypoint = join(x402Dir, svc, "index.ts");
|
|
341
|
+
if (!existsSync(entrypoint)) {
|
|
342
|
+
spin.fail(`Missing handler: x402/${svc}/index.ts`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
const source = readFileSync(entrypoint, "utf-8");
|
|
346
|
+
bundles.push({ name: svc, source });
|
|
347
|
+
}
|
|
348
|
+
// Deploy via API (server-side build + deploy)
|
|
349
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/deploy`, {
|
|
350
|
+
method: "POST",
|
|
351
|
+
headers: authHeaders(),
|
|
352
|
+
body: JSON.stringify({
|
|
353
|
+
config,
|
|
354
|
+
bundles: bundles.map((b) => ({
|
|
355
|
+
name: b.name,
|
|
356
|
+
source: b.source,
|
|
357
|
+
})),
|
|
358
|
+
}),
|
|
359
|
+
});
|
|
360
|
+
const result = await handleResponse(res);
|
|
361
|
+
spin.succeed(`Deployed ${result.deployments.length} service(s)`);
|
|
362
|
+
// Print results
|
|
363
|
+
console.log();
|
|
364
|
+
for (const dep of result.deployments) {
|
|
365
|
+
const svcConfig = config.services[dep.name];
|
|
366
|
+
output.label(" Service", dep.name);
|
|
367
|
+
output.label(" URL", dep.url);
|
|
368
|
+
output.label(" Price", `$${svcConfig?.price ?? "0.001"} ${svcConfig?.currency ?? "USDC"}/req`);
|
|
369
|
+
output.label(" Version", String(dep.version));
|
|
370
|
+
console.log();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
spin.fail("Deploy failed");
|
|
375
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* bankr x402 list — List deployed services
|
|
381
|
+
*/
|
|
382
|
+
export async function x402ListCommand() {
|
|
383
|
+
const spin = output.spinner("Fetching endpoints...");
|
|
384
|
+
try {
|
|
385
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints`, {
|
|
386
|
+
headers: authHeaders(),
|
|
387
|
+
});
|
|
388
|
+
const result = await handleResponse(res);
|
|
389
|
+
spin.stop();
|
|
390
|
+
if (result.endpoints.length === 0) {
|
|
391
|
+
output.info("No deployed endpoints. Run 'bankr x402 deploy' to get started.");
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
for (const ep of result.endpoints) {
|
|
395
|
+
const route = ep.routes[0];
|
|
396
|
+
const status = ep.status === "active"
|
|
397
|
+
? output.fmt.success("active")
|
|
398
|
+
: output.fmt.warn(ep.status);
|
|
399
|
+
console.log(` ${output.fmt.brand(ep.name)} ${status} v${ep.version} $${route?.price ?? "?"} ${route?.currency ?? "USDC"} ${ep.totalRequests} reqs $${ep.totalRevenueUsd} earned`);
|
|
400
|
+
output.dim(` ${ep.description}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
spin.fail("Failed to list endpoints");
|
|
405
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* bankr x402 pause/resume <name>
|
|
411
|
+
*/
|
|
412
|
+
export async function x402PauseResumeCommand(name, action) {
|
|
413
|
+
const status = action === "pause" ? "paused" : "active";
|
|
414
|
+
const spin = output.spinner(`${action === "pause" ? "Pausing" : "Resuming"} ${name}...`);
|
|
415
|
+
try {
|
|
416
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/${name}`, {
|
|
417
|
+
method: "PATCH",
|
|
418
|
+
headers: authHeaders(),
|
|
419
|
+
body: JSON.stringify({ status }),
|
|
420
|
+
});
|
|
421
|
+
await handleResponse(res);
|
|
422
|
+
spin.succeed(`${name} ${action === "pause" ? "paused" : "resumed"}`);
|
|
423
|
+
}
|
|
424
|
+
catch (err) {
|
|
425
|
+
spin.fail(`Failed to ${action} ${name}`);
|
|
426
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* bankr x402 delete <name>
|
|
432
|
+
*/
|
|
433
|
+
export async function x402DeleteCommand(name) {
|
|
434
|
+
const confirmed = await confirm({
|
|
435
|
+
message: `Delete endpoint "${name}"? This cannot be undone.`,
|
|
436
|
+
default: false,
|
|
437
|
+
theme: output.bankrTheme,
|
|
438
|
+
});
|
|
439
|
+
if (!confirmed)
|
|
440
|
+
return;
|
|
441
|
+
const spin = output.spinner(`Deleting ${name}...`);
|
|
442
|
+
try {
|
|
443
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/${name}`, {
|
|
444
|
+
method: "DELETE",
|
|
445
|
+
headers: authHeaders(),
|
|
446
|
+
});
|
|
447
|
+
await handleResponse(res);
|
|
448
|
+
spin.succeed(`${name} deleted`);
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
spin.fail(`Failed to delete ${name}`);
|
|
452
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
453
|
+
process.exit(1);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* bankr x402 revenue [name]
|
|
458
|
+
*/
|
|
459
|
+
export async function x402RevenueCommand(name) {
|
|
460
|
+
if (!name) {
|
|
461
|
+
// Show all endpoints revenue summary
|
|
462
|
+
await x402ListCommand();
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const spin = output.spinner(`Fetching revenue for ${name}...`);
|
|
466
|
+
try {
|
|
467
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/revenue/${name}`, {
|
|
468
|
+
headers: authHeaders(),
|
|
469
|
+
});
|
|
470
|
+
const result = await handleResponse(res);
|
|
471
|
+
spin.stop();
|
|
472
|
+
console.log(`\n Revenue for ${output.fmt.brand(name)}\n`);
|
|
473
|
+
for (const [period, data] of Object.entries(result.revenue)) {
|
|
474
|
+
const label = period === "last7d"
|
|
475
|
+
? "Last 7 days"
|
|
476
|
+
: period === "last30d"
|
|
477
|
+
? "Last 30 days"
|
|
478
|
+
: "All time";
|
|
479
|
+
const earned = (data.totalUsd - data.bankrFeesUsd).toFixed(6);
|
|
480
|
+
console.log(` ${label.padEnd(14)} ${data.requests} reqs $${earned} earned $${data.bankrFeesUsd.toFixed(6)} fees`);
|
|
481
|
+
}
|
|
482
|
+
console.log();
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
spin.fail("Failed to fetch revenue");
|
|
486
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* bankr x402 env set KEY=VALUE
|
|
492
|
+
*/
|
|
493
|
+
export async function x402EnvSetCommand(keyValue) {
|
|
494
|
+
const eqIdx = keyValue.indexOf("=");
|
|
495
|
+
if (eqIdx === -1) {
|
|
496
|
+
output.error("Usage: bankr x402 env set KEY=VALUE");
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
const key = keyValue.slice(0, eqIdx);
|
|
500
|
+
const value = keyValue.slice(eqIdx + 1);
|
|
501
|
+
if (!key) {
|
|
502
|
+
output.error("Key cannot be empty");
|
|
503
|
+
process.exit(1);
|
|
504
|
+
}
|
|
505
|
+
const spin = output.spinner(`Setting ${key}...`);
|
|
506
|
+
try {
|
|
507
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/env`, {
|
|
508
|
+
method: "POST",
|
|
509
|
+
headers: authHeaders(),
|
|
510
|
+
body: JSON.stringify({ vars: { [key]: value } }),
|
|
511
|
+
});
|
|
512
|
+
await handleResponse(res);
|
|
513
|
+
spin.succeed(`Set ${key}`);
|
|
514
|
+
}
|
|
515
|
+
catch (err) {
|
|
516
|
+
spin.fail(`Failed to set ${key}`);
|
|
517
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* bankr x402 env list
|
|
523
|
+
*/
|
|
524
|
+
export async function x402EnvListCommand() {
|
|
525
|
+
const spin = output.spinner("Fetching env vars...");
|
|
526
|
+
try {
|
|
527
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/env`, {
|
|
528
|
+
headers: authHeaders(),
|
|
529
|
+
});
|
|
530
|
+
const result = await handleResponse(res);
|
|
531
|
+
spin.stop();
|
|
532
|
+
if (result.vars.length === 0) {
|
|
533
|
+
output.info("No environment variables set.");
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
for (const name of result.vars) {
|
|
537
|
+
console.log(` ${name}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (err) {
|
|
541
|
+
spin.fail("Failed to list env vars");
|
|
542
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
543
|
+
process.exit(1);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* bankr x402 env unset KEY
|
|
548
|
+
*/
|
|
549
|
+
export async function x402EnvUnsetCommand(key) {
|
|
550
|
+
const spin = output.spinner(`Removing ${key}...`);
|
|
551
|
+
try {
|
|
552
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/env/${key}`, {
|
|
553
|
+
method: "DELETE",
|
|
554
|
+
headers: authHeaders(),
|
|
555
|
+
});
|
|
556
|
+
await handleResponse(res);
|
|
557
|
+
spin.succeed(`Removed ${key}`);
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
spin.fail(`Failed to remove ${key}`);
|
|
561
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
562
|
+
process.exit(1);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* bankr x402 search <query> — Search the x402 service marketplace
|
|
567
|
+
*
|
|
568
|
+
* Public — no auth required. Uses vector search + keyword matching
|
|
569
|
+
* to find relevant paid API services.
|
|
570
|
+
*/
|
|
571
|
+
export async function x402SearchCommand(queryParts) {
|
|
572
|
+
const query = queryParts.join(" ").trim();
|
|
573
|
+
if (!query) {
|
|
574
|
+
output.error("Usage: bankr x402 search <query>");
|
|
575
|
+
process.exit(1);
|
|
576
|
+
}
|
|
577
|
+
const spin = output.spinner("Searching services...");
|
|
578
|
+
try {
|
|
579
|
+
const params = new URLSearchParams({ q: query, limit: "10" });
|
|
580
|
+
const res = await fetch(`${getApiUrl()}/x402/endpoints/discover?${params}`);
|
|
581
|
+
const result = await handleResponse(res);
|
|
582
|
+
spin.stop();
|
|
583
|
+
if (result.services.length === 0) {
|
|
584
|
+
output.info(`No services found for "${query}"`);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
console.log();
|
|
588
|
+
output.dim(` Found ${result.services.length} service(s) for "${query}"`);
|
|
589
|
+
console.log();
|
|
590
|
+
for (const svc of result.services) {
|
|
591
|
+
const route = svc.routes[0];
|
|
592
|
+
const price = route ? `$${route.price} ${route.currency}` : "—";
|
|
593
|
+
const methods = route?.methods?.filter((m) => m !== "*").join(", ") || "ANY";
|
|
594
|
+
const score = svc.score
|
|
595
|
+
? ` ${output.fmt.dim(`${(svc.score * 100).toFixed(0)}% match`)}`
|
|
596
|
+
: "";
|
|
597
|
+
console.log(` ${output.fmt.brand(svc.name)}${score}`);
|
|
598
|
+
if (svc.description) {
|
|
599
|
+
output.dim(` ${svc.description}`);
|
|
600
|
+
}
|
|
601
|
+
const url = svc.url ?? `https://x402.bankr.bot/${svc.slug}`;
|
|
602
|
+
console.log(` ${output.fmt.dim("Method:")} ${methods} ${output.fmt.dim("Price:")} ${price} ${output.fmt.dim("Network:")} ${route?.network ?? "base"}`);
|
|
603
|
+
output.dim(` ${url}`);
|
|
604
|
+
// Show schema if available
|
|
605
|
+
const qp = route?.schema?.queryParams ??
|
|
606
|
+
(methods === "GET" ? route?.schema?.input : undefined);
|
|
607
|
+
const body = route?.schema?.body ??
|
|
608
|
+
(methods !== "GET" ? route?.schema?.input : undefined);
|
|
609
|
+
if (qp) {
|
|
610
|
+
const fields = Object.entries(qp)
|
|
611
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
612
|
+
.join("&");
|
|
613
|
+
output.dim(` ${output.fmt.dim("Params:")} ?${fields}`);
|
|
614
|
+
}
|
|
615
|
+
if (body) {
|
|
616
|
+
const fields = Object.entries(body)
|
|
617
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
618
|
+
.join(", ");
|
|
619
|
+
output.dim(` ${output.fmt.dim("Body:")} { ${fields} }`);
|
|
620
|
+
}
|
|
621
|
+
if (route?.schema?.output) {
|
|
622
|
+
const fields = Object.entries(route.schema.output)
|
|
623
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
624
|
+
.join(", ");
|
|
625
|
+
output.dim(` ${output.fmt.dim("Returns:")} { ${fields} }`);
|
|
626
|
+
}
|
|
627
|
+
console.log();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
catch (err) {
|
|
631
|
+
spin.fail("Search failed");
|
|
632
|
+
output.error(err instanceof Error ? err.message : String(err));
|
|
633
|
+
process.exit(1);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
//# sourceMappingURL=x402.js.map
|
package/dist/lib/chains.js
CHANGED
|
@@ -5,6 +5,7 @@ export const CHAIN_LABELS = {
|
|
|
5
5
|
unichain: "Unichain",
|
|
6
6
|
worldchain: "World Chain",
|
|
7
7
|
arbitrum: "Arbitrum",
|
|
8
|
+
bnb: "BNB Chain",
|
|
8
9
|
solana: "Solana",
|
|
9
10
|
};
|
|
10
11
|
export const VALID_CHAINS = new Set([
|
|
@@ -14,6 +15,7 @@ export const VALID_CHAINS = new Set([
|
|
|
14
15
|
"unichain",
|
|
15
16
|
"worldchain",
|
|
16
17
|
"arbitrum",
|
|
18
|
+
"bnb",
|
|
17
19
|
"solana",
|
|
18
20
|
]);
|
|
19
21
|
export const CHAIN_IDS = {
|
|
@@ -23,6 +25,7 @@ export const CHAIN_IDS = {
|
|
|
23
25
|
unichain: 130,
|
|
24
26
|
worldchain: 480,
|
|
25
27
|
arbitrum: 42161,
|
|
28
|
+
bnb: 56,
|
|
26
29
|
};
|
|
27
30
|
export const NATIVE_SYMBOLS = {
|
|
28
31
|
base: "ETH",
|
|
@@ -31,5 +34,6 @@ export const NATIVE_SYMBOLS = {
|
|
|
31
34
|
worldchain: "ETH",
|
|
32
35
|
arbitrum: "ETH",
|
|
33
36
|
polygon: "POL",
|
|
37
|
+
bnb: "BNB",
|
|
34
38
|
};
|
|
35
39
|
//# sourceMappingURL=chains.js.map
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export declare const fmt: {
|
|
|
4
4
|
readonly brand: import("chalk").ChalkInstance;
|
|
5
5
|
readonly brandBold: import("chalk").ChalkInstance;
|
|
6
6
|
readonly dim: import("chalk").ChalkInstance;
|
|
7
|
+
readonly success: import("chalk").ChalkInstance;
|
|
8
|
+
readonly warn: import("chalk").ChalkInstance;
|
|
7
9
|
};
|
|
8
10
|
export declare const bankrTheme: {
|
|
9
11
|
prefix: string;
|
package/dist/lib/output.js
CHANGED