npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yuuko1410/feishu-bitable

v0.0.5

Published

基于 Bun + TypeScript + 飞书官方 SDK 的多维表格操作库

Downloads

48

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

导出内容

主导出:

  • Bitable
  • FeishuOAuthClient
  • FeishuBitableError
  • AppType
  • Domain
  • LoggerLevel

类型导出:

  • BitableConstructorOptions
  • FeishuOAuthConstructorOptions
  • BuildOAuthLoginUrlOptions
  • OAuthTokenInfo
  • OAuthUserInfo
  • OAuthCallbackResult
  • FetchAllRecordsOptions
  • BatchOperationOptions
  • UpdateRecordsOptions
  • UploadFileOptions
  • BitableInsertRecord
  • BitableUpdateRecord
  • BitableRecord
  • BitableRecordFields
  • BitableFieldValue
  • BitableFilterCondition
  • BitableFilterGroup
  • BitableSort
  • BitableBatchUpdatePayload
  • BitableBatchUpdateResponse
  • MediaParentType
  • UploadableFile

创建客户端

方式一:对象式构造

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_ID
  • FEISHU_APP_SECRET
  • FEISHU_APP_TOKEN
  • FEISHU_OAUTH_REDIRECT_URI(OAuth 登录回调地址)

构造参数说明

BitableConstructorOptions 支持:

  • appId:飞书应用 app_id
  • appSecret:飞书应用 app_secret
  • defaultAppToken:默认多维表格 app_token
  • appType:飞书 SDK AppType
  • domain:飞书 SDK Domain
  • maxRetries:失败最大重试次数,默认 5
  • retryDelayMs:重试基础延迟,默认 1000
  • defaultConcurrency:默认并发数,默认 1
  • sdkClient:可注入已创建的官方 SDK client,便于测试或复用

FeishuOAuthConstructorOptions 支持:

  • appId:飞书应用 app_id
  • appSecret:飞书应用 app_secret
  • redirectUri:OAuth 回调地址
  • domain:飞书 SDK Domain
  • sdkClient:可注入官方 SDK client
  • logger:可注入日志器;传 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 字符串
  • Buffer
  • Uint8Array
  • ArrayBuffer
  • Blob
  • Bun.file() 返回对象

功能:

  • 自动识别文件输入类型
  • 自动转 Buffer
  • 未传 fileName 时尝试推断文件名
  • 小于等于 20MB 走 uploadAll
  • 大于 20MB 自动走官方分片上传:
    • uploadPrepare
    • uploadPart
    • uploadFinish
  • 自动重试

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.user

H5 登录最简接入

前端按钮跳转:

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 控制并发执行数量。

自动重试

以下接口在失败时会自动重试:

  • insertList
  • batchUpdateRecords
  • updateRecords
  • deleteList
  • uploadFile
  • downloadFile

默认配置:

  • 最大重试次数 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