Skip to content

开放注册表协议(Open Registry Protocol) ​

版本:1.0

Qomicex 插件商店的 API 协议已抽象为开放标准,允许第三方实现兼容的注册表(镜像/私有仓库/内网定制源),启动器通过多源发现机制对接任意兼容实现。


1. 核心概念 ​

一个**注册表(Registry)**是一个 HTTP API 端点,提供插件元数据查询与分发。注册表有两种身份:

身份说明
主源(Primary)官方商店 plugins.qomicex.top,完整实现全部端点(含认证/审核/组织管理)
镜像(Mirror)第三方兼容实现,至少实现核心端点即可被启动器识别为可用源

启动器在 settings.registryUrl 中配置源列表,按优先级依次尝试。


2. 端点子集 ​

2.1 核心端点(镜像必须实现) ​

方法路径说明
GET/registry注册表元数据(§3),镜像自报能力与数量基数
GET/plugins?q&category&tags&sort&page&pageSize&minLauncherVersion插件市场列表(仅已发布)。返回 {total, page, pageSize, items[Plugin]}
GET/plugins/:slug插件详情 → Plugin + versions[](仅已发布:{id, version, sha256, sizeBytes, ...})。未发布或不存在返回 404
GET/plugins/:slug/versions/:version/download下载信息 → {url, mirrorUrl?, sha256, size}。:version 支持 latest 别名
POST/plugins/check-updates批量更新检查。Body {launcherVersion, installed:[{slug, version}]} → {updates[...]}

Plugin 对象(核心字段):{id, slug, name, description, category?, tags[], iconUrl?, latestVersion?, downloadsCount, ratingAverage?, ratingCount, createdAt}。

2.2 可选端点(镜像可不实现) ​

