@secret-momo/cf-bridge
v0.1.0
Published
TypeScript SDK for the cf-bridge Cloudflare Worker
Maintainers
Readme
@secret-momo/cf-bridge
这是 cf-bridge Worker 的 TypeScript SDK,用于访问 D1、R2 和 KV。
SDK 运行时需要 Node.js 20.3 或更高版本;仓库开发和测试使用 Node.js 26.12.1。
这是 SDK 选择的运行时支持范围,并非 AbortSignal.any 最早可用版本的声明。Node.js 18.17 虽已包含该 API,SDK 不承诺 Node.js 18 的兼容性。
安装
npm install @secret-momo/cf-bridge创建客户端
import { createBridgeClient } from '@secret-momo/cf-bridge';
const bridge = createBridgeClient({
baseUrl: 'https://cf-bridge.binarykang.workers.dev',
apiToken: process.env.CF_BRIDGE_API_TOKEN!,
timeoutMs: 30_000,
});apiToken 会作为每次请求的 x-api-token 请求头发送。请将令牌保存在服务端环境中,不要放进浏览器代码。
SDK 拒绝所有 HTTP 重定向(包括同源重定向),请将 baseUrl 配置为最终接口地址;注入的自定义 fetch 也需要遵守 redirect: 'error' 选项。
请求默认在等待响应头超过 30 秒时取消;可通过 timeoutMs 调整,设为 0 则关闭。该计时包括上传请求体和等待服务端处理的时间;收到响应头后会清除计时器,后续下载或 JSON 响应体读取不受此超时限制。上传大对象或执行较慢的批量 SQL 时,请按需调整。
客户端的 signal 可统一取消请求,每个方法的最后一个参数也接受 { signal };两者均可中断后续响应体读取。传入依赖 this 的自定义 fetch 方法时,请先绑定所属对象,例如 fetch: api.fetch.bind(api)。
SDK 默认不为响应体读取设置截止时间。若需要限制包含下载在内的整个请求,请显式传入有截止时间的 signal;以下信号从创建起 5 分钟后取消,响应头仍受客户端 timeoutMs 约束:
const download = await bridge.r2.get('big.bin', {
signal: AbortSignal.timeout(5 * 60_000),
});D1
default、v2ex 和 nexus 是可选的数据库名称。使用 execute 执行单条建表、修改表或写入语句,使用 query 获取查询结果;动态值通过 params 绑定。
await bridge.d1.execute('default', {
sql: 'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, text TEXT)',
});
await bridge.d1.execute('default', {
sql: 'INSERT INTO notes (text) VALUES (?)',
params: ['你好'],
});
const { results, meta } = await bridge.d1.query<{ id: number; text: string }>('default', {
sql: 'SELECT id, text FROM notes WHERE text = ?',
params: ['你好'],
});多条语句使用 batch。同一批次中的语句会按顺序在一个事务中执行,失败时回滚。
布尔参数写入 D1 时保存为整数 1 或 0,读取时返回数字。当前网关不支持通过 JSON 参数写入 BLOB。执行语句的 results 字段可能为 null;查询方法的 results 始终是数组。
const batchResults = await bridge.d1.batch('v2ex', [
{ sql: 'CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)' },
{ sql: 'INSERT INTO items (name) VALUES (?)', params: ['示例'] },
]);R2
put 直接上传二进制内容;第三个参数可设置对象的内容类型。get 返回标准 Response,可以读取响应头并按需消费字节流。
put 当前只写入对象内容和 Content-Type,不写入自定义元数据。list({ include: ['customMetadata'] }) 可读取同一存储桶中已有的自定义元数据,例如由其他工具写入的元数据。
await bridge.r2.put('docs/hello.txt', new Blob(['你好']), 'text/plain');
const response = await bridge.r2.get('docs/hello.txt');
const text = await response.text();
const contentType = response.headers.get('content-type');
const page = await bridge.r2.list({ prefix: 'docs/', limit: 100 });
const folders = await bridge.r2.list({
prefix: 'docs/',
delimiter: '/',
include: ['httpMetadata'],
});
const nextPage = page.cursor
? await bridge.r2.list({ prefix: 'docs/', cursor: page.cursor, limit: 100 })
: null;
await bridge.r2.delete('docs/hello.txt');KV
KV 存储字符串。若要保存对象,请自行进行 JSON 序列化和解析。写入时可指定过期秒数 expirationTtl 和 JSON 元数据。KV 采用最终一致性,不适合依赖即时读取结果的协调逻辑。
await bridge.kv.put('settings:theme', JSON.stringify({ theme: 'dark' }), {
expirationTtl: 3600,
metadata: { owner: 'app' },
});
const entry = await bridge.kv.get('settings:theme');
const settings = JSON.parse(entry.value);
const metadata = entry.metadata;
const page = await bridge.kv.list({ prefix: 'settings:', limit: 100 });
const nextPage = page.cursor
? await bridge.kv.list({ prefix: 'settings:', cursor: page.cursor, limit: 100 })
: null;
await bridge.kv.delete('settings:theme');错误处理
除成功的 R2 下载外,SDK 会取出统一响应中的 data 并返回。请求失败时抛出 BridgeError,其中包含 HTTP 状态码 status、业务码 code 和错误信息 message。
import { BridgeError } from '@secret-momo/cf-bridge';
try {
await bridge.kv.get('missing');
} catch (error) {
if (error instanceof BridgeError && error.status === 404) {
// 键不存在
}
}