@yuuko1410/feishu-bitable
v0.0.5
Published
基于 Bun + TypeScript + 飞书官方 SDK 的多维表格操作库
Downloads
48
Maintainers
Readme
@yuuko1410/feishu-bitable
基于 Bun + TypeScript + 飞书官方 @larksuiteoapi/node-sdk 的多维表格操作库。
功能总览
- 使用 Bun 作为包管理与构建工具
- 使用 TypeScript 作为源码语言
- 底层基于飞书官方 Node SDK
- 支持 ESM、CommonJS、类型声明三种发布产物
- 支持对象式构造和环境变量构造
- 支持自动分页获取全部记录
- 支持批量新增记录
- 支持官方批量更新 API 的 1:1 封装
- 支持面向数组的批量更新封装
- 支持批量删除记录
- 支持小文件直接上传
- 支持大文件自动切换分片上传
- 支持文件下载
- 支持 H5 OAuth 登录(生成登录链接、code 换 token、获取用户信息)
- 支持字段值归一化
- 支持批量请求自动分片
- 支持并发控制
- 支持失败自动重试
- 导出完整类型和错误类型
项目结构
packages/feishu-bitable/
├── package.json
├── README.md
├── tsconfig.json
├── tsconfig.build.json
├── src/
│ ├── client.ts
│ ├── auth.ts
│ ├── errors.ts
│ ├── index.ts
│ ├── types.ts
│ └── utils.ts
├── test/
│ ├── auth.test.ts
│ └── bitable.test.ts
└── lib/ # bun run build 后生成安装依赖
bun install构建与开发
bun run check
bun test
bun run build构建完成后输出:
lib/index.js:ESM 入口lib/index.cjs:CommonJS 入口lib/index.d.ts:类型声明入口
安装到业务项目
如果作为 npm 包使用:
bun add @yuuko1410/feishu-bitable或:
npm install @yuuko1410/feishu-bitable导出内容
主导出:
BitableFeishuOAuthClientFeishuBitableErrorAppTypeDomainLoggerLevel
类型导出:
BitableConstructorOptionsFeishuOAuthConstructorOptionsBuildOAuthLoginUrlOptionsOAuthTokenInfoOAuthUserInfoOAuthCallbackResultFetchAllRecordsOptionsBatchOperationOptionsUpdateRecordsOptionsUploadFileOptionsBitableInsertRecordBitableUpdateRecordBitableRecordBitableRecordFieldsBitableFieldValueBitableFilterConditionBitableFilterGroupBitableSortBitableBatchUpdatePayloadBitableBatchUpdateResponseMediaParentTypeUploadableFile
创建客户端
方式一:对象式构造
import { Bitable } from "@yuuko1410/feishu-bitable";
const bitable = new Bitable({
appId: process.env.FEISHU_APP_ID!,
appSecret: process.env.FEISHU_APP_SECRET!,
defaultAppToken: process.env.FEISHU_APP_TOKEN,
});方式二:兼容旧式参数构造
const bitable = new Bitable(
process.env.FEISHU_APP_TOKEN,
process.env.FEISHU_APP_ID,
process.env.FEISHU_APP_SECRET,
);方式三:从环境变量创建
const bitable = Bitable.fromEnv();默认读取的环境变量:
FEISHU_APP_IDFEISHU_APP_SECRETFEISHU_APP_TOKENFEISHU_OAUTH_REDIRECT_URI(OAuth 登录回调地址)
构造参数说明
BitableConstructorOptions 支持:
appId:飞书应用app_idappSecret:飞书应用app_secretdefaultAppToken:默认多维表格app_tokenappType:飞书 SDKAppTypedomain:飞书 SDKDomainmaxRetries:失败最大重试次数,默认5retryDelayMs:重试基础延迟,默认1000defaultConcurrency:默认并发数,默认1sdkClient:可注入已创建的官方 SDK client,便于测试或复用
FeishuOAuthConstructorOptions 支持:
appId:飞书应用app_idappSecret:飞书应用app_secretredirectUri:OAuth 回调地址domain:飞书 SDKDomainsdkClient:可注入官方 SDK clientlogger:可注入日志器;传null可禁用日志
公开 API
1. fetchAllRecords
自动分页获取某个数据表的全部记录。
const records = await bitable.fetchAllRecords("table_id", {
viewId: "vew_xxx",
fieldNames: ["名称", "状态"],
pageSize: 500,
normalizeFields: true,
automaticFields: false,
});功能:
- 自动处理分页
- 默认单页最多 500 条
- 支持视图筛选
- 支持字段筛选
- 支持排序条件
- 支持飞书过滤条件
- 支持返回字段自动归一化
返回值:
Promise<BitableRecord[]>
2. insertList
批量新增记录,自动按飞书限制分片。
await bitable.insertList("table_id", [
{ 名称: "订单 A", 金额: 100 },
{ 名称: "订单 B", 金额: 200 },
], {
concurrency: 2,
chunkSize: 500,
});功能:
- 自动分片
- 支持并发
- 自动重试
- 单批最大 500 条
3. batchUpdateRecords
对飞书官方 appTableRecord.batchUpdate 的直接封装,适合你已经自己组好了官方 payload 的场景。
await bitable.batchUpdateRecords({
path: {
app_token: "app_token",
table_id: "table_id",
},
data: {
records: [
{
record_id: "recxxx",
fields: {
状态: "已完成",
},
},
{
record_id: "recyyy",
fields: {
状态: "处理中",
},
},
],
},
});功能:
- 官方 payload 原样透传
- 自动重试
- 自动校验飞书错误码
返回值:
Promise<BitableBatchUpdateResponse>
4. updateRecords
面向业务数组的批量更新封装,内部会转成官方 batchUpdate payload。
await bitable.updateRecords("table_id", [
{ record_id: "recxxx", 状态: "已完成" },
{ record_id: "recyyy", 状态: "处理中" },
], {
appToken: "app_token",
concurrency: 2,
chunkSize: 500,
userIdType: "open_id",
ignoreConsistencyCheck: false,
});功能:
- 自动把
record_id从字段中拆出 - 自动转换成官方
batchUpdate请求结构 - 自动分片
- 支持并发
- 自动重试
- 支持
userIdType - 支持
ignoreConsistencyCheck
返回值:
Promise<BitableBatchUpdateResponse[]>
5. deleteList
批量删除记录。
await bitable.deleteList("table_id", ["rec_1", "rec_2"], {
concurrency: 2,
chunkSize: 500,
});功能:
- 自动分片
- 支持并发
- 自动重试
- 单批最大 500 条
6. uploadFile
上传文件到飞书文档体系。
const result = await bitable.uploadFile({
parentType: "bitable_file",
parentNode: "tbl_xxx",
fileName: "demo.png",
file: Bun.file("./demo.png"),
extra: "{}",
});支持的文件输入:
- base64 字符串
- data URL 字符串
BufferUint8ArrayArrayBufferBlobBun.file()返回对象
功能:
- 自动识别文件输入类型
- 自动转
Buffer - 未传
fileName时尝试推断文件名 - 小于等于 20MB 走
uploadAll - 大于 20MB 自动走官方分片上传:
uploadPrepareuploadPartuploadFinish
- 自动重试
7. downloadFile
下载飞书素材并返回 Buffer。
const buffer = await bitable.downloadFile("file_token");支持:
- 传入
extra - 自动把可读流转为
Buffer
8. downLoadFile
这是 downloadFile 的兼容别名。
const buffer = await bitable.downLoadFile("file_token");9. FeishuOAuthClient.buildLoginUrl
生成 H5 飞书登录链接。
import { FeishuOAuthClient } from "@yuuko1410/feishu-bitable";
const oauth = FeishuOAuthClient.fromEnv();
const loginUrl = oauth.buildLoginUrl({
state: "csrf_state_123",
scope: ["contact:user.base:readonly"],
});10. FeishuOAuthClient.exchangeCodeForUserToken
后端使用回调 code 换取 user_access_token。
const token = await oauth.exchangeCodeForUserToken(code);11. FeishuOAuthClient.getUserInfo
使用 user_access_token 拉取飞书用户信息。
const user = await oauth.getUserInfo(token.access_token);12. FeishuOAuthClient.handleCallback
最简回调处理:一键完成 code -> token -> user。
const result = await oauth.handleCallback(code);
// result.token
// result.userH5 登录最简接入
前端按钮跳转:
window.location.href = "/api/auth/feishu/login";后端示例(Express/SvelteKit 思路一致):
import { FeishuOAuthClient } from "@yuuko1410/feishu-bitable";
const oauth = FeishuOAuthClient.fromEnv();
export async function loginHandler() {
const state = crypto.randomUUID();
const loginUrl = oauth.buildLoginUrl({
state,
scope: ["contact:user.base:readonly"],
});
return Response.redirect(loginUrl, 302);
}
export async function callbackHandler(code: string) {
const { token, user } = await oauth.handleCallback(code);
// 这里创建你自己的业务登录态(session/JWT)
// 不建议把 user_access_token 暴露给前端
return {
uid: user.open_id ?? user.user_id,
name: user.name,
tokenType: token.token_type,
};
}自动行为说明
自动分页
fetchAllRecords 内部使用官方迭代器接口自动拉取全部页。
自动分片
批量增删改会按飞书上限自动分片,默认和最大都是 500。
自动并发
批量接口支持通过 concurrency 控制并发执行数量。
自动重试
以下接口在失败时会自动重试:
insertListbatchUpdateRecordsupdateRecordsdeleteListuploadFiledownloadFile
默认配置:
- 最大重试次数
5 - 重试延迟基数
1000ms - 每次重试按尝试次数递增延迟
字段归一化
fetchAllRecords 默认会把飞书返回字段结构转成更易用的值:
- 单元素文本数组提取为文本
type === 1的富文本拼接为字符串type === 2 | 3 | 1005的数组值转成逗号连接字符串- 其他复杂字段保持原值
错误处理
库内统一抛出 FeishuBitableError:
import { FeishuBitableError } from "@yuuko1410/feishu-bitable";
try {
await bitable.updateRecords("table_id", records);
} catch (error) {
if (error instanceof FeishuBitableError) {
console.error(error.message);
console.error(error.code);
console.error(error.details);
}
}错误来源包括:
- 凭证缺失
appToken缺失- 飞书接口返回非
0错误码 - 上传预处理信息不完整
- 文件输入类型不支持
- 多次重试后最终失败
一个完整示例
import { Bitable } from "@yuuko1410/feishu-bitable";
const bitable = Bitable.fromEnv();
const records = await bitable.fetchAllRecords("table_id", {
fieldNames: ["名称", "状态"],
});
await bitable.insertList("table_id", [
{ 名称: "新记录", 状态: "待处理" },
]);
await bitable.updateRecords("table_id", [
{ record_id: "recxxx", 状态: "已完成" },
]);
await bitable.deleteList("table_id", ["recyyy"]);测试覆盖的重构能力
当前测试已覆盖:
- 记录归一化
- 数组式批量更新到官方 payload 的转换
- 官方批量更新 payload 透传
- 文件下载
- OAuth 登录链接生成
- OAuth code 换 token
- OAuth 回调获取用户信息
- 凭证缺失报错
发布
bun run build
npm publish --access public发布时包含:
lib/README.md
