RaisFastRaisFast
Plugins

Manifest 参考

完整的 manifest.toml Schema — 插件信息、权限、Hook、路由、定时任务、依赖。

每个插件都有一个 manifest.toml,定义插件的身份、权限、Hook、路由和定时任务。

[plugin] — 插件身份

[plugin]
id = "com.example.my-plugin"
name = "My Plugin"
version = "0.1.0"
description = "Does something useful"
author = "Alice"
license = "MIT"
runtime = "js"
entry = "main.js"
字段必填默认值说明
id是—唯一插件 ID(建议反向域名格式)
name是—显示名称
version是—语义版本号
description否""描述
author否—作者
license否—许可证
runtime否"wasm"运行时:js / lua / rhai / wasm
language否"rust"语言标识
entry否"index.js"入口文件名
wasm否"plugin.wasm"WASM 文件路径(仅 runtime = wasm)
sdk_version否"v1"SDK 版本

自动检测:runtime = "lua" 且未设置 entry 时,加载器查找 init.lua。runtime = "rhai" 时查找 init.rhai。

[permissions] — 安全控制

除非显式声明,否则一律拒绝访问。

[permissions]
max_memory_mb = 16
timeout_ms = 5000
database = ["read:products", "write:orders", "categories"]
http = ["api.example.com", "*.github.com"]
config = ["app.*", "jwt.*"]
filesystem = ["read-write"]
字段默认值说明
max_memory_mb32(配置默认)单实例内存上限
timeout_ms配置默认值Hook 执行超时
database[](禁止)数据库表访问权限
http[](禁止)HTTP 白名单
config[](禁止)配置键白名单
filesystem[](禁止)VFS 访问级别

数据库权限

格式权限
"read:TABLE"只读
"write:TABLE"只写
"TABLE"读写
"*"所有表(受保护表除外)

受保护表即使声明 "*" 也不可访问:users、roles、permissions、audit_log、plugin_storage、options、rbac_roles、rbac_permissions、rbac_role_permissions、tenants。

SQL 安全:DDL 被阻止(CREATE/DROP/ALTER/TRUNCATE)。UNION、JOIN 和子查询在权限检查中被检测并阻止。

HTTP 白名单

  • 精确域名:api.example.com
  • 通配符子域:*.github.com
  • 路径通配:api.example.com/v1/*

内置 SSRF 防护:阻止 localhost、127.x、10.x、172.16-31.x、192.168.x、169.254.x、::1。

文件系统权限

值启用
"read"vfsRead、vfsExists、vfsList、vfsStat
"write"vfsWrite、vfsDelete
"read-write"所有 VFS 操作
"*"所有 VFS 操作

[hooks.<name>] — Hook 注册

[hooks.on-content-created]
priority = 50

[hooks.on-content-updating]
priority = 100
match = "product"

[hooks.on-content-updating]
priority = 100
content_types = ["product", "course"]

[hooks.render-markdown]
priority = 10
字段默认值说明
priority100执行顺序(数字越小越先执行)
match—按 Content Type 名称匹配
content_types[](全部)仅对指定的 Content Type 触发

Hook 名使用连字符(on-content-created),系统自动转换为下划线(on_content_created)。

[[routes]] — 自定义 API 端点

[[routes]]
method = "GET"
path = "/api/v1/plugins/my-plugin/stats"
handler = "getStats"
auth = "public"

[[routes]]
method = "POST"
path = "/api/v1/plugins/my-plugin/contacts/:contactId"
handler = "updateContact"
auth = "admin"
description = "Update a contact"
字段必填默认说明
method是—HTTP 方法
path是—路由路径,支持 :param 占位符
handler是—插件中的函数名
auth否defaultpublic / member / admin
description否—描述
permission否—额外权限要求

处理函数接收 input,包含 { path, method, body, headers, params }。直接返回数据,框架自动包装为 { code: 0, data: ... }。

路由输入参数

[[routes]]
method = "POST"
path = "/api/v1/plugins/my-plugin/deals"
handler = "createDeal"

[[routes.input]]
name = "title"
type = "string"
in = "body"
required = true
description = "Deal title"

[[routes.input]]
name = "page"
type = "integer"
in = "query"
default = 1
description = "Page number"
字段必填默认说明
name是—参数名
in否"query"位置:query / body / path / header
type否""类型提示
required否false是否必填
description否—描述
default否—默认值

路由输出

[routes.output]
description = "Deal list"

[[routes.output.fields]]
name = "id"
type = "string"
description = "Deal ID"

[[routes.output.fields]]
name = "title"
type = "string"
description = "Deal title"

[[cron]] — 定时任务

[[cron]]
label = "Daily Cleanup"
job_type = "daily_cleanup"
cron_expr = "0 0 * * *"
payload = """{"type": "full"}"""
enabled = true
字段必填默认说明
label是—任务名称
job_type是—任务类型(传给 on_cron_tick)
cron_expr是—Cron 表达式(七段,含秒)
payload否—JSON 负载字符串
enabled否true是否启用

Cron 条目在插件加载时同步到数据库,卸载时移除。

[[content_types]] — 捆绑 Content Type

[[content_types]]
file = "content_types/contact.toml"

插件可以自带 Content Type TOML 文件,安装时自动加载。

[[admin_pages]] — 管理后台页面

[[admin_pages]]
path = "/admin/plugins/crm"
label = "CRM"
icon = "users"
component = "CrmDashboard"
字段必填说明
path是页面路径
label是显示名称
icon否图标名
component否前端组件名

[dependencies] — 插件依赖

[dependencies]
"com.example.base" = "1.0.0"

插件按拓扑排序加载,确保依赖先初始化。

完整示例

[plugin]
id = "com.example.crm"
name = "CRM API"
version = "0.1.0"
description = "Sales pipeline and contact management"
author = "Alice"
license = "MIT"
runtime = "js"
entry = "main.js"

[permissions]
max_memory_mb = 16
timeout_ms = 5000
database = ["crm_contacts", "crm_companies", "crm_deals"]
http = ["api.example.com"]
config = ["app.*"]
filesystem = ["read-write"]

[hooks.on-content-created]
priority = 50

[hooks.on-content-updating]
priority = 100
content_types = ["contact"]

[hooks.render-markdown]
priority = 10

[[routes]]
method = "GET"
path = "/api/v1/plugins/crm/pipeline"
handler = "getPipeline"
auth = "public"

[[routes]]
method = "GET"
path = "/api/v1/plugins/crm/pipeline/:dealId"
handler = "getDealDetail"
auth = "member"

[[cron]]
label = "Daily Stats"
job_type = "daily_stats"
cron_expr = "0 0 * * *"
payload = """{"type": "full"}"""

[dependencies]
"com.example.base" = "1.0.0"

On this page