Appearance
插件运行时契约规范
定位
NEXA 产品工程只集成组件渲染、事件、状态、数据、命令、服务发现和生命周期等基础能力。跨组件联动、数据处理和产品业务流程由插件实现。组件不得直接引用其他组件,插件不得直接访问 Vue 实例、Pinia Store、Cesium Viewer 或产品内部路径。
插件数据分为两类:
PluginManifest:插件注册表保存的版本化声明,描述制品、依赖、权限、阶段和失败策略;ProductPluginPlan:某个产品发布使用的插件装配快照,锁定精确版本、不可变入口、完整性摘要和实例配置。
数据库不得保存函数、表达式或已实例化对象。插件实现以不可变 ESM 制品发布,数据库只保存制品引用及可验证 JSON。
启动与渲染顺序
Runtime 必须按以下流水线执行:
- 获取并校验产品组件装配数据;
- 获取并校验插件计划及每个插件 Manifest;
- 校验 Host Contract、精确版本、SRI、配置 Schema、依赖、权限和组件能力约束;
- 构建插件依赖有向图,发现缺失依赖、循环依赖或跨阶段逆序时立即失败;
- 按固定阶段执行插件并推进组件渲染;
- 产品卸载时按激活顺序的逆序释放插件。
固定阶段顺序:
text
bootstrap
→ before-components
→ 加载组件制品
→ components-ready
→ 挂载布局与 Renderer
→ after-render
→ interactive同一阶段内采用稳定拓扑排序:
requires.plugins、after和before形成有向边;- 当前可执行节点按
priority从小到大选择; - 优先级相同时按插件实例 ID 字典序选择;
- 依赖缺失、环、重复实例 ID和指向自身均为装配错误;
before/after只能引用同阶段插件,跨阶段关系由阶段顺序表达。
上下文与权限
Runtime 为每个插件创建独立 PluginContext,并依据 Manifest 对端口做最小权限裁剪:
events:发布和订阅白名单事件;state:读取、写入和订阅命名空间;services:发现并调用 Capability;components:梳理组件快照、发送受控命令,并按组件实例 ID 绑定运行时 Props 与事件;data:通过命名数据源查询、变更或订阅数据;commands:执行宿主已注册命令;lifecycle:登记清理函数;logger:记录带插件身份的结构化日志。
未声明的上下文能力必须拒绝访问。端口返回 unknown,插件必须自行校验外部数据,禁止用泛型断言伪造服务返回类型。
失败规则
abort-product:关键启动插件失败时终止产品启动并回滚已激活插件;skip-plugin:记录错误并跳过该插件及所有硬依赖它的插件;continue:只适用于无下游硬依赖的增强插件;- 每个插件必须设置
timeoutMs,超时后中止其AbortSignal; - 任一插件失败都不得留下事件订阅、定时器或服务注册。
TypeScript 契约和 JSON Schema 位于 @nexa/component-contracts,是接口、数据库和 Runtime 的共同真相源。
当前落地范围
第一阶段运行时已位于 products/tactics-sim-engine/src/runtime/plugins/,内置插件位于产品的 src/plugins/。当前已经实现计划与装配版本绑定、制品锁一致性、Host Contract、插件版本依赖、组件能力依赖、稳定拓扑排序、权限裁剪、超时、失败策略和逆序释放。
当前已落地十个内置插件:
viewer-host是优先级最高的默认基础插件,绑定earth-viewer生命周期,通过viewer-hostCapability 完成 Viewer 能力初始化、场景恢复与释放,并发布viewer.ready;spatial-environment在 Viewer 就绪后通过空间环境 Capability 管理底图与地形,把纯快照和操作意图绑定到对应面板;面板与插件均不持有 Viewer;entity-selection接管实体选择联动:基础组件只发布entity.selected,插件归一化选择状态,直接绑定entity-props的 Props 和update:entity事件,并通过数据端口回写实体;schema-form-routing依赖实体选择插件,根据场景节点和 Action 选择在元数据、时钟、动作三种表单模式间切换,直接绑定schema-form的 Schema、模型、上下文和更新事件。workspace-interaction只绑定场景树和实体列表,负责工作区选择传递;camera-workflow通过 Camera Capability 完成快照捕获、飞行、漫游和停止,插件不获取 Cesium Viewer;scene-workflow接管场景生命周期命令;entity-workflow接管实体创建及实体删除时的 Action 渲染清理;action-workflow接管活动创建、删除及其渲染清理;timeline-orchestration绑定时间轴数据和选择事件,并在 Viewer 就绪时启动时间执行同步。
面板拖拽和重挂载不再创建或销毁这些业务订阅。插件启用数据来自产品内置 Manifest 注册表,不依赖远程契约或产品装配文档。
上述插件通过 context.data 访问 scenario.entities、scenario.actions、scenario.metadata 和 scenario.clock。宿主的数据源注册器将这些语义化端口映射到 Pinia/Cesium,插件既不导入 Store,也不持有 Viewer,并会校验所有 unknown 返回值、丢弃过期异步结果以及在卸载后停止写入状态。
entityPropsAdapter.ts、schemaFormAdapter.ts、cameraPanelAdapter.ts、timelinePanelAdapter.ts、earthViewerAdapter.ts 与 remoteComponentAdapters.ts 已删除。RemoteRendererHost 只合并组件声明 Props 与插件绑定,不识别 Earth Viewer,也不执行组件专属初始化。后续组件迁移应扩展稳定 Capability Port 或数据源,再由插件编排,不再建立“一组件一个 Adapter”。
当前内置插件不使用配置。带 configSchema 的远程插件在接入插件注册表和 JSON Schema 校验器之前不得启用;数据端口也会拒绝访问尚未注册的数据源。