从 @scalar/schemas 变更记录看 Scalar API 平台配置体系的设计演进
【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar
@scalar/schemas是 Scalar 开源 API 平台中负责"为所有 Scalar 包定义数据结构"的基础包:它承载 API Reference 配置校验、OpenAPI/AsyncAPI 文档 schema 以及 Scalar 自定义的x-扩展定义。本文以该包 CHANGELOG.md(版本 0.1.0 → 0.9.0)为主线,结合仓库源码逐项还原这些变更背后的实现细节,帮助你在集成 Scalar 时理解每个配置项的真实行为、优先级与适用场景,并掌握其 schema 驱动的开发范式。
一、包定位:Schemas for Scalar packages
从 package.json 看,@scalar/schemas的定位简洁明确——"Schemas for Scalar packages",依赖仅有两个:@scalar/helpers与@scalar/validation,而@scalar/types作为开发依赖承担"从 schema 生成类型"的任务。其导出结构按功能域划分:
@scalar/schemas/api-reference:API Reference 配置、source 配置、HTML 渲染配置与插件 schema;@scalar/schemas/openapi/3.1:OpenAPI 3.1 文档对象模型(document、operation、path-item、tag 等);@scalar/schemas/asyncapi/3.1:AsyncAPI 3.1 文档对象模型(0.3.0 版本引入)。
这套 schema 同时承担三重职责:运行时校验(通过@scalar/validation的coerce/validate)、类型生成(pnpm types:generate产出@scalar/types中的 TS 类型)、编辑器智能提示(每个字段携带typeComment,多数还带 YAML 示例)。这也是 CHANGELOG 中反复出现"Type the … against the real …"这一类改动的根源。
二、API Reference 配置 schema 的组成架构
0.2.0 版本引入的核心能力是"为 api-reference 配置编写自定义 schema"。实现上,配置 schema 由三个部分交叉(intersection)而成,见 api-reference-configuration.ts:
- base-configuration.ts:通用配置,如
title、slug、theme、layout、proxyUrl、customFetch、persistAuth、searchHotKey、showSidebar等; - source-configuration.ts:文档来源配置,
url、content、title、slug均可按 source 独立设置(0.7.0 移除了对 per-sourcetitle/slug的弃用标记,因为多 source 场景下这正是官方推荐用法); - 配置专属字段:
plugins、pluginUrls、isEditable、hiddenClients、defaultHttpClient、localization、customCss、各类on*回调与generate*Slug函数等。
校验入口apiReferenceConfigurationWithSourceSchema还承担旧配置自动迁移:hideDownloadButton→documentDownloadType: 'none'、spec.url/spec.content→ 顶层url/content、proxy→proxyUrl、fetch→customFetch、showToolbar→showDeveloperTools,并对指向旧代理地址的proxyUrl自动改写并给出警告。这一设计让配置体系可以持续演进而不破坏既有集成。
三、HTML 渲染与构建产物加载策略(0.9.0)
0.9.0 是最近的一次 Minor 变更,核心是把 API Reference 的默认加载方式从"单文件 UMD 包"切换到"代码分割的 ESM 构建":生成的 HTML 默认以<script type="module">加载@scalar/api-reference/esm.js,由于代码被分割,首屏渲染前需要执行的 JavaScript 更少。
对应实现见 html-rendering-configuration.ts,三个关键配置项的优先级与行为如下:
| 配置项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
cdn | string | https://cdn.jsdelivr.net/npm/@scalar/api-reference | UMD 包的加载地址,设置它即选择经典 UMD 构建,可用于固定版本 |
bundle | string | boolean | 不设置(默认 ESM) | 传 URL 字符串加载指定 ESM 构建;false回退到 UMD;true强制 ESM |
nonce | string | 无 | CSP nonce,用于严格script-src场景 |
这里有一个容易踩坑的优先级规则:bundle一旦设置,优先于cdn与nonce回退逻辑;而当设置了nonce(即严格的基于 nonce 的 CSP)时,默认自动使用 UMD 包,因为 ESM 构建通过import()加载的 chunk 无法被打上 nonce。如果你的 CSP 使用了'strict-dynamic',则可以通过bundle: true强制使用 ESM 构建。0.4.0 引入nonce时给出的最小示例仍具参考价值:
ApiReference({ url: '/openapi.json', // 与 script-src 指令中的值保持一致 nonce: 'r4nd0m', })需要特别提醒:nonce只能让script-src做到完全严格(无需unsafe-inline/unsafe-eval),style-src仍须保留'unsafe-inline'——因为渲染结果中存在内联style="…"属性,nonce 只对<script>、<style>、<link>元素生效,无法授权内联属性。
四、请求链路与鉴权相关配置的演进
CHANGELOG 中有多条改动直接关系 API 客户端如何发请求:
customFetch(0.3.0):新增customFetch并转发给 API 客户端,使"Test Request"等真实请求也能使用自定义 fetch(例如携带credentials: 'include');旧的fetch选项被弃用并自动迁移(带控制台警告),源码中fetch的typeComment明确标注@deprecated Use customFetch instead。onRequestBuilt与requestBuilt插件钩子(0.6.0):在请求构建完成、即将发出之前触发,回调收到即将真正上线的精确fetchRequest 对象。头部改动会作用于发出的请求,body 字节与服务器实际收到的一致——这使请求签名成为可能(对重建后的multipart/form-data做哈希会因 boundary 不同而签名失败)。对应 schema 定义在 api-reference-configuration.ts。- 插件 API 的全局鉴权只读访问(0.7.2):插件生命周期钩子
onInit、onConfigChange现在除config外还接收auth访问器,插件管理器向视图组件暴露getAuthState();插件可经auth.export()、auth.getAuthSecrets(documentName, schemeName)、auth.getAuthSelectedSchemas(payload)读取已存储的密钥与选中的安全方案,但不能修改鉴权状态。这与 api-reference-plugin.ts 中lifecycleHooksSchema的定义一致。
五、类型安全收紧:让错误配置"写不出来"
0.8.0~0.8.1 的改动体现了 Scalar 对配置错误的前置拦截思路——运行时保持宽松,类型层收紧:
defaultHttpClient(0.8.1):targetKey与clientKey原先只是string,没有自动补全,也检测不出错误值(例如把显示名'Fetch'当成客户端 id'fetch'传入会静默失效)。现在它们被类型化为真实的 target 与 client id 联合。hiddenClients(0.8.0):原先为Record<string, boolean | string[]> | string[] | true,拼写错误无法被发现。现在数组条目被类型化为 target(如'node')、客户端名(如'fetch')或完整 id(如'node/fetch'),record 形式以 target 为键;运行时仍保持宽松,未知名称依旧被优雅忽略。
实现上这两处的做法一致:运行时仍以宽松字符串通过coerce校验(真实联合会把未知值改写成第一个字面量),仅通过类型断言收紧 TS 类型,从而"配置作者获得自动补全,而运行行为不变"。同时hiddenClients的默认行为是隐藏 Unirest,传[]可显示全部客户端。
六、插件系统:从 JSON 可序列化到视图插槽
插件能力是 0.5.0~0.8.0 之间的重点:
pluginUrls(0.8.0):从 URL 加载插件。每个条目必须指向一个 ESM 模块,其 default export 即插件(与plugins条目同构)。独立构建(Scalar.createApiReference)会在 API Reference 挂载前动态import()这些模块,并将其 default export 与直接传入的plugins一并注册。与plugins的关键差异是pluginUrls可 JSON 序列化——因此 Docker 容器、Scalar for Aspire 这类以 JSON 传递配置的集成无需替换整个 bundle 即可加载插件。注意:该选项仅受独立浏览器构建支持(源码typeComment已注明)。content.start视图插槽(0.5.0):新增视图插槽,在 Introduction/Info 区域之前(内容区顶部)渲染自定义插件组件,见 api-reference-plugin.ts 中viewsSchema的content.start。sidebar选项(0.5.0):ViewComponent可通过sidebar: { show: true, label: 'My Page' }在侧边栏展示自定义视图入口;省略或show: false则隐藏。该入口接入既有导航体系,点击可滚动定位到插件视图并随滚动高亮。- 删除未接线配置(0.5.0):移除了从未被消费者接线的
isLoading与onSpecUpdate(后者回调从未触发)——这是"schema 即契约"原则的反向应用:没有消费者的配置项直接删除而非保留。
七、OpenAPI 扩展:用x-扩展驱动渲染细节
schema目录集中存放了大量 Scalar 自定义的 OpenAPI 扩展,0.4.0 之后的多条变更围绕它们展开:
x-scalar-links(0.7.0):在文档头部(contact、license、terms of service 链接旁)渲染额外的具名链接,例如隐私政策、版权声明等法律文本。schema 定义在 x-scalar-links.ts,每个条目为{ name, url },并有对应测试 x-scalar-links.test.ts 验证校验与强制转换:
x-scalar-links: - name: Privacy Policy url: https://example.com/privacy - name: Imprint url: https://example.com/imprintx-scalar-sdk-installation(0.4.0、0.4.2):在引言卡片中展示自定义 SDK 安装说明,无该扩展时回退到客户端选择器。每个条目含lang与 Markdown 格式的description,单个 tab 即可渲染带语法高亮代码块的富文本说明(例如 Java 同时给出 Maven 与 Gradle)。0.4.2 恢复了对弃用字段source的支持:设置时以围栏代码块形式追加到description(无description时单独使用),但description仍是推荐字段。schema 与示例见 x-scalar-sdk-installation.ts。
代码示例来源扩展(0.4.0):代码示例选择器除x-codeSamples外,新增读取x-scalar-examples、x-stainless-snippets、x-stainless-examples与x-readme.code-samples。同一操作上出现多个来源时按优先级取用:x-scalar-examples>x-stainless-snippets>x-stainless-examples>x-readme>x-codeSamples。
x-scalar-default-request-body-view(0.9.0):请求体编辑器默认以 Form 视图打开。可设defaultRequestBodyView: 'form'配置项,或在 OpenAPI 文档中写x-scalar-default-request-body-view扩展(后者按 source 生效)。默认值为raw,且当 body 无法以表单展示时回退到raw。
modelsSectionLabel(0.3.3):将侧边栏、内容区与搜索中的模型区标签改为'Models' | 'Schemas' | string,便于使用 OpenAPI 术语(源码中默认值来自@scalar/types的DEFAULT_MODELS_SECTION_LABEL)。
八、OpenAPI 3.2 嵌套标签支持(0.8.2)
0.8.2 实现了 OpenAPI 3.2 的嵌套标签:导航树通过tag.parent字段构建任意深度的层级。关键行为:
- 没有自身操作的父标签视为分区(section);既有操作又有子标签的标签则同时以两种身份渲染;
- 原生
parent嵌套优先于x-tagGroups,后者仅作为旧文档的回退方案; - 标签标题依次取
x-displayName、summary; - 现代布局下,无操作的父标签渲染自己的 summary 与 description 头部,而非像传统
x-tagGroups包装那样被扁平化。
对应 schema 见 tag.ts:Tag Object 新增parent(引用的标签必须存在且不得循环引用)、kind(机器可读分类,如nav、badge、audience)与summary三个可选字段(OpenAPI 3.2),该定义同时存在于@scalar/workspace-store与@scalar/schemas。
九、文档解析健壮性修复
CHANGELOG 中还有一组解析层修复,值得集成方关注:
- Path Item 使用
$ref(0.4.3):路径条目与 webhook 可以引用components.pathItems而非内联操作。导航、mutator、搜索与 markdown 导出现在会在读取 HTTP 方法与路径级参数之前解析 path-item 引用。 - 多类型 schema 数组保留(0.3.3):带校验关键字的 schema 被强制转换时,多类型 schema 数组(如
type: ['string', 'null'])得以保留,不再被破坏。 - AsyncAPI 安全方案
$ref修复(0.7.1):此前 server 通过$ref引用安全方案时,强制转换会合成默认的$ref-value(取第一个type字面量userPassword),并经 resolved-document 代理泄漏覆盖真实定义,导致所有方案都渲染成userPassword。修复后引用型字段的$ref-value变为可选,未解析的引用原样通过。
十、AsyncAPI 3.1:从零到一的全量 schema
0.3.x 系列为 AsyncAPI 3.1 补齐了完整支持:
- 0.3.0:新增 AsyncAPI 3.1 校验 schema 与
@scalar/schemas/asyncapi/3.1导出;同时扁平化重构——移除逐 schema 的create*工厂,改用recursiveRef直接导出扁平 schema;为引用专属字段(operation.channel、channel.servers、operation.reply等)新增asyncApiResolvedReference以保证$ref-value总是被校验。 - 0.3.1:新增类型化 AsyncAPI WebSocket binding schema——
asyncApiWsBindingObject覆盖method、query、headers、bindingVersion,并新增asyncApiSchemaObjectOrReference(Schema Object | Reference Object,排除 Multi Format Schema Object)用于 WebSocket binding 字段,同时重新生成@scalar/types/asyncapi/3.1类型。对应文件见 ws-binding.ts 与测试 ws-binding.test.ts。 - 0.3.2:新增 AsyncAPI 连接 URL 构造器与 server 列表辅助函数。
十一、工程化:schema 驱动的类型生成与发布治理
几条 Patch 改动透露了包内部的工程机制:
- 0.3.0 重构(#9294、#9292):把 schema 迁入 schemas 包目录,并从 schema 生成类型(
scripts/generate-types.ts);扩展定义也整体移入 schema 包,使"扩展即 schema"成为单一事实来源。 - 0.8.3 / 0.7.3(发布治理):全量包经 npm trusted publishing 重新发布(无功能变更);README 生成器元数据从
readme字段更名为scalarReadme——因为 npm 会把readme字段当作 README 正文,此前受影响包在 registry 上发布的是字面量[object Object]而非 README.md。 - 0.7.4:更新 README 中 Scalar 平台概览块。
十二、如何在当前仓库中验证这些行为
- 运行 schema 校验测试:
cd packages/schemas && pnpm test(vitest),覆盖 api-reference-configuration.test.ts(最小配置、完整配置、localization、oauth2RedirectUri 等用例)与各扩展的独立测试文件; - 重新生成类型:
pnpm types:generate,产出对应@scalar/types声明; - 完整阅读配置项注释:所有字段的
typeComment即当前版本的权威说明,重点参考 api-reference-configuration.ts 与 html-rendering-configuration.ts。
结语
回看@scalar/schemas从 0.1.0 到 0.9.0 的演进,可以清晰提炼出三条设计主线:以 schema 为单一事实来源(校验、类型、编辑器提示三合一)、运行时宽松而类型严格(让错误配置在编译期暴露而非静默失效)、旧配置自动迁移(弃用项持续工作并给出警告)。无论你是通过 Docker、Aspire 等 JSON 配置接入,还是在 HTML 中直接使用ApiReference,理解这些 schema 与优先级规则都能帮助你写出更可靠、更贴近官方语义的 Scalar 集成。
【免费下载链接】scalarScalar is an open-source API platform: 🌐 Modern REST API Client 📖 Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考