Files
tick-stock-panel/docs/extension-packages.md
T
shy3130 ffe1ff0d3e feat(import): 统一导入备份入口并支持后端扩展包
集中处理策略与定义、配置备份、数据源和页面插件导入,保留旧入口跳转。新增可信后端及前后端完整包的预检、暂存、重启生效、失败回退和版本管理。

验证:扩展、资源、备份与页面定向 pytest 通过,前端 41 项测试及生产构建通过,并完成桌面、窄屏和明暗主题联调。

Signed-off-by: shy3130 <shy3130@qq.com>
2026-11-01 20:01:59 +08:00

5.9 KiB
Raw Permalink Blame History

统一导入与外部后端扩展包

入口是「设置 → 导入与备份」(/settings?tab=import)。策略、因子、信号页的小盒子,以及数据源的「安装插件」都会进入同一页面。旧配置备份和页面插件链接继续重定向到这里。

导入与管理

选择或拖入文件后,先自动识别、预览,再确认写入:

  • 策略 .py、信号/因子 .json 和资源 ZIP 可混合多选;复用原有依赖闭包、冲突比较、批次回滚和缓存刷新。
  • tick-config-backup 配置备份按类别恢复。每次新预览都默认不选择密钥和访问凭证;需要迁移 API Key 时明确勾选。
  • 根目录有 plugin.yaml 的数据源包继续使用 Provider 安装契约。安装后在「已安装扩展」配置 Key、验证并选择数据能力;不会自动切换行情来源。
  • .js/.mjs 页面产物、单个 .tsx 或本项目已有源码页面继续使用 Page Pack SDK。确认信任和同名替换,通过浏览器加载校验后刷新生效。源码编译仍受现有部署环境限制。
  • 根目录有 extension.yaml 的 ZIP 使用下述后端扩展契约,可同时包含配套前端页面。安装仅暂存,重启主程序后生效。

「创建配置备份」和「批量导出资源」保留原有范围,不包含后台扩展的安装文件。行情数据、K 线和回测缓存不包含在配置备份中。外部数据源与后端扩展请单独保留原 ZIP。

后端 / 前后端完整包

ZIP 根目录直接放清单,不额外套目录。每包一个后端模块,可选一个自包含页面 ES 模块:

research.zip
├── extension.yaml
├── backend/
│   ├── __init__.py
│   └── extension.py
└── frontend/
    └── extension.mjs
format: tick-extension-package
format_version: 1
id: example.research
display_name: 研究观察工作台
version: 1.0.0
extension_api_version: 1
author: 作者声明
description: 自定义研究服务与配套页面
backend: backend.extension
frontend: frontend/extension.mjs  # 纯后端扩展省略此项
requires_app: '>=0.3.25'
requires_python: '>=3.11'
platforms: [any]
requires: []  # 仅检查已有依赖,不运行 pip/npm

id 为小写字母开头的字母、数字、下划线,可用点或连字符分段,最长 80 字符;official.*、core.* 保留。版本如 1.0.0;相同版本不同内容拒绝覆盖。更新必须提高版本,降级使用回退操作。

后端模块沿用 app.extensions 的真实契约:

from fastapi import APIRouter
from app.extensions import BACKEND_EXTENSION_API_VERSION

EXTENSION_ID = "example.research"
EXTENSION_API_VERSION = BACKEND_EXTENSION_API_VERSION

def setup(registrar):
    router = APIRouter(prefix="/api/extensions/example.research")

    @router.get("/status")
    def status():
        return {"ready": True}

    registrar.include_router(router)

def startup(context):
    # 可选;核心仓库准备完成后运行。
    # context 提供 api_version、data_dir、只读 repository 协议。
    pass

setup / startup 是同步函数。可注册 HTTP 路由和 NotificationFormatter,不支持替换核心引擎。外置接口必须位于 /api/extensions/<包id>/,不能覆盖核心或其他扩展,不接受 WebSocket 路由。初始化使用 startup(context),不要依赖路由器自身的 lifespan。

配套页面使用 Page Pack SDK v1,default.id 与包 id 相同。用户确认信任后,浏览器先加载候选页面检查导出契约,成功才提交安装;预览阶段不执行 JS 或 Python。页面路由最终由宿主注册表检查,启动时发生冲突会显示在「已安装扩展」,需修正包后重新安装。

生效与失败隔离

安装内容位于 data/extensions/<id>/versions/<version>/,状态原子写入 state.json。限 20 MiB 压缩包、80 MiB 解压总量、1000 条目;拒绝越界路径、重复/大小写冲突、符号链接、原生库、wheel 和安装脚本。不写入程序源码目录。

启动时验证文件摘要、兼容性、ID、接口命名空间和注册冲突,再运行启动钩子。成功后才发布路由、通知格式化器和配套页面。新后台失败时保留原版本,新页面不会先切换;单个扩展错误不阻断主程序或其他扩展。

启停、回退、更新和卸载在下一次主程序启动时应用;浏览器刷新不能替代后台重启。停用中回退不会自动启用。旧页面可能保留在已打开标签中,后台重启完成后需刷新浏览器同步。

失败隔离覆盖已提交的路由、策略注册与安装状态;可信代码自行产生的文件、网络等副作用无法自动撤销。扩展与主程序同权限,不是沙箱。管理使用面板登录会话,不向开放 API Token 授权;无密码时仅接受本机同源管理。

首版面向单进程部署;多 worker 应全部停止后统一维护和重启,不提供跨 worker 在线切换。升级后仍需满足包的兼容范围。

API

请求 行为
POST /api/import-center/inspect 多文件 files,只读识别并委托既有预检
GET /api/extension-packages 安装、运行、待生效版本与错误
POST /api/extension-packages/install file/digest/revision/trusted=true,重新校验后暂存
POST /api/extension-packages/frontend 信任后读取候选页面供浏览器校验,不发布
POST /api/extension-packages/{id}/manage enable/disable/rollback/cancel-update/remove
POST /api/import-center/page 页面上传/编译,增加摘要、信任和同名替换确认
POST /api/import-center/project 信任后编译现有项目页面,保留同名确认

配套页面复用 /api/ext-pages 清单与分发,标记 managed_by,只在对应后台版本就绪时提供。启停和卸载通过整包管理,不能拆开修改。