每个沙盒插件都有一个 emdash-plugin.jsonc 文件,位于 package.json 旁边。它是手动编辑的,包含插件的身份、信任契约(能力、主机、存储)以及注册表显示的配置文件字段。emdash-plugin init 会搭建一个;CLI 在 build、dev、validate、bundle 和 publish 时自动读取 ./emdash-plugin.jsonc。
该文件是 JSONC 格式:允许注释和尾逗号。
以下示例展示了一个图片画廊插件的完整清单:
{
"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",
"slug": "gallery",
"publisher": "did:plc:abc123def456",
"license": "MIT",
"author": { "name": "Jane Doe", "url": "https://example.com" },
"security": { "email": "[email protected]" },
// 可选配置文件
"name": "Gallery",
"description": "Image gallery block for EmDash.",
"keywords": ["gallery", "images"],
"repo": "https://github.com/example/plugin-gallery",
// 信任契约
"capabilities": ["content:read"],
"allowedHosts": [],
"storage": {}
}
身份
| 字段 | 必需 | 说明 |
|---|---|---|
slug | 是 | 发布者命名空间内的 URL 安全 ID。/^[a-z][a-z0-9_-]*$/,最多 64 个字符。 |
publisher | 是 | 您的 Atmosphere 账户的 DID 或 handle。参见发布者固定。 |
version | 否 | Semver 2.0,不含构建元数据。通常省略它——参见下文。 |
slug 和 publisher 共同构成包的身份。EmDash 自动从它们派生包的完整标识符。
version 位于 package.json 中
构建会将清单的 version 与 package.json#version 进行协调:
- 两者都设置且相等 → 正常。
- 两者都设置但不同 → 硬性错误。
- 只设置了一个 → 使用该值。
- 都未设置 → 硬性错误。
对于 npm 分发的插件,推荐的模式是从清单中省略 version,让 package.json 成为唯一的真实来源(您的发布工具已经在那里递增版本号)。没有 package.json 的注册表专属插件必须在清单中设置 version——没有其他地方可以存放它。
配置文件
这些内容供注册表列表使用。license、作者(author 或 authors)和安全联系人(security 或 securityContacts)是必需的;其余是可选的。
| 字段 | 必需 | 说明 |
|---|---|---|
license | 是 | SPDX 表达式("MIT"、"Apache-2.0"、"MIT OR Apache-2.0")。在首次发布时使用;后续发布以现有配置文件为准。 |
author / authors | 是 | 二选一。author: { name, url?, email? } 用于单个作者;authors: [...](≤ 32)用于多个。同时设置两者是错误。 |
security / securityContacts | 是 | 二选一。每个联系人至少需要 email 或 url 之一。securityContacts: [...](≤ 8)用于多个。同时设置两者是错误。 |
name | 否 | 显示名称。默认为 slug。 |
description | 否 | 保持简短(约 140 个字符)。长值可能在列表中被截断。 |
keywords | 否 | ≤ 5 个条目。 |
repo | 否 | 源代码仓库的 https:// URL。自动化发布需要一个规范的公共 GitHub URL;设置时如果缺少会询问。 |
除非您确实有多个作者或联系人,否则请使用单数形式 author / security——这是常见情况,脚手架也会生成这种形式。
信任契约
信任契约包括 capabilities、allowedHosts 和 storage。三者默认都为空,因此不需要额外权限的插件可以完全省略它们。
{
"capabilities": ["network:request", "content:read"],
"allowedHosts": ["api.example.com", "*.cdn.example.com"],
"storage": {
"events": { "indexes": ["timestamp"] },
"submissions": { "indexes": ["email"], "uniqueIndexes": ["token"] }
}
}
能力
已识别的名称:
| 能力 | 授予 |
|---|---|
content:read / content:write | 通过 ctx 读取/修改站点内容。 |
taxonomies:read | 读取分类定义和术语(只读)。 |
media:read / media:write | 读取/写入媒体。 |
users:read | 读取用户记录。 |
email:send | 通过 ctx 发送邮件。 |
network:request | 通过 ctx.http 发起出站 HTTP,限制在 allowedHosts。 |
network:request:unrestricted | 向任何主机发起出站 HTTP。用于替代 network:request。 |
hooks.email-transport:register | 注册邮件传输钩子。 |
hooks.email-events:register | 注册邮件生命周期钩子。 |
hooks.page-fragments:register | 注册 page:fragments 钩子(仅限原生)。 |
CLI 强制执行的两条交叉字段规则(编辑器的 JSON Schema 检查不会执行——请运行 emdash-plugin validate):
network:request要求非空的allowedHosts。如果插件确实需要访问任何主机,请改用network:request:unrestricted。network:request:unrestricted要求allowedHosts为空——不受限制的能力已授予所有主机,因此列表会与之矛盾。
主机模式是裸主机名(无协议、路径或空格)。前导 *. 允许子域名:*.cdn.example.com。
存储
集合名称到索引配置的映射。集合名称遵循相同的 /^[a-z][a-z0-9_]*$/ 规则(运行时使用名称作为 SQL 表后缀)。索引是字段名称或复合数组;uniqueIndexes 也是可查询的——不要同时将它们列在 indexes 中。
"storage": {
"events": { "indexes": ["timestamp", ["collection", "timestamp"]] }
}
管理界面
可选。沙盒插件通过 Block Kit 渲染管理页面和仪表板小部件;清单仅声明它们出现的位置。如果插件没有管理 UI,请完全省略 admin 键。
"admin": {
"pages": [{ "path": "/gallery", "label": "Gallery", "icon": "image" }],
"widgets": [{ "id": "recent-uploads", "title": "Recent uploads", "size": "half" }]
}
声明了 admin.pages 或 admin.widgets 的插件还必须在 src/plugin.ts 中提供渲染 Block Kit 内容的 admin 路由——schema 无法强制执行此规则(路由名称从源代码探测,而非清单),但运行时会检查。
发布者固定
publisher 固定发布身份,防止您意外地在错误的账户下发布插件。
在您首次成功发布时,如果清单的 publisher 与活动会话匹配,它将保持原样。如果您使用 emdash-plugin init 搭建并将其留空,CLI 会将活动会话的 DID 写回清单。
以下示例展示了 CLI 写入的行,其中已解析的 handle 作为注释添加以提高可读性:
"publisher": "did:plc:abc123def456", // jane.example.com
在每次后续发布时,CLI 将活动会话和固定的 publisher 解析为 DID 并进行比较。不匹配会立即以 MANIFEST_PUBLISHER_MISMATCH 失败——没有覆盖标志。请刻意解决:
- 会话错误:
emdash-plugin switch <did>,然后重新发布。 - 确实要将插件转移到新发布者:编辑清单中的
publisher。
不发布只验证
emdash-plugin validate # ./emdash-plugin.jsonc
emdash-plugin validate path/ # 指定目录
离线 schema 检查,带有 tsc 风格的 file:line:column 诊断信息,包括交叉字段规则。适用于预提交钩子或 CI 步骤。重复键和未知键都是错误(严格模式可捕获 "licens" 这类拼写错误)。
CLI 标志优先
显式标志(--license、--author-name 等)在两者都设置时覆盖清单值——这对 CI 覆盖很有用。--no-manifest 完全跳过清单(如果默认路径存在清单则会发出警告,以保持发布者固定安全机制的可见性)。