架构总览
Weftale 的架构可以压缩成一句话:构建期焊死的根骨架,加上运行期可变的扩展单元。根骨架由根插件名单(RPM)确定,运行期只装载小插件、数据包、资源包与 Mod。理解这个分界,后面的所有机制都是它的推论。
相关页面:大插件与小插件、根插件名单(RPM)、装载管线与 guard、大插件总表。
分层总览
┌─────────────────────────────────────────────────────────────┐
│ 启动层 src/boot/ │
│ 读取并核验 rpm.json → 导入 Kernel → 选择宿主 → 交出控制面 │
└───────────────────────────┬─────────────────────────────────┘
│ 启动即一次根结构装载
┌───────────────────────────▼─────────────────────────────────┐
│ Kernel 根插件 kernel@1 │
│ 装载器、guard、版本求解、capability 注入、清单与报告 │
└───────────────────────────┬─────────────────────────────────┘
│ 同一套装载管线
┌───────────────────────────▼─────────────────────────────────┐
│ 大插件(根插件集合,构建期固定) │
│ Platform / Asset / ScriptPlay / Stage / Audio / Text / ... │
│ 每个大插件是一棵不可变的 Cordis 子树 │
└───────────────────────────┬─────────────────────────────────┘
│ ctx.plugin() 挂载分项
┌───────────────────────────▼─────────────────────────────────┐
│ 小插件(实现位条目)· 数据包 · 资源包 · Mod(写边) │
│ 运行期装载,可替换、可卸载;受 RPM 与 policy 约束 │
└─────────────────────────────────────────────────────────────┘宿主差异不在这条主链上,而是被启动层选中后注入:
同一份 src/core 与 src/shared
│
├─ src/host/web/ 浏览器后端(Blob URL、IndexedDB、文件选择器)
└─ src/host/tauri/ Tauri 后端(IPC、原生文件、独立信任库)设计上共 16 个大插件;当前 11 个已有实现:Kernel、Save、Translate 为已完成,Platform、Battle、Author 为实现中,Asset、ScriptPlay、Stage、Audio、Text 为测试中。其中 Author 只进入 editor 目标的 RPM,runtime 目标登记其余 10 个;5 个仍在规划中、不进入 RPM。逐个契约见大插件总表。
各层职责
| 层 | 位置 | 职责 | 不该做什么 |
|---|---|---|---|
| 启动层 | src/boot/main.ts、src/boot/trust.ts | 核验产物、导入 Kernel、选择宿主、交入信任绑定与控制面 | 不承载功能逻辑,不成为可扩展单元 |
| Kernel | src/core/kernel/ | 装载与卸载、准入判定、契约与版本求解、能力注入、只读报告 | 不提供业务功能,不对外暴露「接收代码并挂载」的接口 |
| 大插件 | src/core/<id>/ | 承担一个功能单位,声明服务、机制插槽、实现位与 registry | 不互相 import,不把内部子插件交给外部单元 |
| 小插件 | 扩展包内 code/ 入口 | 在实现位登记分项实现、订阅通知、只读查询 | 不新增实现位,不绕过装载器挂载子树 |
| 宿主实现 | src/host/web/、src/host/tauri/、src-tauri/ | 提供文件、网络、存储、原生能力与信任存储绑定 | 不把宿主差异泄漏进核心层 |
核心层的运行环境约束
src/core/ 与 src/shared/ 只依赖浏览器能力,不 import Tauri 或 Node API,不判断运行环境,不做编译期条件分支。运行环境只在启动层 src/boot/ 判断。宿主做不到的能力如实报「不支持」,不用近似行为冒充。
启动时序
- 启动层以
no-store读取rpm.json,先做形状校验;出现不认识的字段即按拒绝处理。 - 核对
buildChannel与编译期常量一致,核对manifestHash与产物内嵌常量及重新计算的结果一致。 - 读取 Kernel 入口字节,计算 SHA-256,与 RPM 中
kernel的entryHash比对;不符即拒绝启动。 - 导入 Kernel,由 Kernel 用同一个 guard 判定其余根插件;契约版本与入口哈希任一不符即拒绝启动。
- 选择宿主。Tauri 下先执行宿主启动握手,上报
buildId与manifestHash;不符时关闭全部原生路由。 - 根插件就绪后,按 RPM 登记装载内置包,再把控制面交给内置外壳;控制面不注册进
ctx。
核验细节见根插件名单(RPM),判定与拒绝细节见装载管线与 guard。
横切关注点
| 关注点 | 主要落点 | 作用 |
|---|---|---|
| 契约版本 | contract.ts、src/shared/contract.ts | 声明兼容承诺;guard 接受 [current-1, current] |
| policy 与写边 | src/shared/slots.ts、src/core/kernel/loader.ts | 决定谁能写、写到哪、卸载时如何撤销 |
| 准入判定 | src/core/kernel/guard/judge.ts | 纯函数三态裁决:允许、拒绝、待用户裁决 |
| 机械校验 | src/core/kernel/inspect.ts、manifest.ts | 清单形状、文件表、归档哈希、签名事实 |
| 信任与签名 | src/host/*/trust-store.ts、src/shared/trust-types.ts | 四态判定、TOFU、撤销与同意记录 |
| capability | src/host/*/backend.ts、src/shared/host-types.ts | 按单元清单与宿主可用性发放能力 |
| 预算 | src/core/kernel/guard/judge.ts | 归档、单文件、文件数与总量上限 |
| 隔离运行 | src/isolation/、src/shared/isolated-realm.ts | 翻译器与二进制编解码器的独立运行边界 |
| 观测与报告 | src/core/kernel/loader.ts | 拒绝原因、挂起、外来子树与动态代码留痕 |
同 realm 的实际边界
必须明确:除隔离运行的翻译器与编解码器外,Kernel、大插件、小插件与 Mod 都运行在同一个 JavaScript realm 内,框架不提供通用的技术隔离,也不存在沙箱。
RPM、guard、slot 白名单与写边裁剪是装载流程与声明层面的约束:它们能机械判定「声明了什么、落点是否在名单内」,能在装载后核验「声明过的写边是否真的发生」,但无法阻止同一 realm 内已经运行的代码经 ctx.root 等途径绕过约定、修改原型或使用 eval。动态代码只能留痕,不能宣称已阻止。用户修改自己本地的产物同样不在守护范围内。
真正的硬边界只有三类:宿主持有的 capability、不可信代码的独立 realm、远端信任链。不要把 guard 当成沙箱,也不要以「通过 guard」论证代码安全。
源码目录地图
| 路径 | 内容 |
|---|---|
src/boot/ | 外壳入口与信任页入口;唯一判断运行环境、唯一引入 Cordis 运行时的地方 |
src/core/<id>/ | 每个已有实现的大插件;含 contract.ts、index.ts、README.md 与内部实现 |
src/core/kernel/ | 装载器、guard、清单解析、包读取、编解码代理与原因码接线 |
src/shared/ | 跨模块纯函数、契约类型、RPM 形状、IR、JCS、哈希与插槽基类 |
src/host/web/ | 浏览器宿主:Blob URL、文件选择、IndexedDB 信任存储 |
src/host/tauri/ | Tauri 宿主:IPC、原生文件、独立信任库与调试上报 |
src/shell/ | 导航驱动的内置外壳:主页、独立设置、播放区、皮肤引擎与翻译看板 |
src/trust/ | 信任页界面、裁决弹窗与内置字体 |
src/isolation/ | 隔离运行的启动页与 Worker 引导 |
src-tauri/ | Rust 宿主:路由、外部包、写出器、信任存储与编译期常量 |
build/ | Vite 构建插件:RPM 生成、内置包、隔离页、发布产物扫描 |
schema/ | 剧本 IR 的 JSON Schema |
test/ | 契约测试、宿主冒烟、界面测试与最小夹具 |
builtin/ | 随产物发布的原创示例包 |
acgcore/ | 与内容无关的 Rust crate:ZIP、HCA 解码、字体子集化 |
阅读路径
| 你的目标 | 建议顺序 |
|---|---|
| 第一次了解框架 | 本页 → 大插件总表 → 四档扩展模型 |
| 要写插件或 Mod | 大插件与小插件 → 插槽与实现位 → policy 与写边 → 分发包与包结构 |
| 要读或改框架代码 | 本页 → 根插件名单(RPM) → 装载管线与 guard → 接口命名规范 |
| 关心安全与信任 | 信任与签名 → 装载管线与 guard → 隔离运行 |
| 要排查启动失败 | 根插件名单(RPM) → 装载原因码 → 故障排查 |