编写提供商插件
提供商插件实现一个社交网络。它不能添加命令、修改 CLI,也不能改变 Core 存储状态的方式:插件契约就是全部扩展面,五个官方提供商与第三方提供商使用完全相同的契约。
包结构
提供商是一个 ESM 包,其根默认导出为插件对象。使用 @syndroo/provider-sdk 提供的 defineProvider 声明插件,并导出结果:
import { defineProvider } from "@syndroo/provider-sdk";
export default defineProvider({
manifest: {
id: "example",
name: "Example",
version: "0.7.0",
apiVersion: 1,
declaredCapabilities: ["text"],
egress: { fixedOrigins: ["https://api.example.com"] },
schemas: {
connectOptions: { type: "object", additionalProperties: false, properties: {} },
credentialInput: {
type: "object",
additionalProperties: false,
required: ["token"],
properties: { token: { type: "string", minLength: 1 } }
},
content: {
type: "object",
additionalProperties: false,
properties: { text: { type: "string" } }
},
publishOptions: { type: "object", additionalProperties: false, properties: {} }
}
},
connect: async (input, context) => {
return { status: "done", identity: { /* account */ }, credentials: { /* stored */ } };
},
freeze: (input) => {
return { payload: { text: input.content.text } };
},
publish: async (input, context) => {
return { status: "succeeded" };
}
});默认导出就是插件对象本身,而不是工厂。一个包通过一次 defineProvider 调用声明一个提供商;该 ID 同时也是注册表键和包名后缀。
清单
| 字段 | 规则 |
|---|---|
id | 小写提供商 ID,最多 64 个字符,并与包名后缀一致。 |
name | 仅用于显示的名称,最多 128 个字符。 |
version | 必须等于包自身的版本。 |
apiVersion | 整数 1。不匹配时会拒绝,而不是猜测。 |
declaredCapabilities | 从 text 和 article 中选择的列表,不得重复,最多八个条目。 |
schemas | 四个模式:connectOptions、credentialInput、content 和 publishOptions。每个都是 JSON Schema,最大 64 KiB、最深 32 层,只能使用本地引用。 |
egress | 插件可以使用的外部 HTTPS 地址(域名);见下文。 |
声明会在被读取前先受到限制:验证器只检查自有数据属性,从不执行 getter,从不编译或求值模式,而且在模块加载期间从不导入、访问文件系统、读取时钟或打开套接字。
出站声明
egress.fixedOrigins 必填,列出提供商打算访问的规范 HTTPS 地址(域名)。运行时会根据此列表生成出站策略,因此对插件未声明地址的请求会在离开进程之前被拒绝。
- 每项由
https://加主机组成:不得包含端口、路径、查询或用户信息。 - IP 字面量或不含点的主机会被拒绝。
- 列表最多 20 个条目,重复项会被删除。
- 没有固定外部地址的提供商(例如由用户指定主机的联邦网络)会声明空列表,并设置
federated: true。
官方声明就是示例:Bluesky 使用 https://bsky.social,DEV.to 使用 https://dev.to,LinkedIn 使用 linkedin.com 的两个地址,Threads 使用 threads.net 的两个地址,Mastodon 使用空的联邦列表。
三个操作
connect 运行连接中的一个步骤。它要么以身份和要保存的凭证结束,要么向调用方返回一个动作:请求凭证字段、用于浏览器授权的 open_url,或 wait_for_callback。插件从不驱动用户界面,也从不决定会话如何存储。
freeze 是冻结内容、目标选项和同一次运行已知信息的纯函数。它编译提供商原生载荷,并且必须具有确定性:相同输入产生逐字节相同的输出。任何机密都不得出现在冻结载荷、预览、写入结果或抛出的错误中。
publish 通过注入的传输层发送冻结载荷,并报告三种结果之一:succeeded;带处置状态 not_applied 的 failed;或 unknown。插件绝不自行重试,也绝不重新分类此前的未知写入。
测试插件
@syndroo/provider-sdk/testing 导出共享契约测试,而生产入口点刻意不导出它们,因此运行时依赖图绝不会接触测试脚手架。官方提供商也用它断言相同契约。
不包含的内容
- 不能贡献 CLI 命令、中间件、状态适配器或执行规则。
- 没有自动发现:注册表是显式且由配置驱动的。
- 没有插件市场。本站记录契约和官方提供商;第三方提供商自行记录其平台。