Files
shaw c63bd14a02 feat(plugin): generic host services + read-only status bridge channel
Extend the local plugin system's host<->plugin contract with generic,
capability-neutral facilities, so transport plugins can be built on top
without embedding plugin-specific logic in the host.

Host services (plugin dials a broker-provided HostService gRPC):
- per-plugin namespaced KV store (key/value size and TTL bounded)
- account directory: ListAccounts + ResolveOutboundIdentity, restricted to
  the accounts a plugin's declared capability already covers
- InitHostServices lifecycle hook; plugins that don't implement it run
  unchanged and are simply offered no host services

Read-only runtime status channel:
- HealthResponse gains an opaque, plugin-defined status_json produced
  passively (no config apply, no upstream call, no side effects)
- GET /admin/plugins/:id/status (ungated) and the plugin.status UI-bridge
  verb map to Health, so a status UI can poll live state without a step-up
  prompt or a "test" side effect
- config.test no longer force-shows a host success toast; the plugin UI owns
  result presentation, so plugins that read status do not spam toasts

Document the UI-bridge verb taxonomy (read vs mutate/test gating) and the
status contract under pkg/pluginapi.
2026-09-19 11:25:56 +08:00

2.0 KiB
Raw Permalink Blame History

UI Bridge v1

加载方式

宿主为每次打开配置页创建短时 UI 会话:

/api/v1/plugin-ui/<asset-token>/index.html#bridge_token=<bridge-token>

资源 Token 用于读取包内 ui/ 文件,Bridge Token 只存在于 URL fragment,不会发送到服务器。iframe 使用 sandbox="allow-scripts",不授予 allow-same-origin。

UI 只能加载包内、已在清单声明的资源。CSP 禁止外部网络连接、表单提交和外部 frame。

消息信封

UI 到宿主:

{
  "source": "sub2api-plugin-ui",
  "bridge_token": "TOKEN",
  "type": "config.load",
  "request_id": "UNIQUE_ID"
}

宿主到 UI:

{
  "source": "sub2api-plugin-host",
  "bridge_token": "TOKEN",
  "request_id": "UNIQUE_ID",
  "ok": true
}

方法

type UI 参数 成功响应
sub2api.plugin.ready 无 无响应
config.load 无 config
config.save config 对象 规范化后的 config
config.test 无 result
plugin.status 无 result(Health:{healthy, message, status_json})
ui.resize height 无响应
ui.notify level、message 无响应

config.test 在 v1 中测试已保存配置(需二次验证,可产生副作用)。UI 若要测试当前表单,应先调用 config.save。

plugin.status 是只读运行时状态通道:无副作用、免二次验证、不弹宿主提示,供状态面板轮询。它映射到插件 Health,result.status_json 是插件自定义的不透明 JSON 快照。带状态展示的插件应使用它,而不是把 config.test 当作状态轮询。

必须执行的校验

UI 接收消息时必须验证 event.source === parent、消息来源标识、Bridge Token 和等待中的 request_id。每个请求必须有超时和卸载清理。

宿主不会向 iframe 提供管理员 Token。插件 UI 不得尝试访问管理 API、Cookie、父页面 DOM 或浏览器存储中的宿主数据。