@dp-bohrium/widget-contracts
Bohrium Widget 平台的跨仓共享 Contract 包。它是 Manifest、Host Runtime Config、 Runtime Bridge 消息及其相关类型的唯一事实源,供 Host、SDK Runtime 与 Widget 工具链共同消费。
本包提供版本化 JSON Schema、由 Schema 生成的 TypeScript 类型、激活事件目录和 conformance fixtures,不提供生产 Runtime、AJV validator 或 Widget UI。
使用 Agent 接入时,先读 llms.txt 获取文档索引,再读 AGENTS.md
了解安装、Schema 校验和错误恢复规则。
环境要求
| 项 | 要求 |
|---|---|
| Node.js | ≥ 20 |
| 模块格式 | 纯 ESM |
| 根入口 | 类型、激活事件目录和运行时事件名校验 |
| JSON Schema | 2020-12(AJV 或任意等价实现) |
安装
只消费协议的 Host 或控制面可以直接安装本包。Widget 作者推荐安装 SDK,使用其统一子入口。
pnpm add @dp-bohrium/widget-contracts
包入口
| 入口 | 内容 |
|---|---|
. | 全部生成类型、WIDGET_ACTIVATION_EVENTS 和 isWidgetActivationEvent |
./schemas/*.json | 宿主清单、作者 Manifest、Host Runtime Config 和 Runtime Bridge Schema |
./conformance/* | 跨语言实现的固定测试语料 |
./package.json | 读取已安装版本 |
TypeScript 类型
import type {
HostToWidgetMessage,
PublicWidgetEvent,
RenderRequest,
WidgetHostRuntimeConfig,
WidgetManifest,
WidgetPluginManifest,
WidgetToHostMessage,
} from "@dp-bohrium/widget-contracts";
function handleRender(request: RenderRequest) {
// request.contribution 与 request.content.contribution 保持类型级别一致。
return request.contribution;
}
主要导出:
| 类型 | 含义 |
|---|---|
WidgetManifest | Widget bundle 的 Manifest(包含可选 activationEvents) |
WidgetPluginManifest | 插件作者编辑的 Manifest;使用 contributes 声明扩展点,不含 widgetSdkVersion、hostApiVersion 等由 bohr-widget pack 生成的宿主字段 |
WidgetActivationEvent | activationEvents 可声明的固定事件和工具名筛选形式 |
WIDGET_ACTIVATION_EVENTS | 编辑器、CLI 与 Host 文档使用的固定激活事件目录 |
WidgetEventName | context.events.on 可监听的实时事件名;不包含仅用于激活的 session.start |
PublicWidgetEvent | 上游事件经 Host 归一化、裁剪后的公开生命周期事件 |
WidgetLiveEvent | Host 按 type 向当前 iframe 主动推送的聚合事件 |
WidgetHostRuntimeConfig | 控制面为一次运行解析出的 Host Runtime Config |
RenderRequest | Forge 外部作者可声明的 Surface 只有 file-preview / panel;底层 Runtime Schema 仍保留内部 tool-result 投影,供受信任的 Host/协议验证使用,不进入外部 Manifest 或作者导航 |
ToolResultEnvelope | 可复用的工具结果状态、数据、指标、产物引用、provenance、warning 和 missing 投影 |
HostToWidgetMessage / WidgetToHostMessage | 双向 Bridge 消息联合类型 |
CapabilityRequest / CapabilityResult | 能力请求与结果 |
FileReadInput / FileReadResult | 普通读取,以及可选的内容版本、字节范围和截断元数据 |
FileWriteInput / FileWriteResult | 以 expectedRevision 和 mutationId 条件替换当前文件及其持久化回执 |
TaskListPage / TaskListItem | Host 授权后的任务摘要页、可观察的不透明任务引用与受限展示字段 |
WidgetError、ResourceBudget | 错误与预算,及相关主题、文件、渲染上下文类型 |
JSON Schema
| 文件 | 责任 | 主要消费者 |
|---|---|---|
schemas/widget-manifest.schema.json | bundle 名称、入口、Contribution、能力申请和样例 | 上传与管理侧 |
schemas/widget-plugin-manifest.schema.json | 插件作者维护的 name、源码 entry、contributes、激活事件和能力申请;宿主入口由 CLI 生成 | 编辑器、SDK 工具链 |
schemas/host-runtime-config.schema.json | 一次运行选定的版本、Digest、授权和资源配置 | Host Runtime |
schemas/widget-runtime-contracts.schema.json | 公开生命周期事件,以及 iframe 启动后的 Bridge、Render、Capability、Error 与预算消息 | SDK Runtime / Host Runtime |
import manifestSchema from
"@dp-bohrium/widget-sdk/schemas/widget-manifest.schema.json" with {
type: "json",
};
$id 是包内相对标识(如 widget-manifest.schema.json),不是可联网拉取的 URL。
host-runtime-config.schema.json 通过包内 $id / $ref 指向 宿主清单 和 Runtime
Schema,所以
消费者必须先从已安装的 @dp-bohrium/widget-sdk/schemas/*.json 本地加载并按
$id 注册,再解析 $ref —— 不要假设校验器会访问网络。
Conformance fixtures
conformance/ 与 Schema 一起发布,作为跨语言、跨仓实现的固定测试输入,不是另一套
协议定义:
conformance/
├── manifests/ # 合法 Manifest
├── host-runtime-config/ # 合法 / 非法 Host Runtime Config
├── resource-budgets/ # 正整数边界与拒绝结果的共用语料
├── render-inputs/ # File Preview / Panel 的渲染请求及增量更新
├── bridge/ # Bridge 消息样例
├── file-responses/ # 文件能力响应样例
├── file-grants/ # 独立文件写入授权与预算
├── invalid-file-requests/ # 缺版本、缺 mutationId 和路径越权请求
├── invalid-file-results/ # 不完整的操作专属结果
├── invalid-file-grants/ # 缺预算或带私有作用域的授权
├── invalid-network-requests/ # 必须拒绝的 network.fetch 请求
├── invalid-bridge-messages/ # 必须拒绝的完整 Bridge 消息
├── invalid-presentation-grants/ # 必须拒绝的展示授权
├── invalid-presentation-requests/ # 必须拒绝的展示请求
└── invalid-* # 其余必须被拒绝的输入
const fixture = await import(
"@dp-bohrium/widget-sdk/conformance/manifests/valid-panel.json",
{ with: { type: "json" } },
);
resource-budgets/corpus.json 以完整 baseline 和 cases 记录资源预算的通过/拒绝结果。
每个用例先深拷贝基线,再按 changes[].path 替换已有字段;remove: true 表示删除,
与 value 互斥。当前语料聚焦 retry 正整数和安全整数边界,不声明整个数值域或预算执行等价。
候选尚未发布时,跨仓测试可保留该文件的完整字节快照,记录源路径并在同步时核对 SHA-256;
普通 CI 读取仓内快照,不依赖兄弟 checkout 或未发布包。正式包发布后再按精确版本读取同一路径。
展示能力的语料覆盖 floating / overlay 申请、带 ui.presentation grant 的 init
消息、present / change-surface / close / focus-boundary 请求,以及降级成功、
关闭成功、策略拒绝和用户拒绝各类结果;对应的 invalid 语料拒绝空或未知 surface、
错误的确认标记,以及 Widget 提交的坐标、geometry、z-index 和身份字段。
manifests/valid-panel.json 刻意不申请展示能力,用于证明历史 Panel Manifest 仍然
兼容。
文件语料覆盖仅含 content / encoding 的普通读取、无版本的字节范围与 truncated、仅增加
revision 的读取、带 expectedRevision 的请求、独立的 files.write 申请与 grant、完整保存请求和回执,
以及 revision-conflict / mutation-conflict / write-outcome-unknown 失败。file-responses 的合法
结果包含能力信封;校验 ok: true 时,还需将 data 按 $defs/FileReadResult 或
$defs/FileWriteResult 校验。通用 CapabilityResult 的成功分支允许任意 JSON,无法代替操作专属校验;
invalid-file-results 则直接保存必须拒绝的 data。
这些语料证明结构契约,不模拟持久化。Host 还需执行当前文件绑定、写权限、实际字节预算、条件原子替换
和 mutationId 去重。普通读取不强制返回版本或范围字段,提供的可选字段仍须合法。请求携带
expectedRevision 时,Host/SDK 必须在运行时确认结果带有有效且匹配的 revision;缺失或不匹配
不能作为条件读取成功。Schema 不能单独表达请求与响应的版本关联。
SDK 还检查已提供的字节范围、实际字节数及回执与原请求的一致性。写入结果未知时不能据此判定
未保存,也不能自动生成新 mutationId 重试。
契约覆盖的范围
| 契约面 | 内容 | 权威 Schema |
|---|---|---|
| 能力申请与授予 | Widget 在 Manifest 的 requestedCapabilities 里申请 files(包含 Host 托管的 files.download)/ events / tasks.list / tasks.watch / state / actions / network / presentation / region,Host Runtime Config 在 binding 中授予 | manifest + host-runtime-config |
| Bridge 与事件 | init / render / capability / error / dispose 消息,以及公开生命周期事件 | runtime-contracts |
字段、枚举、上限和拒绝条件一律以 Schema 与 conformance fixtures 为准,本文不 复述:复述一份就多一份会漂移的事实源。
边界与版本约定
host-runtime-config.schema.json是控制面与 Host Runtime 之间的配置 Contract, 不是 Widget 收到的 Bridge 消息;Host Runtime 只把必要视图通过init传给 Widget。- 本包不实现 Runtime 行为,不负责权限执行、iframe 隔离、CSP、资源治理或 fallback / revoke。
- Schema 校验只覆盖结构与协议形状,不等于 Host Runtime 的安全策略决策。时间 顺序、隔离域、凭据与 query、Origin 规范化、Manifest/授权策略/运行授权交集,以及 DNS / SSRF 等运行时策略都必须由 Host 另行校验。
- Schema 通过不表示 Host 支持或授权某个动作。 Host 必须继续校验能力名称、 输入语义与运行策略,未知动作 fail closed。Manifest 不是任意 Host command 的执行入口。
- 凭据 binding 属于 Host provider 私有上下文;
credentialBindingId、credentialValue和 Host 场景上下文都不是插件公开协议字段。 - 协议版本只由载荷里的
schemaVersion、hostApiVersion、protocolVersion和resourceBudget.version承载,不进 Schema 文件名或$id。 - 开发期只维护一套当前 Contract:
WidgetManifest与WidgetHostRuntimeConfig均为schemaVersion: 1/hostApiVersion: 1,未知版本必须拒绝。破坏性调整直接升级所有 消费者,不创建 V1/V2 sibling,也不产出<name>.v2.schema.json。 - 包版本走 SemVer。新增协议字段必须同时更新 Schema、生成类型、fixtures 和 conformance 测试。
许可证
MIT。