方法路径说明
GET/plugins/:slug/reviews?page&pageSize评价列表
POST/auth/*用户注册/登录/设备流
GET/orgs/*组织管理
GET/admin/*审核与管理员管理
GET/plugins/:id/stats插件统计面板

启动器对可选端点采用优雅降级:不可用时对应 UI 功能隐藏或禁用。

2.3 公共约定 ​

  • Base URL:注册表 API 根路径,如 https://plugins.qomicex.top/api/v1
  • 请求/响应:JSON,字段命名 camelCase;时间为 ISO 8601
  • 错误格式:统一 { "error": { "code": "...", "message": "..." } },HTTP 状态码语义化
  • 分页:page(从 1 起)、pageSize(默认 20,上限 50)
  • 缓存:插件列表建议 15s、详情建议 300s、注册表元数据建议 60s

3. 注册表元数据 GET /registry ​

注册表的身份牌。启动器发现 registryUrl 后发出的第一个请求即为此端点,用于确认兼容性:

json
{
  "apiVersion": "1.0",
  "baseUrl": "https://mirror.example.com/api/v1",
  "pluginCount": 42,
  "capabilities": ["list", "detail", "download", "check-updates"],
  "mirrors": ["https://cdn.mirror.example.com"]
}
字段类型必填说明
apiVersionstring✅协议版本号,当前 "1.0";启动器做 major 级比较(>=1 可对接)
baseUrlstring✅注册表 API 根,客户端据此构建后续请求。可不同于真实 host(CDN 回源)
pluginCountinteger✅已发布插件总数,启动器用于源质量评估(插件少可降权)
capabilitiesstring[]✅能力标记列表。核心:list、detail、download、check-updates;可选:reviews、auth、stats
mirrorsstring[]可选下载镜像域列表。仅含包体分发镜像,不含 API 回退源

mirrors 字段的镜像域用于竞速下载而非 API 回退。API 回退由启动器 registryUrl 多源列表控制。


4. 客户端发现机制 ​

4.1 配置方式 ​

启动器设置支持插件式多源发现:

registryUrl: [
  { url: "https://plugins.qomicex.top/api/v1",    primary: true,  priority: 1, enabled: true },
  { url: "https://mirror.example.com/api/v1",      primary: false, priority: 2, enabled: true }
]
  • 主源(primary: true):启动器默认查询的注册表
  • 备源(primary: false):主源不可达或超时时自动回退(备源为只读,写操作仅在主源尝试)
  • 优先级(priority):数字越小越优先

4.2 启动流程 ​

  1. 启动器对所有 enabled: true 的源并行发出 GET /registry
  2. 检测 apiVersion >= 1 且 capabilities 包含至少 list、detail、download → 标记为可用
  3. 按 priority 排序,选择第一个可用的为主源
  4. 缓存所有源的 pluginCount,界面中注明插件来源
  5. 主源连续失败 N 次后自动切换至存量可用源(如无可用则暂停轮询)

4.3 回退策略 ​

场景行为
主源 GET /registry 超时 / 5xx立即切备源
主源 GET /plugins 4xx透传错误给用户,不自动切源(请求合法但被拒绝)
主源连续 3 次请求超时标记为不可用,切备源
备源全部不可用停用商店功能,提示用户检查网络
写操作(安装/登录/评价)仅主源尝试,备源不执行写操作

5. 下载双通道与 SHA-256 校验 ​

5.1 双通道语义 ​

GET /plugins/:slug/versions/:version/download 返回:

json
{
  "url": "https://cdn.registry.example.com/plugins/my-plugin/1.0.0.qplugin",
  "mirrorUrl": "https://mirror-cdn.example.com/plugins/my-plugin/1.0.0.qplugin",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "size": 4096
}

启动器竞速下载:同时发起主 URL 与镜像 URL 的请求,取先完成者。无论使用哪个 URL,都必须按 sha256 校验完整性。

5.2 校验强制规则 ​

  • 下载完成后必须计算 SHA-256,与响应中的 sha256 比对(全小写 hex)
  • 不匹配 → 拒绝安装,且不留存篡改包
  • 镜像返回的 sha256 必须与主源完全一致——镜像不可修改包内容

5.3 镜像包体要求 ​

镜像重传包体时必须:

  • 保持包内文件结构完全不变(不可重打包、修改 manifest、增减文件)
  • signature.json、signature.cert.json 原样保留(签名链必须完整传递,接收方验签依赖包内证书)
  • 以 200 状态码返回,Content-Type: application/octet-stream 或 application/zip

6. 签名链要求(ADR-050) ​

开放注册表协议对签名的要求只针对包体完整性,不要求镜像自身提供签名验证服务:

角色签名要求
元数据 API(/plugins 等)镜像无需签名 API 响应,启动器以主源数据为准
包体重传镜像必须原样传递包内 signature.json + signature.cert.json,不可缺失或修改。接收方完全依赖包内签名链自行验证

6.1 包内签名链结构 ​

.qplugin 包内
├── manifest.json            # 规范化后参与 signedHash
├── signature.json           # Ed25519 签名
│   ├── alg: "Ed25519"
│   ├── signedHash: SHA-256(规范化 manifest + 文件清单)
│   ├── signerKeyId: "<key id>"
│   └── signature: "<base64 ed25519 sig>"
├── signature.cert.json      # 开发者证书(根钥签发)
│   ├── algorithm: "Ed25519"
│   ├── keyId / publicKey
│   ├── issuer: { keyId: "<根钥 id>" }
│   └── signature: "<base64 root sig>"
└── dist/…
  • 镜像不得重新打包,不得修改 signature.json / signature.cert.json 或包内任何文件
  • 镜像可在响应头附加额外校验摘要(如 X-Checksum-SHA256),但不可替代包内签名
  • 启动器收到包后先校验 Ed25519 签名再安装,镜像服务无需关心验签细节

7. 自建镜像指南 ​

7.1 方案 A:Cloudflare Worker 复制(共享负载) ​

最适合分担官方商店下载流量的场景:

  1. Fork / 部署 qomicex-plugin-store 仓库的 Worker 代码到自己的 Cloudflare 账号
  2. 配置专属 CDN_BASE_URL(R2 或外部存储)与 MIRROR_BASE_URL
  3. 周期性把主商店的插件数据同步到自己的 D1(wrangler d1 execute --file=sync.sql)
  4. 在启动器设置中添加 registryUrl: "https://你的域名/api/v1" 作为备源
  5. 下载流量指向你自己的 R2 / CDN

7.2 方案 B:纯静态托管(只读镜像) ​

如果只做只读缓存,无需 Worker 计算能力:

  1. 周期性抓取主商店的 GET /plugins 列表 + 各详情页,生成 registry.json 静态文件
  2. 把下载的 .qplugin 包上传到自己的 CDN / 对象存储
  3. 托管 registry.json 与下载文件在同一域下
  4. 提供静态 GET /registry 元数据端点(返回 registry.json 内容)
  5. 静态镜像只能提供核心读端点,不支持 check-updates(需要计算能力,capabilities 中如实声明)

7.3 方案 C:自建完整注册表(独立源) ​

运行自己的审核/组织/认证流程:

  1. 完整实现核心端点 + GET /registry
  2. 可选实现 auth、reviews 等端点(capabilities 中如实声明)
  3. 配置自己的签名根公钥(PLUGIN_ROOT_PUBLIC_KEY),开发者上传公钥获证书后签名上传
  4. 客户端配置 registryUrl 后即可作为完整独立源使用

7.4 验证镜像兼容性 ​

bash
# 1. 元数据端点
curl https://你的镜像/api/v1/registry
# 应返回: { apiVersion: "1.0", pluginCount: ..., capabilities: [...] }

# 2. 列表
curl https://你的镜像/api/v1/plugins?page=1&pageSize=5
# 应返回: { total, page, pageSize, items: [...] }

# 3. 详情
curl https://你的镜像/api/v1/plugins/<slug>
# 应返回 Plugin + versions[]

# 4. 下载信息
curl https://你的镜像/api/v1/plugins/<slug>/versions/latest/download
# 应返回: { url, sha256, size }

# 5. 包体校验
curl -o test.qplugin <url>
qomicex verify --package test.qplugin   # Ed25519 验签,主源镜像应同样通过

8. 启动器集成方案(TODO) ​

当前启动器后端 services/plugin_store.rs 使用固定的 QOMICEX_STORE_API_BASE 环境变量作为单源代理。多源集成的改动点:

层改动工作量
后端store_api_base() 改为按请求来源选择;store_get / store_post 增加 base_url 参数中
后端认证 token 存储改为按来源分键({registryId}-tokens.json)中
后端安装管线 install 接受来源参数小
后端新增 GET /store/registry 透传端点(代理上游 /registry)小
前端settings 增加 registryUrl 配置 UI(多源列表)中
前端api/pluginStore.ts 透传来源参数小

建议分步计划:

  1. 后端加 GET /store/registry 透传(独立小端点,不破坏现有语义)
  2. 后端 store_api_base() 参数化,按来源选择 base URL
  3. 前端设置页加 registryUrl 输入(可叠加多条)
  4. 安装/更新从指定源拉取;未指定时默认官方源

🚧 上述集成尚未实现,当前 launcher 仍为单源固定代理模式。本规范作为开放生态基础,由后续 PHASE 任务细化实施。