Corsair 集成指南:从零到生产环境的用户应用连接方案
导读
Corsair 是当前仓库(corsa/corsair)中的核心 TypeScript 集成框架,它帮助你的应用通过 OAuth 或 API Key 连接 GitHub、Slack、Linear、Stripe、Gmail 等数百个外部服务,并把连接后的凭证加密存储在你自己的数据库中,供 Agent、UI、Webhook、知识库等消费。本文以仓库内 skills/corsair/SKILL.md 为骨架,完整覆盖从规划、安装、配置、路由挂载、账户连接、API 调用、Webhook、工作流、MCP 接入、权限审批到生产发布的端到端流程,并结合 packages/corsair 源码说明底层实现原理,读完后你可以把任意 TypeScript 应用(Next.js、Express、Hono、SvelteKit、Astro、Nuxt、Remix 乃至 Bun/Deno/Workers)接入 Corsair 并跑通真实数据调用。
一、Corsair 的核心模型与两个贯穿原则
1.1 先理解四个术语
在整个集成过程中,你会反复遇到四个术语,它们构成了 Corsair 的领域模型:
- tenant(租户):应用的某个最终用户。多租户模式下(
multiTenancy: true),所有连接、凭证、数据都按租户隔离。 - plugin(插件):一个外部服务,如
github、slack、linear。插件包按@corsair-dev/<service>作用域发布。 - delivery URL(投递地址):Hub 向你的应用回传结果(OAuth token、Webhook、连接状态等)的地址。它不需要写进配置文件——首次请求时自动向 Hub 注册,仪表盘头部的小圆点变绿即表示投递已打通。
- Hub:Corsair 托管的控制面,负责托管 OAuth 授权页、环境管理与密钥发放;它不存储任何凭证数据。
1.2 贯穿始终的两条规则
SKILL.md 明确了两条规则,它们是集成是否成功的关键:
- 动手接线前先读真实文档:仓库根目录的 docs/docs.json 聚合了全部文档索引,其中的 docs/hub/overview.mdx、docs/hub/setup.mdx 等页面描述了 Hub 模式的核心概念,动手前应先通读这些内容。
- 服务跑起来不算完成,真实 API 调用返回数据才算完成。这条规则贯穿全文:连接账户、跑通调用、验证端到端,缺一不可。
1.3 架构前提:Corsair 需要一个服务端
/api/corsair 路由持有签名密钥并接收 Hub 的服务端到服务端投递,因此 Corsair 需要服务端,不能跑在纯客户端 SPA 上。如果你用的是 Angular、Vue 或纯前端 Svelte 且没有后端,需要把该路由挂载到 SSR 服务、Express 或 Hono 上;如果后端不使用 JavaScript,则可以跳过 SDK,改用 Hub REST API(对应源码 packages/corsair/hub/route-handlers.ts)。
二、Phase 1:写代码前的规划
2.1 学习模型
首先阅读文档索引,重点先看介绍与 Hub 页面,建立对数据流(应用 ↔ Hub ↔ 外部服务)的整体认知。
2.2 扫描项目,只问空白
SKILL 建议先探测项目现状,能检测到的直接预填,只对信息缺口提问:
| 检测项 | 信息来源 |
|---|---|
| 框架 | next.config.*、svelte.config.*、nuxt.config.*、astro.config.*、Express/Hono 入口、package.json 依赖 |
| 是否已装 Corsair | 存在 corsair 依赖、已有 /api/corsair 路由、存在 corsair.ts、或已有 CORSAIR_* 环境变量 → 应重配置而非重新脚手架 |
| 包管理器 | lockfile(pnpm-lock.yaml / package-lock.json / yarn.lock) |
| 数据库 | 已有的 DB 句柄或 ORM;否则最快路径是用 better-sqlite3 走 SQLite |
2.3 敲定两个决定整体形态的选择
SKILL 强调这两个问题要用对话式讨论,而不是非黑即白的 yes/no:
- 连接谁的账号? 只是应用自己的工具账号,还是最终用户的账号?用户账号意味着多租户(
multiTenancy: true),这是最常见的情况,不确定时默认倾向多租户。 - 用哪个框架? 它决定了路由的挂载方式(见第五章的适配器表)。
2.4 先确认计划再动代码
在改动任何文件前,先把整体方案(框架、数据库、租户模型、要接的插件)总结出来并征得确认。
三、Phase 2:实施总览
SKILL 给出三条路径的实施决策树:
New / empty app? ── install → corsair.ts → /api/corsair route → keys in .env
→ start server (dot goes green) → connect an account → real API call
Adding to an app? ── detect stack → install → add route → keys → connect the services named
Already wired? ── reconcile corsair.ts → add the new plugins/features → re-check keys
- 全新/空应用:安装 → 写
corsair.ts→ 挂/api/corsair路由 → 配置.env密钥 → 启动服务(圆点变绿)→ 连接账户 → 真实 API 调用。 - 已有应用接入:探测技术栈 → 安装 → 加路由 → 配密钥 → 连接指定服务。
- 已接入再扩展:核对既有
corsair.ts→ 新增插件/功能 → 复查密钥。
四、安装与密钥环境
4.1 安装
npm install corsair @corsair-dev/github
多个服务一次安装:
npm install corsair @corsair-dev/slack @corsair-dev/linear
插件包统一以 @corsair-dev/<service> 作用域命名,完整服务目录可查看 docs/integrations 相关文档 与仓库中各插件包(如 packages/github、packages/slack)。集成哪个服务不确定时应当提问确认,不要凭仓库名猜测。
4.2 生成 KEK(密钥加密密钥)
KEK 是信封加密(envelope encryption)的根密钥:它包裹每个连接独立的 DEK(数据加密密钥),DEK 再加密每条凭证。KEK 一旦丢失,所有已存储的凭证都无法恢复,必须妥善保管:
openssl rand -base64 32
在源码中,KEK 的加解密逻辑集中在 packages/corsair/core/auth/encryption.ts,密钥管理见 packages/corsair/core/auth/key-manager.ts;缺少 KEK 时会抛出 CorsairKekMissingError(定义于 packages/corsair/core/auth/errors/kek-missing.ts),从源码结构看,这是初始化时的第一道守卫。
4.3 获取密钥并写入 .env
Corsair 需要三个东西:开发 API Key、签名密钥(signing secret)和 KEK。API Key 的前缀(ck_dev_ 或 ck_prod_)告诉 SDK 当前处于哪个环境。
最快路径:生成一个带项目名的登录链接,用户用 Google 登录后,工作区和项目自动创建,onboarding 界面直接展示密钥:
https://hub.corsair.dev/login?title=My%20App
偏好仪表盘的话,在 https://hub.corsair.dev/dashboard 创建项目,从 Keys 标签页复制同样的密钥。
CORSAIR_DEV_API_KEY=ck_dev_...
CORSAIR_DEV_SIGNING_SECRET=...
CORSAIR_KEK=...
生产环境改用 CORSAIR_PROD_API_KEY 与 CORSAIR_PROD_SIGNING_SECRET,CORSAIR_KEK 保持一致。绝不记录或提交这些密钥到日志、版本库。
五、编写 corsair.ts 并理解每个配置项
5.1 最小可用配置
import "dotenv/config";
import { createCorsair } from "corsair";
import { github } from "@corsair-dev/github";
export const corsair = createCorsair({
kek: process.env.CORSAIR_KEK!,
database: db, // the app's own DB handle; Corsair persists here, Hub stores nothing
hub: {
projectApiKey: (process.env.CORSAIR_PROD_API_KEY ?? process.env.CORSAIR_DEV_API_KEY)!,
signingSecret: (process.env.CORSAIR_PROD_SIGNING_SECRET ?? process.env.CORSAIR_DEV_SIGNING_SECRET)!,
},
plugins: [github()],
multiTenancy: true, // from the "whose accounts?" choice
});
仓库内的最小示例见 demo/minimal/corsair.ts:它用 slack()、linear()、resend() 三个插件演示了 withTenant 租户隔离与全类型推断的 API/DB 调用。
5.2 字段速查表
| 字段 | 作用 |
|---|---|
kek |
信封密钥。包裹每个连接的 DEK,DEK 加密每条凭证。 |
database |
应用的数据库句柄。Corsair 会创建五张表:corsair_integrations、corsair_accounts、corsair_entities、corsair_events、corsair_permissions。 |
hub |
{ projectApiKey, signingSecret },Hub 模式配置。 |
plugins |
配置好的插件工厂,例如 github({ authType: "managed" })。 |
multiTenancy |
true 时所有数据按最终用户隔离;false 用于应用自己的工具账号。 |
permissions |
可选的审批门控,见 docs/concepts/permissions.mdx。 |
5.3 源码佐证:五张表与工厂函数
五张表的类型定义在 packages/corsair/db/kysely/database.ts(CorsairKyselyDatabase),其中 corsair_accounts 的 dek 字段直接对应 SKILL 中"每个连接独立 DEK"的设计。createCorsair 工厂的重载实现于 packages/corsair/core/index.ts:传入 multiTenancy: true 时返回带 withTenant() 方法的 CorsairTenantWrapper;不传时返回直接可用的 CorsairSingleTenantClient,且两者都暴露 keys(集成级密钥管理)与 manage(管理命名空间)属性。
关于 Hub 配置,packages/corsair/hub/config.ts 的 normalizeHubConfig 会校验 projectApiKey 与 signingSecret 非空,缺失即抛 HubCredentialsMissingError;同时 ck_dev_ 前缀的开发密钥默认自动开启本地隧道(tunnel: false 可显式关闭),对应 maybeStartTunnel 与 superviseTunnel 的逻辑——这解释了为什么 SKILL 说开发环境无需配置投递 URL。
5.4 数据库接入形式
database 字段接受 pg 的 Pool、better-sqlite3 实例、postgres.js 的 Sql 或 Kysely 实例(见 packages/corsair/db/kysely/database.ts 的 CorsairDatabaseInput)。demo 中的 PostgreSQL 示例见 demo/minimal/db.ts。
六、添加 /api/corsair 路由(各框架适配器)
每个框架都有各自的适配器包装共享处理器(对应源码 packages/corsair/core/management/adapters 下的 express.ts、fastify.ts、hono.ts、next.ts 等):
| 框架 | 路由写法 |
|---|---|
Next.js(App Router),文件 app/api/corsair/[[...path]]/route.ts |
export const { GET, POST, OPTIONS } = toNextJsHandler(corsair, { basePath: "/api/corsair" }); |
| Express | app.use("/api/corsair", toExpressHandler(corsair, { basePath: "/api/corsair" }));。不要挂载 body parser:全局 express.json() 若出现在该路由之前会重新序列化 body,破坏 Hub 的签名校验。如果有全局 parser,应将 express.raw({ type: "application/json" }) 限定到本路由、全局 parser 注册在其后,或捕获 req.rawBody。 |
| Hono | app.all("/api/corsair/*", toHonoHandler(corsair, { basePath: "/api/corsair" })); |
| SvelteKit / Astro | export const { GET, POST, OPTIONS } = toSvelteKitHandler(corsair, { basePath: "/api/corsair" });。Astro 用同形状的 toAstroHandler。 |
| Remix / React Router | export const { loader, action } = toRemixHandler(corsair, { basePath: "/api/corsair" }); |
| Nuxt / Nitro | export default toNuxtHandler(corsair, { basePath: "/api/corsair" });。尽早挂载,置于任何 body parser 之前。 |
| Web 运行时(Bun、Deno、Workers) | toWebHandler(corsair, { basePath: "/api/corsair" }),返回 (Request) => Promise<Response>。 |
各框架的完整细节见 docs/adapters/handlers.mdx。测试方面,仓库提供了 packages/corsair/tests/framework-body-fidelity.test.ts 与 packages/corsair/tests/framework-realserver.test.ts,专门验证各框架下 body 保真与真实服务端行为——这正是 SKILL 反复强调"body parser 顺序破坏签名"的测试依据。
启动服务后,首次请求会自动向 Hub 注册投递 URL,仪表盘圆点变绿即表示接线已生效。投递 URL 的自动解析逻辑在 packages/corsair/hub/resolve-delivery-url.ts:优先取 CORSAIR_DELIVERY_URL 环境变量,否则自动推导 http://localhost:{PORT}/api/corsair;它不会从入站请求头读取投递地址。
七、连接账户(Connect Link)
7.1 服务端铸造连接链接
在服务端铸造 connect link,让用户跳转完成授权。tenantId 必须来自会话(session),绝不能来自用户输入:
const { connectUrl } = await corsair.manage.connect.createLink({
plugin: "github",
tenantId: session.userId,
});
// redirect the user to connectUrl
corsair.manage 命名空间对应源码 packages/corsair/core/management/index.ts 的 buildManagementNamespace,而 createLink 等核心操作定义在 packages/corsair/core/management/operations.ts。从源码看,createConnectLink 会根据是否配置 hub 分流:Hub 模式走 createHubConnectSession(托管 OAuth 会话,见 packages/corsair/hub/connect.ts),非 Hub 模式走 createManualConnectLink(需要 manual: { baseUrl, redirectUri } 配置并校验 OAuth 客户端凭证)。
7.2 React 客户端
React 中可用 createCorsairReactClient({ baseURL }) 及其 useCreateConnectLink、useConnectionStatus hooks,详见 docs/adapters/react.mdx,对应实现位于 packages/corsair/client/react。
用户授权发生在 Hub 托管页面上,授权完成后 token 加密落入你自己的数据库(Hub 不存储凭证)。
八、调用 API 与读取落库数据
8.1 直接调用
// call a service
await corsair.slack.api.messages.post({ channel, text });
// read auto-persisted responses back out of the app's DB
await corsair.github.db.repositories.search({});
8.2 多租户隔离
多租户应用通过租户作用域调用,所有请求与查询都限定在该租户:
const tenant = corsair.withTenant("user_123");
await tenant.github.api.repositories.list({});
await tenant.github.db.repositories.search({}); // only this tenant's rows
withTenant 的返回包装器在 packages/corsair/core/index.ts 中实现,它是多租户模式下的统一入口。demo 示例 demo/minimal/corsair.ts 展示了完全类型推断的调用体验:tenant.slack.api.messages.post(...) 的返回值(如 message.ts、message.channel)以及 tenant.linear.db.issues.list() 的行结构在编辑器中都能获得自动补全。
8.3 用 CLI 探索可用操作
需要查看当前实例支持哪些 API/DB 操作时,安装 Corsair CLI 并使用内省(introspection)命令:
npm install @corsair-dev/cli
npm corsair list # for api operations
npm corsair list --type=db # for db operations
npm corsair schema <endpoint> # to get input / output schema of any operation
CLI 实现位于 packages/cli,内省能力由 packages/corsair/core/inspect 提供。
九、Providers:托管 vs 自带凭证(authType)
authType 是插件配置中的关键字段,共有三种取值:
authType |
适用场景 | 配置示例 |
|---|---|---|
"managed" |
最快路径。使用 Corsair 托管的 OAuth 应用,无需自行注册 provider | github({ authType: "managed" }) |
"oauth_2" |
用户自带 OAuth 应用 | linear({ authType: "oauth_2", credentials: { clientId, clientSecret } }) |
"api_key" |
静态 API Key 或 bot token | slack({ authType: "api_key", credentials: { botToken } }) |
哪些服务支持自带 OAuth,见 docs/concepts/auth.mdx 与 docs/guides/plugin-credentials.mdx。从源码看,packages/corsair/core/management/operations.ts 中 getIntegrationCredState 会按 authType 校验凭证完整性:OAuth2 要求 client_id + client_secret 齐全(redirect_url 视为可选),其余类型要求所有必填字段齐全,未配置时 /plugins 与 /connection-status 仍返回 200 而非报错。
十、Webhook 与触发器
10.1 一个端点处理一切
processWebhook(corsair, headers, body, { tenantId }) 会完成:识别 integration、事件与租户 → 校验签名 → 写入数据库 → 执行 hooks。按插件用 secret 启用,并用 webhookHooks 响应:
github({
webhookSecret: process.env.GITHUB_WEBHOOK_SECRET,
webhookHooks: {
pullRequestOpened: {
after: async (ctx, result) => {
await corsair.withTenant(ctx.tenantId).slack.api.messages.post({ channel: "#eng", text: "PR opened" });
},
},
},
});
核心处理器在 packages/corsair/async-core/webhook-handler.ts(BaseWebhookHandler 提供 on/off/clearHandlers 事件注册),事件解析与租户匹配见 packages/corsair/core/webhooks 与 packages/corsair/core/webhooks/tenant-match.ts。另外 packages/corsair/core/webhooks/tenant-links.ts 负责 OAuth 场景下把回调与租户关联。
10.2 租户路由与 before 钩子
- 通过 webhook URL 上的查询参数路由租户:
?tenantId=user_abc123。 before钩子可以改写参数,或返回{ continue: false }跳过执行。
完整说明见 docs/guides/webhooks.mdx。
十一、工作流(Workflows)
工作流是基于上述 webhook hooks 构建的事件驱动自动化:事件触发 → after 钩子执行 → 调用任意插件 API。它没有独立引擎,就是纯 TypeScript。对于重型或长耗时任务,应从钩子中卸载到任务队列(job queue),仓库为此提供了 docs/guides/inngest.mdx、docs/guides/temporal.mdx、docs/guides/trigger-dev.mdx、docs/guides/hatchet.mdx 四份对接指南。
运行记录相关的命名空间(corsair.runs)与工作流执行实现见 packages/corsair/core/runs 与 packages/corsair/workflows/execute.ts。
十二、通过 MCP 把 Corsair 暴露给 AI Agent
12.1 安装与三个核心工具
安装 @corsair-dev/mcp,它通过三个工具把 Corsair 的能力暴露给 Agent,无需手动接线 schema:list_operations、get_schema、run_script。MCP 包源码位于 packages/mcp,其 buildCorsairTools(见 packages/corsair/adapters.ts)会把 API 操作转换为框架无关的工具:操作路径(如 slack.api.channels.list)被自动清洗成符合 OpenAI function-calling 命名约束的工具名,输入 schema 由 Zod 推导,execute 按点分路径动态解析并调用。
12.2 Claude Code 的 stdio 服务器
Claude Code 使用 stdio 服务器(mcp-server.ts):
import "dotenv/config";
import { runStdioMcpServer } from "@corsair-dev/mcp";
import { corsair } from "./corsair";
runStdioMcpServer({ corsair }).catch((err) => {
console.error("[corsair-mcp] Fatal:", err);
process.exit(1);
});
在 .mcp.json 中注册后用 /mcp 确认。Vercel AI SDK、OpenAI Agents、Mastra、Cursor、Codex 各有独立适配器(见 packages/mcp/src/adapters 下的 vercel-ai.ts、openai-agents.ts、mastra.ts、claude.ts 等),完整说明见 docs/mcp-adapters/mcp-adapters.mdx。
十三、权限与审批(Permissions)
对高风险操作做门控。根级配置:
permissions: { timeout: "30m", onTimeout: "deny", mode: "asynchronous" }
每个插件可设置 mode(open | cautious | strict | readonly)与按操作覆盖(overrides),例如:
"repositories.delete": "deny",
"releases.create": "require_approval"
被标记为 require_approval 的操作会向 corsair_permissions 表写入一条带 token 的记录;批准后 Agent 可重试该操作。实现见 packages/corsair/core/permissions(含 PermissionRequiredError、runReadonly 等导出,见 packages/corsair/core/index.ts 的 re-export),审批记录会附带审批 URL(enrichPermissionWithApprovalUrl)。完整语义见 docs/concepts/permissions.mdx。
十四、走向生产(Go to production)
- 配置生产密钥:在部署环境中设置
CORSAIR_PROD_API_KEY(ck_prod_前缀)与CORSAIR_PROD_SIGNING_SECRET。前面corsair.ts中的CORSAIR_PROD_* ?? CORSAIR_DEV_*写法会自动优先使用生产密钥,ck_prod_前缀把 SDK 切换到生产环境。 - 注册投递 URL:在仪表盘 Delivery URLs 标签页注册应用的公网 HTTPS 投递地址并激活生产环境。开发环境自动注册,生产环境是显式操作。相关说明见 docs/hub/environments.mdx 与 docs/hub/delivery-urls.mdx。
- 部署。
部署到 Vercel 时,可在 Hub 仪表盘连接 Vercel,把生产密钥直接推送到项目的环境变量,省去手动复制。
十五、端到端验证与安全检查
15.1 验证清单(缺一不可)
SKILL 明确:服务器能跑不代表任务完成,必须确认以下三项:
- 仪表盘圆点变绿(投递 URL 已自动注册);
- 账户能通过铸造的 connect link 完成连接;
- 一次真实的 API 调用成功返回数据。
15.2 安全红线
- 绝不记录或暴露签名密钥、KEK、租户 token 或插件凭证。
- 投递 URL 来自应用自身配置,绝不从入站请求头读取;不要试图用请求头"修正"它。
tenantId来自会话,绝不来自用户输入。- 当技术栈、插件、租户或数据库存在歧义时询问用户,不要凭仓库元数据猜测。
参考资源(仓库内对应文件)
- 文档索引:docs/docs.json、docs/introduction.mdx
- 设置指南:docs/hub/setup.mdx
- 路由处理器(全框架):docs/adapters/handlers.mdx
- Connect 与 OAuth:docs/management/connect.mdx
- 环境(dev vs prod):docs/hub/environments.mdx
- 插件目录:仓库 packages 下各
@corsair-dev/*包,如 packages/github、packages/slack、packages/linear - Hub REST API(非 JS 后端):docs/hub/rest-api.mdx
- 最小示例:demo/minimal/corsair.ts、demo/minimal/db.ts
- 核心源码:packages/corsair/core/index.ts、packages/corsair/core/management/operations.ts、packages/corsair/hub/config.ts
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351