Supabase 文档 spec 流水线:从 OpenAPI 与 TypeDoc 规格文件生成 API 参考文档
Supabase 文档站(apps/docs)的参考文档并不是手写出来的,而是由一组“规格文件”(spec files)自动生成的。本文基于 apps/docs/spec/README.md 的核心描述展开,结合同目录下的 Makefile 与生成脚本源码,完整拆解这条“下载 → 转换 → 生成 → 格式化”的文档生成流水线,帮助读者理解 Supabase 的 Management API、Storage、Auth 等参考页面是如何从上游 OpenAPI / TypeDoc 规格中构建出来的,以及如何本地运行和验证这条流水线。
spec 目录的角色:规格文件是参考文档的唯一来源
apps/docs/spec/README.md 的核心陈述只有一句:这些 spec 文件用于生成参考文档(reference documentation)。也就是说,apps/docs/spec/ 目录是文档站的“数据源层”,里面存放了以下几类物料:
- OpenAPI 规格:如
api_v1_openapi.json/api_v2_openapi.json(Management API)、storage_v0_openapi.json、auth_v1_openapi.json等,以及对应的*_config.yaml配置文件; - TypeDoc 规格:
enrichments/tsdoc_v1/下存放各 JS SDK 包(supabase-js、auth-js/gotrue、postgrest-js、realtime-js、storage-js、functions-js)的类型文档 JSON; - 共享章节树:
common-api-sections.json、common-client-libs-sections.json、common-cli-sections.json、common-cli.yml等,定义文档站各产品章节的组织结构; - 客户端 SDK 规格:
supabase_js_v1.yml、supabase_dart_v2.yml、supabase_kt_v3.yml、supabase_py_v2.yml、supabase_swift_v2.yml、supabase_csharp_v1.yml等按语言/版本划分的 YAML 规格; - 生成脚本:
sections/generateMgmtApiSections.cts与sections/generateAccessControlPartials.mts,负责把 OpenAPI 规格转换为文档章节和权限表。
从源码结构看,这个目录与文档站的构建脚本紧密耦合:apps/docs/package.json 中的 codegen:references 脚本会同时驱动旧版 YAML 管线(Reference.generated.script.ts)和新版 TypeDoc 管线(scripts/build-reference-content.ts),两者都以 apps/docs/spec/ 为输入。
快速上手:make init 与 make
README 给出的上手步骤只有两步:
make init # 安装全部依赖
make # 下载并转换 spec 文件,生成文档内容
需要说明两点适用前提:
- 当前仓库根目录的 Makefile 的
help输出中并没有列出init目标,可以推断 README 中的make init描述来自较早的仓库阶段;在现有仓库中,依赖安装实际由 pnpm workspace(pnpm-workspace.yaml+ 根package.json)承担,即pnpm install后执行 Make 命令即可。 - README 中的
make指的是在apps/docs/spec/目录下执行。由于 spec/Makefile 的第一个目标是run,默认目标即:
run: download transform generate format
因此一次 make 会顺序执行四个阶段。Makefile 顶部还定义了 GENERATOR_DIR=../../../packages/generator,指向仓库内的 packages/generator 工具包,供生成脚本复用。
四阶段流水线拆解
download:从各服务拉取最新规格源
Makefile 中 download 目标聚合了当前启用的下载任务:
download: download.api.v1 download.mcp-tools-permissions download.storage.v1 download.tsdoc.v2 download.server.v1 download.middleware.v1
各任务的来源与产物:
| 目标 | 来源 | 产物(写入 spec 目录) |
|---|---|---|
download.api.v1 |
Management API 的 /api/v1-json 与 /api/v2-json 端点 |
api_v1_openapi.json、api_v2_openapi.json |
download.mcp-tools-permissions |
Management API 的 platform/mcp-tools-permissions 投影端点 |
mcp_tools_permissions.json(下载后用 Prettier 格式化) |
download.storage.v1 |
Storage 服务的 OpenAPI 文档 | storage_v0_openapi.json |
download.tsdoc.v2 |
各 JS SDK 包发布的 TypeDoc JSON(supabase-js、auth-js、postgrest-js、realtime-js、storage-js、functions-js 共 6 个包) | spec/reference/javascript/v2/*.json |
download.server.v1 |
@supabase/server 的 TypeDoc 规格 | spec/reference/server/v1/server.json |
download.middleware.v1 |
@supabase/middleware 的 TypeDoc 规格 | spec/reference/middleware/v1/middleware.json |
Makefile 中保留了若干被注释的目标,记录了规格的演化历史,值得注意:
download.auth.v1被注释掉,注释说明 GoTrue(Auth)的 OpenAPI 目前走人工流程:先从 GoTrue 的 swagger.json 获取 Swagger 2.0 定义,再手动转换为 OpenAPI 3.0 后写入auth_v1_openapi.json;download.tsdoc.v1(v1 SDK 的 TypeDoc)标注为“不再更新”,v1 客户端规格改为由enrichments/tsdoc_v1/中已提交的 JSON 承担;download.analytics.v0从 Logflare 拉取 OpenAPI,配套了独立的validate.analytics.v0校验目标(redocly lint --extends=minimal)。
transform:用 Redocly bundle 展开 OpenAPI $ref
transform 目标(Makefile)对三份 OpenAPI 规格做“解引用”(dereference),产物统一落到 transforms/ 目录:
transform: dereference.api.v1 dereference.auth.v1 dereference.storage.v0
具体命令形如:
npx --package=@redocly/cli redocly bundle --dereferenced \
-o transforms/auth_v1_openapi_deparsed.json auth_v1_openapi.json
这里有一个在 Makefile 中明确注释的工程细节:api_v1 / api_v2 的 bundle 故意不带 --dereferenced,因为 api_v2_openapi.json 中存在循环引用(APIErrorObject.issues -> APIErrorObject),Redocly 无法将其扁平化为 JSON;未解析的 $ref 会在后续的 writeApiReferenceSections 逻辑中手动处理。其余规格(auth、storage)则用 --dereferenced 完全展开。
generate:从 OpenAPI 生成章节导航与权限表
generate 目标(Makefile)包含两个生成任务:
generate: generate.sections.api.v1 generate.partials.access-control
任务一:Management API 章节。generateMgmtApiSections.cts 接收 transforms/ 下的 v1 与 v2 deparsed 规格,输出 common-api-sections.json。其核心逻辑(见该文件 extractSectionsFromOpenApi 函数)是:
- 将 v1、v2 的
paths合并,后者覆盖前者(Object.assign按文件顺序合并,v2 优先); - 遍历每个 route × HTTP method,跳过带
x-internal标记的内部端点; - 以
tags[0]作为分类(category),按operationId生成条目,operationId必须匹配^[a-z0-9]+(?:-[a-z0-9]+)*$,标题则由 slug 反向转换(去掉v\d+前缀、连字符转空格、首字母大写); - 输出
type: 'category'的嵌套 sections 数组,供文档站渲染侧边栏导航。
任务二:访问控制(Scoped PAT / MCP 工具)权限表。generateAccessControlPartials.mts 的输入除了 v1/v2 deparsed 规格外,还有 mcp_tools_permissions.json,以及 Studio 侧维护的共享权限目录 packages/shared-data/scoped-access-token-permissions.ts(PERMISSION_CATALOG_BY_CATEGORY 与 PERMISSION_MODE_LABEL)。脚本从每个端点读取 x-fga-permissions 字段(一组 scope 组替代项),按资源/访问级别聚合出权限行,最终写入:
- apps/docs/content/_partials/access-control/scoped_pat_permissions.mdx
- apps/docs/content/_partials/access-control/scoped_pat_mcp_tools.mdx
脚本在生成内容顶部写入固定注释 {/* Generated by 'make ... generate.partials.access-control'. Do not hand-edit ... */},并内置了一张 WORD_FIXES 映射表(api→API、sso→SSO、pit r→PITR、pgbouncer→PgBouncer 等),保证生成的 Markdown 术语大小写与文档站风格一致。生成后再执行 prettier --write 统一格式。
format:Prettier 统一格式,便于 Git 追踪变更
最后一个阶段非常务实(Makefile):
format:
npx prettier --cache --write .
注释说明了动机:规格文件体量巨大且频繁变动,用 Prettier 规范化后 Git 的 diff 才稳定可读——这也是 download.mcp-tools-permissions 单独再跑一次 Prettier 的原因。
客户端 SDK 规格:legacy YAML 与新版 TypeDoc 管线
spec 目录还承载客户端库参考文档的生成,这里存在新旧两条管线,均以 spec 目录为输入:
旧管线(legacy):各语言 SDK 的 supabase_<lib>_v<ver>.yml(如 supabase_js_v2.yml、supabase_dart_v2.yml)加上共享章节树 common-client-libs-sections.json,由 apps/docs/features/docs/Reference.generated.script.ts 驱动生成 features/docs/generated/<sdk>.<version>.*.json。对应 apps/docs 的 pnpm codegen:references:legacy。
新管线(TypeDoc):spec/reference/<lib>/<ver>/ 下存放下载得到的 TypeDoc JSON dump(gitignored 构建产物)与手工维护的 config.json、partials/,由 apps/docs/scripts/build-reference-content.ts 在构建期扫描生成 content/reference/<lib>/<ver>/ 下的五个 JSON(bySlug、flat、sections、functions、typeSpec)。该子管线的完整设计——包括 @category/@subcategory 标签收集规则、partials 的路由语义、config.json 的全部选项(excludeCategories、excludeDefinitions、categoryOrder、partialsOrder、navigationPrefixes)——在 apps/docs/spec/reference/README.md 中有详尽说明,此处不展开。
一个具体的配置实例是 apps/docs/spec/reference/javascript/v2/config.json:
{
"excludeCategories": ["Initializing"],
"excludeDefinitions": ["constructor"],
"categoryOrder": ["Database", "Auth", "Edge Functions", "Realtime", "Storage"],
"partialsOrder": ["introduction", "installing", "initializing", "typescript-support"],
"navigationPrefixes": {
"Database": false,
"Realtime": false,
"Edge Functions": "functions"
}
}
它控制了 JavaScript SDK v2 参考文档的分类过滤、导航顺序以及 URL slug 前缀(例如 Edge Functions 的分类挂在 /functions 而非 /edge-functions 下)。
两条管线都挂在 apps/docs 的构建链上:pnpm codegen:references = codegen:references:legacy + codegen:references:new,而 codegen:references:new 又先执行 codegen:references:new:ensure——检查 spec/reference/javascript/v2/supabase.json 等 dump 是否存在,缺失时自动回落到 cd spec && make download.tsdoc.v2 补下载,因此干净克隆后即可直接 pnpm dev / pnpm build。
校验与同步:快照测试与 CI
这条流水线有两个防漂移机制:
- 本地快照测试:apps/docs/spec/reference/README.md 说明 CI 通过
scripts/build-reference-content.test.ts的快照测试把关新管线——任何输出变化(新方法、slug 形状、类型签名、章节顺序)都会以快照 diff 的形式出现在 PR 中,作为“人类可审阅的变更预览”。需要刷新快照时执行cd apps/docs && npx vitest run --update scripts/build-reference-content.test.ts。 - CI 自动更新:仓库
.github/workflows/下存在docs-mgmt-api-update.yml(Management API 规格定期刷新)与docs-js-libs-update.yml(supabase-js 发版后自动拉取新 TypeDoc dump 并提交再生成的快照 PR)等工作流,从源码结构看,上游规格更新不会依赖人工记得跑make download。
关键文件索引
| 路径 | 作用 |
|---|---|
| apps/docs/spec/README.md | spec 目录使用说明(本文骨架来源) |
| apps/docs/spec/Makefile | 下载/转换/生成/格式化四阶段任务定义 |
| apps/docs/spec/sections/generateMgmtApiSections.cts | OpenAPI → 章节导航(common-api-sections.json) |
| apps/docs/spec/sections/generateAccessControlPartials.mts | OpenAPI + 权限目录 → Scoped PAT / MCP 工具权限表 |
| apps/docs/spec/reference/README.md | 新版 TypeDoc 参考文档管线设计 |
| apps/docs/scripts/build-reference-content.ts | TypeDoc dump → 五个参考文档 JSON 的构建脚本 |
| apps/docs/package.json | codegen:references:* 脚本与 predev/prebuild 挂载点 |
| packages/shared-data/scoped-access-token-permissions.ts | 权限表生成共享的权限目录 |
总结来说,apps/docs/spec/ 是 Supabase 文档站参考文档的规格层:README 给出“make init + make”两步入口,而 spec/Makefile 把这条入口落实为 download → transform → generate → format 四个可独立复用的阶段——用 Redocly 展开 OpenAPI 引用,用脚本生成章节导航与权限表,再用 Prettier 固定格式以便 Git 审阅。理解这条链路后,你可以自行定位“某个参考页面的章节结构或权限表为什么长这样”,并通过对应的 download.* / generate.* 目标做局部刷新与验证。
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 StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00