# cfapi.aog.cc 插件开发 · AI 索引 > 本文件是给 AI 编码助手的入口,不是宣传页。实现前先读“不可违反的事实”,再按目标选择唯一路线。文档核对日期:2026-11-05。 ## 先读 - 完整开发上下文:https://cfapi.aog.cc/docs/devcenter/llms-full.txt - 结构化机器上下文:https://cfapi.aog.cc/docs/devcenter/ai-context.json - 插件清单 JSON Schema:https://cfapi.aog.cc/docs/devcenter/schemas/plugin-manifest.schema.json - 唯一 API 合同(OpenAPI 3.1):https://cfapi.aog.cc/api/openapi.json - 公开契约(只含公开/插件接口,138 个操作,全部带 schema):https://cfapi.aog.cc/docs/devcenter/openapi.public.json - TypeScript SDK(由公开契约生成):https://cfapi.aog.cc/docs/devcenter/downloads/cfapi-sdk-ts.zip - Postman 集合:https://cfapi.aog.cc/docs/devcenter/downloads/cfapi-postman.json - 人类可读开发者中心:https://cfapi.aog.cc/docs/devcenter/ ## 不可违反的事实 1. 清单文件是 `plugin.json`,不是 `plugin.toml`。 2. `code` 仅允许小写字母、数字、下划线,1–64 位,必须与上传参数完全一致。 3. `local` 静态入口固定为 `index.html`;`entry` 不会改变页面入口。 4. 外部开发者(`external`)不能私有创建、上传或启用插件;只能向市场投稿。 5. 市场投稿用 `POST /api/market/upload?plugin_code=...`,`multipart/form-data`,文件字段名 `file`,上限 500 MB;私有安装才是 raw ZIP,上限默认 50 MB。 6. 市场批准不会自动安装、启用、部署或启动沙箱。 7. `POST /api/market/versions/{id}/set-current` 只切换市场当前版本指针,不会替换已部署文件或重启 remote 服务。 8. 插件代理只适用于有 `base_url` 的 `remote` 插件。读需要 `plugin.view`,写需要 `plugin.manage`。 9. 仅持有 `external` 身份不会自动获得任何插件权限码;API Key 的 scope 只是前置闸门,不能提权。 10. 前端包内绝不能放 API Key、插件密钥、`plugin.manage` 令牌。 11. 沙箱默认网络 `deny`、文件系统 `readonly`、超时 5000ms、内存 256MB、CPU 1000ms、并发 8、WASM 运行时 `wasmi`。 12. 平台已废弃 `openapi_extra.json` 作为事实源;不要把它当补充接口清单。 13. remote 验签使用按插件派生的 `X-Platform-Signature` / `X-Platform-Caller-Signature`。市场批准后原始提交者从 `GET /api/market/submissions/{code}/signing-secret` 取密钥;私有插件走 `GET /api/plugins/{code}/signing-secret`。绝不把密钥放前端。 14. 旧 `X-Platform-Token` 使用平台全局密钥,仅为兼容;新插件不要依赖它做外部验签。 15. 私有安装是 `POST /api/plugins/upload?code=`,Body 为 **raw ZIP**(`Content-Type: application/zip`);市场投稿才是 `POST /api/market/upload?plugin_code=` + `multipart/form-data` 的 `file` 字段。两者参数名不同,混用会得到 `400 missing field 'code'`。 16. 插件静态资源按**完整 URL** 缓存 7 天。改了 `app.js` / `style.css` 必须同时把 `index.html` 里的 `?v=` 递增,否则上传成功、接口 200,但线上继续跑旧文件。 17. 所有时间字段是 **UTC**,且不带时区后缀(例如 `2026-11-06T23:18:45` 表示 UTC,不是本地时间)。前端按本地时区展示时要自行转换。 18. 插件数据列表按 `doc_id DESC` 返回,**不按业务更新时间**;需要按时间排序请自行重排。单文档默认上限 256KB,整库备份请分片或走文件导出。 ## 两条路线 ### A. 外部开发者发布到市场 1. `POST /api/auth/login` → Bearer JWT。 2. 准备 `local`(ZIP,含 `plugin.json` 与 `index.html`)或 `remote`(`plugin.json` 含公网 `base_url`)。 3. multipart 上传 → 取 `download_url`。 4. `GET /api/market/captcha` → 回答算术题。 5. `POST /api/market/submit`(版本必须 `x.y.z` 且高于历史最高版本)。 6. 等待管理员用 `plugin.govern` 批准。 7. 用户安装是另一个动作:`POST /api/plugins/market/install`(需 `plugin.manage`)。 ### B. 内部高级开发者自建自用 `internal_advanced` 账号 → 注册或 raw ZIP 上传 → `enable` → local 页面 `/plugins/{code}/` 或 remote 代理 `/api/plugins/{code}/proxy/**`。 ## 插件层级(v1.10.130+,每个层级都支持全部协议) 层级:`cfapi` > **总插件平台**(depth=1) > **一级子插件平台**(depth=2) > **二级**(depth=3) > **三级**(depth=4) > …无限下级。 建模不是每个层级一张表,而是 `plugins` 上的四列:`parent_id` / `tree_depth` / `tree_path`(物化路径 `/42/94/95/`) / `is_platform`。 **两条硬规则** 1. 只有 `is_platform=1` 的节点能挂子节点;普通插件要当平台,先 `POST /api/plugins/{code}/platform`。 2. 上级对任意深度的子孙天然有管理权(越级),不需要逐层授权;`manage_mode=delegated` 只是把日常运维委托给子平台,**不剥夺上级越级权**。 **五个必用端点** | 目的 | 请求 | |---|---| | 看整棵树 | `GET /api/plugins/tree?root=&max_depth=3` | | 挂子节点 | `POST /api/plugins/{code}/children` `{"code":"l1_erp","kind":"api","is_platform":true}` | | 看全部后代 | `GET /api/plugins/{code}/descendants` | | 面包屑 | `GET /api/plugins/{code}/lineage` | | 改挂/防环 | `PUT /api/plugins/{code}/parent` `{"parent":"..."}`(挂到自己子孙下会被 400 拒绝) | **让子平台自己管自己**:`POST /api/plugins/{code}/tokens` 签发 `pscope` 令牌,它只能在该节点子树内增删改,越界 403,且恒非超管。 **接入形态 `kind`**:`api`(对端已有 API,零代码接入)/ `code`(只能改代码)/ `db`(只能连库)/ `native` / `wasm` / `sandbox`。 不要求对方有 API —— 这正是「万物皆可插件」的落点。 **协议面**:`GET /api/plugins/{code}/protocols` 返回该节点的 20 种协议入口。协议实现是**全局唯一翻译器 + 节点身份(code)**, 不给每个节点复制一套服务器;因此新增一个节点立刻拥有全部协议,且各层行为不可能不一致。 ## 数据库后端(平台自身,三种可切换) 插件仍然**禁止直连数据库**,数据只能走 REST(文档集合 / 键值 / 对象存储)。以下是排障用的事实: - 三种:**SQLite 3.46.0(默认,库文件 `app/var/data/cfapi.db`,WAL)**、MariaDB 11.8.6、PostgreSQL 18.6(端口 5433)。 - `.env` 里 `DATABASE_SQLITE_URL` / `DATABASE_MYSQL_URL` / `DATABASE_POSTGRES_URL` 常驻;`DATABASE_URL` + `DATABASE_TYPE` 表示当前生效。 - 切换:后台 `/qq123008/` → 数据库管理,或命令行 `bash scripts/db_port/cutover.sh sqlite|mysql|postgres`。切换自动「停写 → 快照 → 搬运 → 行级摘要校验(mismatch 必须 0)→ 改配置 → 重启 → 健康检查」,失败自动回滚。 - 查询当前后端:`GET /api/db-backend/status`(需管理凭证),返回 `dialect` / `server_version` / `table_count` / `production_ready` / `backends`(含 sqlite)。 - 写 SQL 的坑:MySQL `int(11)` 在 PG 是 `int4`、`tinyint` 是 `int2`,解码类型必须对齐(`bigint↔i64` / `integer↔i32` / `smallint↔i16`),否则 PG 拒绝解码而 MySQL 隐式放宽 → **静默失效**。 - `INSERT IGNORE` / `IF()` / `DATE_FORMAT` / `LIMIT a,b` 等 MySQL 语法在 SQLite 下会被运行时改写;PG 的 upsert 自增列必须写表名(`t.calls = t.calls + 1`)。 ## 何时不要使用本文档 - 不要为“任意插件自动运行”生成架构:平台没有这种能力。 - 不要生成 `plugin.toml`、`main.wasm` 自动入口假设。 - 不要声称已实现 seccomp、capability 裁剪、全站 CSRF、租户级并发等源码中无证据的机制。 - 不要假设市场目录里的 `local` 插件可通过 `/proxy` 调用。 - 不要通过降低权限或关闭安全闸门来“让流程跑通”。 ## 推荐提示词(直接复制给编码助手) > 你正在为 cfapi.aog.cc 开发插件。先读取 https://cfapi.aog.cc/docs/devcenter/llms-full.txt、`/api/openapi.json` 和 `plugin-manifest.schema.json`。实现前请声明:插件类型(local/remote)、账号层级、所需权限码、是否需要市场发布。不得使用 `plugin.toml`,不得在前端写入任何密钥,不得声称市场批准会自动运行插件。所有网络请求必须有超时、状态码分支和错误处理;remote 服务必须校验 `X-Platform-*` 签名。完成后按“上架前检查清单”逐项自检。