Repository navigation
Plugin Prepare
在 packages/plugins/ 下新建插件包需要三步:从模板生成目录、把它接入 workspace、配置构建脚本。下面的流程同时覆盖内置插件的本地调试与 ZIP 上传包的准备。
仓库内置了插件脚手架模板 packages/plugins/template,并提供了生成器脚本:
pnpm plugin:create <your-id> --name "显示名称" --frontend生成器按 packages/plugins/template 的形态生成 packages/plugins/<your-id>(后端入口 src/index.ts,--frontend 时另含前端包)、写入包名与插件 ID、刷新 workspace lockfile 并打印后续步骤。
手工创建等价于:
-
复制模板目录:
cp -r packages/plugins/template packages/plugins/my-plugin cd packages/plugins/my-plugin -
修改
package.json中的包名为@stackpanel/plugin-my-plugin。 -
修改
src/index.ts中的插件 ID。 -
编辑
pnpm-workspace.yaml(如果packages/plugins/*已包含则无需修改),然后更新 lockfile:pnpm install --no-frozen-lockfile
插件的 package.json 至少需要:
{
"name": "@stackpanel/plugin-my-plugin",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "node ../../../scripts/build-plugin.mjs",
"typecheck": "tsc -p tsconfig.json"
},
"dependencies": {
"@stackpanel/sdk": "workspace:*"
},
"devDependencies": {
"@types/node": "^22.20.1",
"typescript": "^6.0.3"
}
}scripts/build-plugin.mjs 是内置插件的标准构建:先 tsc --emitDeclarationOnly 出 .d.ts,再用 esbuild 把源码打包成单文件 dist/index.js(不留裸相对导入,Node ESM 可直接跑)。不要用纯 tsc 直接产出运行入口——共享配置下 moduleResolution: bundler 会留下无扩展名的相对导入,Node ESM 解析不了。也不再用 tsup(已从插件脚手架移除)。
内置插件不需要 tsup.config.ts,只用两个 tsconfig:
-
编写插件代码(
src/index.ts)。 -
编译到
dist/:pnpm --filter @stackpanel/plugin-my-plugin build
-
若含前端包,编译
frontend/并更新前端注册表:pnpm build:frontend
-
重启 API(开发模式下
tsx watch会自动重启)。 -
API 启动时自动 seed 内置插件;非内置插件需打包上传安装。
touch apps/api/src/app.ts可手动触发tsx watch重新 seed 内置插件。
如果你的插件在 packages/plugins/ 下且被 apps/api 的 package.json 依赖,它会被视为内置插件,API 启动时自动 seed。修改源码后重新构建并重启 API 即可生效。
如果你在开发一个将通过 ZIP 上传安装的插件:
- 编写并构建。
- 打包为 ZIP(见 打包与签名)。
- 通过管理后台
/admin/plugins上传。 - 启用插件。
插件数据自治:插件不直接持有数据库句柄,不得把业务表写进内核 schema,也不通过数据库句柄操作数据。用 defineModel 声明模型,放进 PluginDefinition.customModels,由内核在激活时建表并暴露类型化访问:
import { defineModel } from '@stackpanel/sdk';
import { z } from 'zod';
export const itemModel = defineModel({
kind: 'my-plugin/item', // 命名空间/名称
label: '条目',
schema: z.object({ title: z.string(), stock: z.number().int().default(0) }),
indexes: [{ fields: ['stock'], types: { stock: 'integer' } }],
});读写只经 ctx.extensions(get / list / listAll / create / update / delete / patch)或 ctx.tx 事务。内核同时提供 /custom/<namespace>/<name> 通用 REST 面。PluginContext 不提供任何数据库句柄(ctx.db 已移除),插件拿不到 PrismaClient,也无法绕过 Extension 引擎直连数据库。内核自身的表结构变更与插件无关,属内核维护范畴。
开始
- 核心开发
构建内核扩展
- 插件
- 主题与前端包
AI 与自动化
- 内核 Agent
- MCP
对接平台
- Open Platform API
- Partner API