@bankr/cli 0.1.3 → 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.
@@ -0,0 +1,60 @@
1
+ import { searchTokens } from "../lib/api.js";
2
+ import * as output from "../lib/output.js";
3
+ export async function tokensSearchCommand(query, opts) {
4
+ const spin = output.spinner(`Searching tokens for "${query}"...`);
5
+ try {
6
+ const chainId = opts.chain ? Number(opts.chain) : undefined;
7
+ const res = await searchTokens(query, chainId);
8
+ spin.succeed(`Found ${res.tokens.length} result(s)`);
9
+ if (res.tokens.length === 0) {
10
+ output.info("No tokens found. Try a different search query.");
11
+ return;
12
+ }
13
+ console.log();
14
+ for (const token of res.tokens) {
15
+ const price = token.priceUsd
16
+ ? `$${token.priceUsd.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}`
17
+ : output.fmt.dim("n/a");
18
+ console.log(` ${output.fmt.brandBold(`${token.symbol}`)} ${output.fmt.dim(token.name)}`);
19
+ console.log(` Address: ${token.address}`);
20
+ console.log(` Price: ${price}`);
21
+ console.log();
22
+ }
23
+ }
24
+ catch (err) {
25
+ spin.fail(`Search failed: ${err.message}`);
26
+ process.exit(1);
27
+ }
28
+ }
29
+ export async function tokensInfoCommand(address, opts) {
30
+ const spin = output.spinner(`Fetching token info for ${address}...`);
31
+ try {
32
+ const chainId = opts.chain ? Number(opts.chain) : undefined;
33
+ const res = await searchTokens(address, chainId);
34
+ spin.succeed("Token info loaded");
35
+ // Match by the requested address (search returns all tokens from matching pools)
36
+ const addressLower = address.toLowerCase();
37
+ const token = res.tokens.find((t) => t.address.toLowerCase() === addressLower) ??
38
+ res.tokens[0];
39
+ if (!token) {
40
+ output.error("Token not found. Check the address and try again.");
41
+ process.exit(1);
42
+ }
43
+ console.log();
44
+ output.label("Name", token.name);
45
+ output.label("Symbol", token.symbol);
46
+ output.label("Address", token.address);
47
+ output.label("Decimals", String(token.decimals));
48
+ if (token.priceUsd) {
49
+ output.label("Price", `$${token.priceUsd.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}`);
50
+ }
51
+ if (token.logoURI) {
52
+ output.label("Logo", token.logoURI);
53
+ }
54
+ }
55
+ catch (err) {
56
+ spin.fail(`Failed to fetch token info: ${err.message}`);
57
+ process.exit(1);
58
+ }
59
+ }
60
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1,8 @@
1
+ export declare function transferCommand(opts: {
2
+ to: string;
3
+ amount: string;
4
+ token?: string;
5
+ native?: boolean;
6
+ chain?: string;
7
+ }): Promise<void>;
8
+ //# sourceMappingURL=transfer.d.ts.map
@@ -0,0 +1,80 @@
1
+ import { transfer, searchTokens } from "../lib/api.js";
2
+ import * as output from "../lib/output.js";
3
+ import { NATIVE_SYMBOLS, CHAIN_IDS } from "../lib/chains.js";
4
+ import { isAddress } from "viem";
5
+ /**
6
+ * Resolve a token symbol or address to a contract address.
7
+ * If it's already a valid address, return as-is. Otherwise search by symbol.
8
+ */
9
+ async function resolveToken(tokenInput, chain) {
10
+ if (isAddress(tokenInput)) {
11
+ return { address: tokenInput, symbol: tokenInput };
12
+ }
13
+ const chainId = CHAIN_IDS[chain];
14
+ const res = await searchTokens(tokenInput, chainId);
15
+ // Exact symbol match (case-insensitive) to avoid resolving to wrong token
16
+ const inputUpper = tokenInput.toUpperCase();
17
+ const exactMatch = res.tokens.find((t) => t.symbol.toUpperCase() === inputUpper);
18
+ if (!exactMatch) {
19
+ const available = res.tokens
20
+ .slice(0, 5)
21
+ .map((t) => `${t.symbol} (${t.address})`)
22
+ .join(", ");
23
+ throw new Error(`No exact match for "${tokenInput}" on ${chain}. Did you mean: ${available || "no results"}`);
24
+ }
25
+ return { address: exactMatch.address, symbol: exactMatch.symbol };
26
+ }
27
+ export async function transferCommand(opts) {
28
+ const isNative = opts.native ?? false;
29
+ const chain = opts.chain ?? "base";
30
+ if (!isNative && !opts.token) {
31
+ output.error("Token required for ERC20 transfers. Use --token <symbol or address> or --native.");
32
+ process.exit(1);
33
+ }
34
+ let tokenAddress;
35
+ let tokenLabel;
36
+ if (isNative) {
37
+ tokenAddress = "0x0000000000000000000000000000000000000000";
38
+ tokenLabel = NATIVE_SYMBOLS[chain] ?? "ETH";
39
+ }
40
+ else {
41
+ const spin = output.spinner(`Resolving token "${opts.token}"...`);
42
+ try {
43
+ const resolved = await resolveToken(opts.token, chain);
44
+ tokenAddress = resolved.address;
45
+ tokenLabel = resolved.symbol;
46
+ if (tokenAddress !== opts.token) {
47
+ spin.succeed(`Resolved ${opts.token} → ${tokenLabel} (${tokenAddress})`);
48
+ }
49
+ else {
50
+ spin.stop();
51
+ }
52
+ }
53
+ catch (err) {
54
+ spin.fail(err.message);
55
+ process.exit(1);
56
+ }
57
+ }
58
+ const chainLabel = chain !== "base" ? ` on ${chain}` : "";
59
+ const spin = output.spinner(`Transferring ${opts.amount} ${tokenLabel} to ${opts.to}${chainLabel}...`);
60
+ try {
61
+ const result = await transfer({
62
+ tokenAddress,
63
+ recipientAddress: opts.to,
64
+ amount: opts.amount,
65
+ isNativeToken: isNative,
66
+ chain,
67
+ });
68
+ if (!result.success) {
69
+ spin.fail(`Transfer failed: ${result.error}`);
70
+ process.exit(1);
71
+ }
72
+ spin.succeed(`Transfer successful`);
73
+ output.label("Tx Hash", result.txHash ?? "unknown");
74
+ }
75
+ catch (err) {
76
+ spin.fail(`Transfer failed: ${err.message}`);
77
+ process.exit(1);
78
+ }
79
+ }
80
+ //# sourceMappingURL=transfer.js.map
@@ -0,0 +1,4 @@
1
+ export declare function updateCommand(opts: {
2
+ check?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1,116 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { execSync } from "node:child_process";
3
+ import * as output from "../lib/output.js";
4
+ const PACKAGE_NAME = "@bankr/cli";
5
+ /**
6
+ * Compare two semver version strings.
7
+ * Returns -1 if a < b, 0 if equal, 1 if a > b.
8
+ */
9
+ function compareSemver(a, b) {
10
+ const partsA = a.split(".").map(Number);
11
+ const partsB = b.split(".").map(Number);
12
+ for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
13
+ const numA = partsA[i] ?? 0;
14
+ const numB = partsB[i] ?? 0;
15
+ if (numA < numB)
16
+ return -1;
17
+ if (numA > numB)
18
+ return 1;
19
+ }
20
+ return 0;
21
+ }
22
+ async function fetchLatestVersion() {
23
+ const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
24
+ signal: AbortSignal.timeout(10000),
25
+ });
26
+ if (!res.ok) {
27
+ throw new Error(`Failed to check for updates (HTTP ${res.status})`);
28
+ }
29
+ const data = (await res.json());
30
+ return data.version;
31
+ }
32
+ function getCurrentVersion() {
33
+ const pkg = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf-8"));
34
+ return pkg.version;
35
+ }
36
+ /**
37
+ * Detect which package manager installed the CLI globally.
38
+ * Falls back to npm if we can't determine.
39
+ */
40
+ function detectPackageManager() {
41
+ try {
42
+ const execPath = process.argv[1] ?? "";
43
+ // Check if running under bun
44
+ if (execPath.includes("/.bun/") || "bun" in process.versions) {
45
+ return "bun";
46
+ }
47
+ // Check if running under pnpm
48
+ if (execPath.includes("/pnpm/") || execPath.includes("/.pnpm/")) {
49
+ return "pnpm";
50
+ }
51
+ // Check if running under yarn
52
+ if (execPath.includes("/yarn/") || execPath.includes("/.yarn/")) {
53
+ return "yarn";
54
+ }
55
+ }
56
+ catch {
57
+ // ignore detection errors
58
+ }
59
+ return "npm";
60
+ }
61
+ function getInstallCommand(pm) {
62
+ switch (pm) {
63
+ case "bun":
64
+ return `bun install -g ${PACKAGE_NAME}@latest`;
65
+ case "pnpm":
66
+ return `pnpm add -g ${PACKAGE_NAME}@latest`;
67
+ case "yarn":
68
+ return `yarn global add ${PACKAGE_NAME}@latest`;
69
+ default:
70
+ return `npm install -g ${PACKAGE_NAME}@latest`;
71
+ }
72
+ }
73
+ export async function updateCommand(opts) {
74
+ const current = getCurrentVersion();
75
+ const spin = output.spinner("Checking for updates...");
76
+ let latest;
77
+ try {
78
+ latest = await fetchLatestVersion();
79
+ }
80
+ catch (err) {
81
+ spin.fail();
82
+ output.error(err.message);
83
+ process.exit(1);
84
+ }
85
+ const cmp = compareSemver(current, latest);
86
+ if (cmp === 0) {
87
+ spin.succeed(`Already on the latest version (${current})`);
88
+ return;
89
+ }
90
+ if (cmp > 0) {
91
+ spin.succeed(`You're ahead of latest (${current} > ${latest}). No update needed.`);
92
+ return;
93
+ }
94
+ spin.succeed(`Update available: ${current} → ${latest}`);
95
+ if (opts.check) {
96
+ return;
97
+ }
98
+ const pm = detectPackageManager();
99
+ const cmd = getInstallCommand(pm);
100
+ output.blank();
101
+ output.info(`Updating via ${pm}...`);
102
+ output.dim(` $ ${cmd}`);
103
+ output.blank();
104
+ try {
105
+ execSync(cmd, { stdio: "inherit" });
106
+ output.blank();
107
+ output.success(`Updated to ${PACKAGE_NAME}@${latest}`);
108
+ }
109
+ catch {
110
+ output.blank();
111
+ output.error("Update failed. Try running manually:");
112
+ output.dim(` $ ${cmd}`);
113
+ process.exit(1);
114
+ }
115
+ }
116
+ //# sourceMappingURL=update.js.map
@@ -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