Repository navigation
Plugin Packaging
worable edited this page Oct 12, 2026
·
1 revision
插件开发完成后打包为 ZIP 上传安装。生产环境使用 Ed25519 签名校验包来源与完整性。
在仓库根目录执行:
pnpm plugin:pack <plugin-name>该命令执行 apps/api/scripts/pack-plugin.ts:
- 运行插件
build。内置插件走scripts/build-plugin.mjs(esbuild 打包 +tsc输出声明)。 - 自动生成
manifest.json:读取package.json,注入schemaVersion与apiVersion,并从编译产物的manifest读取requires/provides/consumes/permissions/roleTemplates。 - 产出
packages/plugins/<name>/dist-pack/<name>-<version>.zip,内含dist/、可选的assets/与可选的frontend/。
pack-plugin.ts 已自动排除 .d.ts、.d.ts.map、.ts、.tsx 等源码,只保留编译产物与前端包。如确需手动打包,只包含必要文件:
cd packages/plugins/my-plugin
zip -r dist-pack/my-plugin-1.0.0.zip \
manifest.json \
dist/index.js \
dist/index.js.map \
frontend/ # 如果有前端包my-plugin-1.0.0.zip
├── manifest.json # 必须
├── dist/
│ ├── index.js # 必须(或 manifest.entry 指定的文件)
│ └── index.js.map # 可选
├── assets/ # 可选:静态资源
├── frontend/ # 可选
│ ├── manifest.json
│ └── dist/
│ ├── index.js
│ └── admin.js # 有客户端入口时
└── signature.json # 可选
上传 ZIP 时,内核执行以下校验:
| 规则 | 限制 |
|---|---|
| 最大文件数 | 128 |
| 单文件最大 | 1 MB |
| 解压总大小 | 8 MB |
| 入口文件最大 | 512 KB |
| 禁止源码 |
.ts/.tsx/.jsx/.mts/.cts/.d.ts.map
|
| 禁止隐藏文件 |
.git*、.htaccess
|
| 路径安全 | 禁止 ..、绝对路径 |
| ID 格式 | /^[a-z0-9_-]{1,64}$/ |
| 保留 ID | 不可使用内置插件 ID、kernel、default
|
上传时检查 requires 声明的依赖:
- 非 optional 依赖必须已安装,否则返回 409
- 依赖版本必须满足
range(如有) - 内置插件不可通过上传覆盖
openssl genpkey -algorithm ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem使用 scripts/sign-package.mjs:
pnpm package:sign my-plugin-1.0.0.zip private.pem该命令计算 ZIP 内所有文件(除 signature.json)的 SHA-256 哈希,生成 signature.json 并写入 ZIP:
{
"algorithm": "ed25519",
"files": {
"manifest.json": "sha256...",
"dist/index.js": "sha256..."
},
"signature": "base64..."
}公钥可通过两种方式配置:
- 环境变量(优先级高,不可变):
STACKPANEL_SIGNING_PUBLIC_KEY - 管理后台:
PATCH /admin/signing(存储在 settings 表)
PATCH /admin/signing
{ "publicKey": "-----BEGIN PUBLIC KEY-----\n..." }
PACKAGE_SIGNATURE_REQUIRED |
公钥状态 | 行为 |
|---|---|---|
false(开发默认) |
未配置 | 跳过签名校验 |
true(生产默认) |
未配置 | 拒绝所有上传(启动时也会因缺公钥而报错) |
| 任意 | 已配置 | 必须有有效签名;缺 signature.json、哈希不符或验签失败均拒绝 |
只要配置了公钥,签名就是强制的——
PACKAGE_SIGNATURE_REQUIRED=false不会放宽「已配置公钥」场景。
- 读取 ZIP 中的
signature.json - 计算所有非签名文件的 SHA-256 哈希(排序后)
- 与
signature.json中的files比对 - 用公钥验证签名
访问 /admin/plugins,点击上传按钮选择 ZIP 文件。
curl -X POST http://127.0.0.1:3001/admin/plugins/upload \
-H "Authorization: Bearer <token>" \
-F "file=@my-plugin-1.0.0.zip"响应(HTTP 201):
{
"installed": true,
"live": true,
"upgraded": false,
"id": "my-plugin",
"frontendApply": { "requestedAt": "2026-01-01T00:00:00.000Z" }
}-
upgraded: false— 新安装;true— 升级已存在的插件 -
frontendApply— 含前端产物时返回,表示已请求 web 容器重建 registry 并重启;无前端时为null
上传后插件处于 registered 状态,需启用:
curl -X PATCH http://127.0.0.1:3001/admin/plugins/my-plugin \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'curl -X DELETE http://127.0.0.1:3001/admin/plugins/my-plugin \
-H "Authorization: Bearer <token>"内置插件不可删除。
packages/plugins/template 是最小可发布脚手架,复制改名即可开发:
cp -r packages/plugins/template packages/plugins/my-plugin核心开发
插件开发
主题开发
前端包开发
RESTful API