应用扩展
ShopFaaS 应用扩展开发完整指南——目录结构、权限声明、原子 API、Webhook、前端 UI 与发布流程。强隔离架构确保店铺数据安全。
应用扩展是 ShopFaaS 的核心扩展机制,让店长与第三方开发者为店铺添加新功能。应用通过受控 API 访问店铺数据,运行在隔离沙箱中,确保店铺数据安全。
开发流程一览
- 初始化项目 — 用
@shopfaas/plugin-devkit init创建应用骨架 - 声明权限 — 在
plugin.json列出所需权限码 - 实现 Handler — 编写 Webhook handler 与自定义 Action
- 开发 UI — 在
ui/目录编写设置页与仪表盘组件(运行在 Web Worker 沙箱) - 本地测试 —
plugin-devkit dev启动 HotReload 调试 - 打包发布 —
plugin-devkit pack && publish提交到应用市场 - 审核上架 — 自动化扫描 + 人工审核通过后上架
核心概念
强隔离架构
| 层 | 机制 | 说明 |
|---|---|---|
| 运行时 | 独立 Worker 子线程 | 应用代码独立运行,CPU/内存/超时配额限制 |
| 权限声明 | plugin.json | 显式声明所需权限,店长安装时可审查 |
| 数据访问 | 原子 API + 事件钩子 | 不能直接操作平台数据库 |
| 前端 UI | Web Worker 沙箱 | UI 代码运行在沙箱,不影响主页面 |
| 数据存储 | 元对象 API | 应用不允许自建表,使用平台元对象存储数据 |
数据访问方式
应用通过以下三种方式访问数据:
- 原子 API:
ctx.api.orders.list()/ctx.api.products.get()等受控 CRUD 接口 - 元对象 API:创建应用自定义数据(基于平台元对象机制,存于 JSONB)
- 事件钩子:通过 Webhook 接收订单创建、支付完成等事件推送
应用目录结构
plugins/my-plugin/
├── plugin.json # 应用元信息(名称、版本、权限、Webhook)
├── index.ts # 应用入口(注册 Action / Webhook handler)
├── lib/ # 应用内部库
├── webhooks/ # Webhook handler
│ ├── order-created.ts
│ └── order-paid.ts
├── actions/ # 自定义 Action handler
│ └── send-notification.ts
├── ui/ # 前端 UI 组件(运行在 Web Worker 沙箱)
│ ├── Settings.tsx
│ └── Dashboard.tsx
├── config-schema.ts # 设置项 schema(Zod)
└── package.json
plugin.json
{
"name": "order-notify",
"version": "1.0.0",
"description": "订单通知应用,订单创建/支付时推送通知到外部服务",
"author": "Your Name",
"permissions": ["order:view"],
"webhooks": [
{
"event": "order.created",
"handler": "webhooks/order-created.ts"
},
{
"event": "order.paid",
"handler": "webhooks/order-paid.ts"
}
],
"actions": [
{
"name": "send-notification",
"handler": "actions/send-notification.ts"
}
],
"config_schema": "config-schema.ts",
"ui": {
"settings": "ui/Settings.tsx",
"dashboard": "ui/Dashboard.tsx"
}
}
权限声明
应用在 plugin.json 中声明所需权限,权限码与 店铺角色权限码 一致:
{
"permissions": ["order:view", "order:fulfill", "product:view", "customer:view"]
}
安装时审查
店长安装应用时,系统会展示应用所需权限列表,店长确认后才会授予对应权限。
运行时校验
应用调用原子 API 时,运行时自动校验权限:
// 若应用未声明 order:view 权限,调用将抛出 PermissionDeniedError
const orders = await ctx.api.orders.list({ limit: 10 });
原子 API
应用通过 ctx.api.* 访问店铺数据:
import type { PluginContext } from "@shopfaas/plugin-runtime";
export default async function handler(ctx: PluginContext) {
// 订单
const orders = await ctx.api.orders.list({ limit: 10, status: "PAID" });
const order = await ctx.api.orders.get("uuid-1");
await ctx.api.orders.fulfill("uuid-1", { tracking_number: "SF123" });
// 商品
const products = await ctx.api.products.list({ limit: 10 });
await ctx.api.products.updateInventory("uuid-1", { quantity: 100 });
// 客户
const customers = await ctx.api.customers.list({ limit: 10 });
// 元对象(应用自定义数据)
const metaobject = await ctx.api.metaobjects.create({
type: "wishlist",
fields: { product_id: "uuid-1", customer_id: "uuid-2" },
});
}
事件钩子(Webhook)
Webhook handler
// plugins/order-notify/webhooks/order-created.ts
import type { WebhookHandler } from "@shopfaas/plugin-runtime";
const handler: WebhookHandler<"order.created"> = async (event, ctx) => {
const { order_id } = event.payload;
// 调用原子 API 获取订单详情
const order = await ctx.api.orders.get(order_id);
// 读取应用配置
const config = await ctx.getConfig();
const webhookUrl = config.notification_webhook_url;
// 发送通知到外部服务
await fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event: "order.created",
order,
timestamp: event.timestamp,
}),
});
};
export default handler;
支持的事件
完整事件清单见 Webhook 文档。
自定义 Action
应用可注册自定义 Action,供前端 UI 调用:
// plugins/order-notify/actions/send-notification.ts
import type { ActionHandler } from "@shopfaas/plugin-runtime";
const handler: ActionHandler<"send-notification"> = async (input, ctx) => {
const { message, channel } = input;
const config = await ctx.getConfig();
const response = await fetch(config.notification_webhook_url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message, channel }),
});
if (!response.ok) {
throw new Error(`通知发送失败: ${response.status}`);
}
return { success: true };
};
export default handler;
应用配置
config-schema.ts
使用 Zod 定义应用配置 schema(店长在后台填写):
import { z } from "astro/zod";
export const configSchema = z.object({
notification_webhook_url: z.url({ message: "请输入有效的 URL" }),
notification_channels: z.array(z.enum(["email", "sms", "webhook"])).default(["webhook"]),
retry_times: z.number().int().min(0).max(5).default(3),
});
export type Config = z.infer<typeof configSchema>;
读取配置
const config = await ctx.getConfig();
const webhookUrl = config.notification_webhook_url;
前端 UI
应用前端 UI 运行在 Web Worker 沙箱,通过 @shopfaas/plugin-bridge 与主页面通信:
// plugins/order-notify/ui/Settings.tsx
import { usePluginConfig, usePluginAction } from "@shopfaas/plugin-bridge";
export default function Settings() {
const [config, setConfig] = usePluginConfig();
const sendNotification = usePluginAction("send-notification");
return (
<div>
<h2>订单通知设置</h2>
<label>
通知 Webhook URL:
<input type="url" value={config?.notification_webhook_url ?? ""} onChange={e => setConfig({ notification_webhook_url: e.target.value })} />
</label>
<button onClick={() => sendNotification({ message: "测试通知", channel: "webhook" })}>发送测试通知</button>
</div>
);
}
开发工具链
@shopfaas/plugin-devkit
CLI 工具,提供应用扩展开发的完整工作流:
# 初始化新应用
bunx @shopfaas/plugin-devkit init my-plugin
# 本地开发(HotReload + 调试)
bunx @shopfaas/plugin-devkit dev
# 运行测试
bunx @shopfaas/plugin-devkit test
# 打包
bunx @shopfaas/plugin-devkit pack
# 发布到应用市场
bunx @shopfaas/plugin-devkit publish
@shopfaas/plugin-runtime
应用扩展运行时,提供:
PluginContext— 应用上下文(API 调用、配置读取、日志)WebhookHandler— Webhook handler 类型ActionHandler— Action handler 类型
@shopfaas/plugin-bridge
前端 UI 桥接,提供:
usePluginConfig()— 读取/写入应用配置usePluginAction(name)— 调用应用自定义 ActionusePluginData(key)— 读取应用缓存数据
发布与审核
应用提交到应用市场需通过自动化扫描 + 人工审核:
自动化扫描
- 权限最小化检查(是否声明了不必要的权限)
- API 调用合规性检查
- 静态代码分析(潜在安全风险)
- 性能基准测试(响应时间、资源占用)
人工审核
- 业务合规性(是否符合平台政策)
- 代码质量(注释、类型、测试覆盖)
- UI/UX 体验
- 文档完整性
审核通过后应用即可在应用市场上架,详见 应用市场。