bankr-dev---client-patterns by bankrbot/claude-plugins
npx skills add https://github.com/bankrbot/claude-plugins --skill 'Bankr Dev - Client Patterns'适用于 Bankr API 项目的可复用客户端代码和通用文件。
所有 Bankr 项目的核心 API 客户端模块:
import "dotenv/config";
const API_URL = process.env.BANKR_API_URL || "https://api.bankr.bot";
const API_KEY = process.env.BANKR_API_KEY;
// ============================================
// 类型定义
// ============================================
export type JobStatus = "pending" | "processing" | "completed" | "failed" | "cancelled";
export interface JobStatusResponse {
success: boolean;
jobId: string;
status: JobStatus;
prompt: string;
response?: string;
transactions?: Transaction[];
richData?: RichData[];
statusUpdates?: StatusUpdate[];
error?: string;
createdAt: string;
startedAt?: string;
completedAt?: string;
cancelledAt?: string;
processingTime?: number;
cancellable?: boolean;
}
export interface StatusUpdate {
message: string;
timestamp: string;
}
// 交易类型
export type Transaction =
| SwapTransaction
| ApprovalTransaction
| TransferErc20Transaction
| TransferEthTransaction
| ConvertEthToWethTransaction
| ConvertWethToEthTransaction
| TransferNftTransaction
| MintManifoldNftTransaction
| MintSeaDropNftTransaction
| BuyNftTransaction
| AvantisTradeTransaction
| SwapCrossChainTransaction
| ManageBankrStakingTransaction;
interface BaseTransactionMetadata {
__ORIGINAL_TX_DATA__: {
chain: string;
humanReadableMessage: string;
inputTokenAddress: string;
inputTokenAmount: string;
inputTokenTicker: string;
outputTokenAddress: string;
outputTokenTicker: string;
receiver: string;
};
transaction: {
chainId: number;
to: string;
data: string;
gas: string;
gasPrice: string;
value: string;
};
}
export interface SwapTransaction {
type: "swap";
metadata: BaseTransactionMetadata & {
approvalRequired?: boolean;
approvalTx?: { to: string; data: string };
permit2?: object;
};
}
export interface ApprovalTransaction {
type: "approval";
metadata: BaseTransactionMetadata;
}
export interface TransferErc20Transaction {
type: "transfer_erc20";
metadata: BaseTransactionMetadata;
}
export interface TransferEthTransaction {
type: "transfer_eth";
metadata: BaseTransactionMetadata;
}
export interface ConvertEthToWethTransaction {
type: "convert_eth_to_weth";
metadata: BaseTransactionMetadata;
}
export interface ConvertWethToEthTransaction {
type: "convert_weth_to_eth";
metadata: BaseTransactionMetadata;
}
export interface TransferNftTransaction {
type: "transfer_nft";
metadata: BaseTransactionMetadata;
}
export interface MintManifoldNftTransaction {
type: "mint_manifold_nft";
metadata: BaseTransactionMetadata;
}
export interface MintSeaDropNftTransaction {
type: "mint_seadrop_nft";
metadata: BaseTransactionMetadata;
}
export interface BuyNftTransaction {
type: "buy_nft";
metadata: BaseTransactionMetadata;
}
export interface AvantisTradeTransaction {
type: "avantisTrade";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value?: string;
};
}
export interface SwapCrossChainTransaction {
type: "swapCrossChain";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value: string;
};
}
export interface ManageBankrStakingTransaction {
type: "manage_bankr_staking";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value?: string;
};
}
// 富数据类型
export type RichData = SocialCard | Chart;
export interface SocialCard {
type: "social-card";
variant: "analysis";
text: string;
}
export interface Chart {
type: "chart";
url: string;
}
// ============================================
// API 函数
// ============================================
export async function submitPrompt(prompt: string): Promise<{ jobId: string }> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set. Get one at https://bankr.bot/api");
}
const response = await fetch(`${API_URL}/agent/prompt`, {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt }),
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error || "Failed to submit prompt");
}
return { jobId: data.jobId };
}
export async function getJobStatus(jobId: string): Promise<JobStatusResponse> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set");
}
const response = await fetch(`${API_URL}/agent/job/${jobId}`, {
headers: { "x-api-key": API_KEY },
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
return response.json();
}
export async function cancelJob(jobId: string): Promise<JobStatusResponse> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set");
}
const response = await fetch(`${API_URL}/agent/job/${jobId}/cancel`, {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
return response.json();
}
export async function waitForCompletion(
jobId: string,
onProgress?: (message: string) => void,
options?: { pollInterval?: number; maxAttempts?: number }
): Promise<JobStatusResponse> {
const pollInterval = options?.pollInterval || 2000;
const maxAttempts = options?.maxAttempts || 150; // 最长 5 分钟
let lastUpdateCount = 0;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const status = await getJobStatus(jobId);
// 报告新的状态更新
if (onProgress && status.statusUpdates) {
for (let i = lastUpdateCount; i < status.statusUpdates.length; i++) {
onProgress(status.statusUpdates[i].message);
}
lastUpdateCount = status.statusUpdates.length;
}
// 检查终止状态
if (["completed", "failed", "cancelled"].includes(status.status)) {
return status;
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
throw new Error("Job timed out after maximum attempts");
}
/**
* 执行 Bankr 提示并等待完成
* 结合提交和轮询的便捷函数
*/
export async function execute(
prompt: string,
onProgress?: (message: string) => void
): Promise<JobStatusResponse> {
const { jobId } = await submitPrompt(prompt);
onProgress?.(`Job submitted: ${jobId}`);
return waitForCompletion(jobId, onProgress);
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
所有 Bankr 项目的基础 package.json:
{
"name": "{project-name}",
"version": "0.1.0",
"description": "{description}",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"dotenv": "^16.3.1"
},
"devDependencies": {
"@types/node": "^20.10.0",
"tsx": "^4.7.0",
"typescript": "^5.3.0"
}
}
根据项目模板添加:
Web 服务 (Express):
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"@types/express": "^4.17.21"
}
Web 服务 (Fastify):
"dependencies": {
"fastify": "^4.25.0"
}
CLI:
"dependencies": {
"commander": "^12.0.0"
}
TypeScript 配置:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
环境变量模板:
# Bankr API 配置
BANKR_API_KEY=bk_your_api_key_here
BANKR_API_URL=https://api.bankr.bot
# 可选:用于上下文的钱包地址
BANKR_WALLET_ADDRESS=0x...
标准忽略模式:
# 依赖项
node_modules/
# 构建输出
dist/
# 环境变量
.env
.env.local
.env.*.local
# 日志
*.log
npm-debug.log*
# IDE
.idea/
.vscode/
*.swp
*.swo
# 操作系统
.DS_Store
Thumbs.db
# 测试
coverage/
import { execute } from "./bankr-client";
const result = await execute("What is the price of ETH?", (msg) => {
console.log("Progress:", msg);
});
console.log(result.response);
import { execute } from "./bankr-client";
try {
const result = await execute("Buy $50 of ETH on Base");
if (result.status === "completed") {
console.log("Success:", result.response);
// 处理交易
if (result.transactions) {
for (const tx of result.transactions) {
console.log(`${tx.type}:`, tx.metadata.__ORIGINAL_TX_DATA__?.humanReadableMessage);
}
}
} else if (result.status === "failed") {
console.error("Failed:", result.error);
}
} catch (error) {
console.error("Error:", error.message);
}
import { submitPrompt, waitForCompletion, cancelJob } from "./bankr-client";
// 提交
const { jobId } = await submitPrompt("Analyze ETH market");
// 设置超时
const timeout = setTimeout(() => {
cancelJob(jobId);
}, 120000);
// 使用自定义选项等待
const result = await waitForCompletion(jobId, console.log, {
pollInterval: 2000,
maxAttempts: 60,
});
clearTimeout(timeout);
请查阅 bankr-api-basics 技能以获取:
每周安装次数
–
仓库
GitHub 星标数
70
首次出现
–
Reusable client code and common files for Bankr API projects.
The core API client module for all Bankr projects:
import "dotenv/config";
const API_URL = process.env.BANKR_API_URL || "https://api.bankr.bot";
const API_KEY = process.env.BANKR_API_KEY;
// ============================================
// Types
// ============================================
export type JobStatus = "pending" | "processing" | "completed" | "failed" | "cancelled";
export interface JobStatusResponse {
success: boolean;
jobId: string;
status: JobStatus;
prompt: string;
response?: string;
transactions?: Transaction[];
richData?: RichData[];
statusUpdates?: StatusUpdate[];
error?: string;
createdAt: string;
startedAt?: string;
completedAt?: string;
cancelledAt?: string;
processingTime?: number;
cancellable?: boolean;
}
export interface StatusUpdate {
message: string;
timestamp: string;
}
// Transaction types
export type Transaction =
| SwapTransaction
| ApprovalTransaction
| TransferErc20Transaction
| TransferEthTransaction
| ConvertEthToWethTransaction
| ConvertWethToEthTransaction
| TransferNftTransaction
| MintManifoldNftTransaction
| MintSeaDropNftTransaction
| BuyNftTransaction
| AvantisTradeTransaction
| SwapCrossChainTransaction
| ManageBankrStakingTransaction;
interface BaseTransactionMetadata {
__ORIGINAL_TX_DATA__: {
chain: string;
humanReadableMessage: string;
inputTokenAddress: string;
inputTokenAmount: string;
inputTokenTicker: string;
outputTokenAddress: string;
outputTokenTicker: string;
receiver: string;
};
transaction: {
chainId: number;
to: string;
data: string;
gas: string;
gasPrice: string;
value: string;
};
}
export interface SwapTransaction {
type: "swap";
metadata: BaseTransactionMetadata & {
approvalRequired?: boolean;
approvalTx?: { to: string; data: string };
permit2?: object;
};
}
export interface ApprovalTransaction {
type: "approval";
metadata: BaseTransactionMetadata;
}
export interface TransferErc20Transaction {
type: "transfer_erc20";
metadata: BaseTransactionMetadata;
}
export interface TransferEthTransaction {
type: "transfer_eth";
metadata: BaseTransactionMetadata;
}
export interface ConvertEthToWethTransaction {
type: "convert_eth_to_weth";
metadata: BaseTransactionMetadata;
}
export interface ConvertWethToEthTransaction {
type: "convert_weth_to_eth";
metadata: BaseTransactionMetadata;
}
export interface TransferNftTransaction {
type: "transfer_nft";
metadata: BaseTransactionMetadata;
}
export interface MintManifoldNftTransaction {
type: "mint_manifold_nft";
metadata: BaseTransactionMetadata;
}
export interface MintSeaDropNftTransaction {
type: "mint_seadrop_nft";
metadata: BaseTransactionMetadata;
}
export interface BuyNftTransaction {
type: "buy_nft";
metadata: BaseTransactionMetadata;
}
export interface AvantisTradeTransaction {
type: "avantisTrade";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value?: string;
};
}
export interface SwapCrossChainTransaction {
type: "swapCrossChain";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value: string;
};
}
export interface ManageBankrStakingTransaction {
type: "manage_bankr_staking";
metadata: {
chainId: number;
description: string;
to: string;
data: string;
value?: string;
};
}
// Rich data types
export type RichData = SocialCard | Chart;
export interface SocialCard {
type: "social-card";
variant: "analysis";
text: string;
}
export interface Chart {
type: "chart";
url: string;
}
// ============================================
// API Functions
// ============================================
export async function submitPrompt(prompt: string): Promise<{ jobId: string }> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set. Get one at https://bankr.bot/api");
}
const response = await fetch(`${API_URL}/agent/prompt`, {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt }),
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error || "Failed to submit prompt");
}
return { jobId: data.jobId };
}
export async function getJobStatus(jobId: string): Promise<JobStatusResponse> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set");
}
const response = await fetch(`${API_URL}/agent/job/${jobId}`, {
headers: { "x-api-key": API_KEY },
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
return response.json();
}
export async function cancelJob(jobId: string): Promise<JobStatusResponse> {
if (!API_KEY) {
throw new Error("BANKR_API_KEY not set");
}
const response = await fetch(`${API_URL}/agent/job/${jobId}/cancel`, {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
});
if (!response.ok) {
const text = await response.text();
throw new Error(`API error ${response.status}: ${text}`);
}
return response.json();
}
export async function waitForCompletion(
jobId: string,
onProgress?: (message: string) => void,
options?: { pollInterval?: number; maxAttempts?: number }
): Promise<JobStatusResponse> {
const pollInterval = options?.pollInterval || 2000;
const maxAttempts = options?.maxAttempts || 150; // 5 minutes max
let lastUpdateCount = 0;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const status = await getJobStatus(jobId);
// Report new status updates
if (onProgress && status.statusUpdates) {
for (let i = lastUpdateCount; i < status.statusUpdates.length; i++) {
onProgress(status.statusUpdates[i].message);
}
lastUpdateCount = status.statusUpdates.length;
}
// Check for terminal states
if (["completed", "failed", "cancelled"].includes(status.status)) {
return status;
}
await new Promise((resolve) => setTimeout(resolve, pollInterval));
}
throw new Error("Job timed out after maximum attempts");
}
/**
* Execute a Bankr prompt and wait for completion
* Convenience function that combines submit + poll
*/
export async function execute(
prompt: string,
onProgress?: (message: string) => void
): Promise<JobStatusResponse> {
const { jobId } = await submitPrompt(prompt);
onProgress?.(`Job submitted: ${jobId}`);
return waitForCompletion(jobId, onProgress);
}
Base package.json for all Bankr projects:
{
"name": "{project-name}",
"version": "0.1.0",
"description": "{description}",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"dotenv": "^16.3.1"
},
"devDependencies": {
"@types/node": "^20.10.0",
"tsx": "^4.7.0",
"typescript": "^5.3.0"
}
}
Add based on project template:
Web Service (Express):
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"@types/express": "^4.17.21"
}
Web Service (Fastify):
"dependencies": {
"fastify": "^4.25.0"
}
CLI:
"dependencies": {
"commander": "^12.0.0"
}
TypeScript configuration:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Environment variables template:
# Bankr API Configuration
BANKR_API_KEY=bk_your_api_key_here
BANKR_API_URL=https://api.bankr.bot
# Optional: Wallet address for context
BANKR_WALLET_ADDRESS=0x...
Standard ignore patterns:
# Dependencies
node_modules/
# Build output
dist/
# Environment
.env
.env.local
.env.*.local
# Logs
*.log
npm-debug.log*
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Testing
coverage/
import { execute } from "./bankr-client";
const result = await execute("What is the price of ETH?", (msg) => {
console.log("Progress:", msg);
});
console.log(result.response);
import { execute } from "./bankr-client";
try {
const result = await execute("Buy $50 of ETH on Base");
if (result.status === "completed") {
console.log("Success:", result.response);
// Handle transactions
if (result.transactions) {
for (const tx of result.transactions) {
console.log(`${tx.type}:`, tx.metadata.__ORIGINAL_TX_DATA__?.humanReadableMessage);
}
}
} else if (result.status === "failed") {
console.error("Failed:", result.error);
}
} catch (error) {
console.error("Error:", error.message);
}
import { submitPrompt, waitForCompletion, cancelJob } from "./bankr-client";
// Submit
const { jobId } = await submitPrompt("Analyze ETH market");
// Set up timeout
const timeout = setTimeout(() => {
cancelJob(jobId);
}, 120000);
// Wait with custom options
const result = await waitForCompletion(jobId, console.log, {
pollInterval: 2000,
maxAttempts: 60,
});
clearTimeout(timeout);
Consult the bankr-api-basics skill for:
Weekly Installs
–
Repository
GitHub Stars
70
First Seen
–
飞书OpenAPI Explorer:探索和调用未封装的飞书原生API接口
19,800 周安装