核心类型定义
@aalis/core 导出的是运行时基础设施与事件扩展点 AalisEvents。业务服务接口、消息、工具、命令等一律在 @aalis/api-* / @aalis/schema-*,类型随服务描述符走,core 不持有领域词汇。
源码: packages/core/src/index.ts(值导出定格见 test/core/purity.test.ts);类型按分层散在 types/、composition/、infrastructure/、orchestration/。
一律从包根 @aalis/core 导入。package.json 的 exports 只开放包根与 @aalis/core/package.json(读版本号用),@aalis/core/dist/… 等深路径报 ERR_PACKAGE_PATH_NOT_EXPORTED(定格见 test/core/package-exports.test.ts)。
领域接口请到对应契约包查阅,文档入口:api 包 与 服务。
插件定义
interface PluginMeta {} // core 内字面为空;额外字段由契约包 declaration merging 挂上
interface PluginDefinition<U = {}> extends PluginMeta {
name: string;
displayName?: unknown; // 展示值,core 原样转交
subsystem?: string;
uses?: U;
provides?: ServiceDescriptor<any, any>[];
reusable?: boolean;
apply(caps: BoundOf<U>): void | Promise<void>;
}
function definePlugin<U extends object = {}>(
definition: PluginDefinition<U> & { uses?: CheckedUses<U> },
): PluginDefinition<U>;name 须为 trim 后非空的字符串,不含 :suffix(只用于 instanceId),也不能是 __proto__ / constructor / prototype(只保证 id 写进普通对象当键时安全)。
uses 逐项核对:某一项不是描述符(也不是 optional() 的返回值)时,编译错误只落在这一项上,其余绑定照常推导,apply 里不会连带出现「类型为 never」的报错。
PluginMeta 增强
core 对 PluginMeta 的字段零感知,只原样带在定义上:
// @aalis/schema-config:配置表单是插件配置的唯一声明来源
declare module '@aalis/core' {
interface PluginMeta {
configSchema?: ConfigSchema;
}
}
// @aalis/api-webui:仅用于前端展示
declare module '@aalis/core' {
interface PluginMeta {
extends?: ExtendDeclaration; // { events?: string[]; hooks?: string[] }
}
}写 definePlugin({ configSchema, extends, … }) 时,对应包必须在编译图里(值导入或 import type {}),否则字段在类型上不存在。core 不解释 configSchema:默认值回填与按 schema 裁剪未知字段属宿主政策(@aalis/runtime)。
注册表条目
type PluginState = 'pending' | 'activating' | 'active' | 'disabled' | 'disposed' | 'error';
interface PluginEntry {
definition: PluginDefinition;
instanceId: string;
config: Record<string, unknown>;
state: PluginState;
error?: string; // 由 failure 现算
failure?: unknown; // 激活失败时抛出的原值
}
type CoreFailureCode = 'required-retry-exhausted' | 'provides-not-registered' | 'exclusive-conflict' | 'service-unavailable';
function parseInstanceId(instanceId: string): { moduleName: string; suffix?: string };公开类型不声明内部激活记录。getPlugin() 交出调用时刻的浅快照:之后的状态变化不改它,要最新的就再调一次或看 getStatus(),写它也进不了注册表;config 与 definition 仍是运行中的同一对象,只读,状态与配置变更须经管理 API。状态摘要 PluginStatusEntry 同样带 error 与 failure,另含 provides / reusable,以及激活超过 slowThresholdMs 仍未完成、已转入后台(state 为 activating)时的 slow: true、旧实例关完仍有工作没落定(停下之前同一 id 不起新实例)时的 lingering: true(否则都不给);uses 是完整声明的快照,每项为 { key, service, kind: 'required' | 'optional' },保留参数别名,零声明为 []。Core 基础服务也计入。配置详情经 getPlugin(instanceId) 从 entry.config / entry.definition 读取。
描述符与绑定
interface ServiceDescriptor<P, B = P> {
readonly name: string;
bind(port: BindingPort<P>): B;
}
interface ServiceSelection<B> {
list(): ProviderEntry<B>[];
readonly use: B;
of(id: string): B;
readonly present: boolean;
follow(attach: (handle: B) => FollowCleanup): () => void;
}
interface ProviderEntry<B> {
readonly id: string;
readonly label?: unknown;
readonly priority: number;
readonly selected: boolean;
readonly basis?: SelectionBasis; // 'plugin' | 'global' | 'rank'
readonly use: B; // 钉在这一条登记上
}
interface ServiceView<T = unknown> {
instance: T;
contextId: string;
priority: number;
label?: unknown;
}
interface BindingPort<P> { /* id, identity, logger, present, provider, follow, track, registrar */ }
interface Registrar<Item> {
add(item: Item): () => void;
}
function defineService<P>(name: string): ServiceDescriptor<P, P>;
function defineService<P, B>(name: string, bind: (port: BindingPort<P>) => B): ServiceDescriptor<P, B>;
function optional<P, B>(descriptor: ServiceDescriptor<P, B>): OptionalUse<P, B>;P 是提供者形状,B 是业务层:不给 bind 时 B 就是 P,业务层是按 P 转发的活句柄。自定义 bind 要在转发之上加或改成员,写 Object.assign(Object.create(port.provider), { ... })。不要对象展开——展开看不到提供者的成员。ServiceView 是 services.all 返回的原始实例投影;选择层的 list() 给 ProviderEntry。
ProviderOf<D> / BoundOf<U>(每项声明一个 ServiceSelection)/ CheckedUses<U> / Uses 是推导载体。OptionalUse<P, B> 是 optional() 的返回类型,FollowCleanup(void | (() => unknown))是 follow 回调的返回类型,SelectionBasis 是选中依据,三者都从包根导出。详见 service.md、hub-services.md。
BindingPort.identity 是这次激活的不透明资源身份(symbol),即调用方身份,见 资源身份。
ServiceInfo 是无实例的登记元数据:contextId、priority、可选 label、exclusive: boolean、selected: boolean,选中的那一条另带 basis。由 services.inspect(key, { for? }) 返回,顺序与选中按所查口径(给 for 为那个插件,不给为全局)。
基础服务与宿主服务
值导出(插件放进 uses):events、lifecycle、logger、config、provide、services。hooks / contributions 不在 core,从 @aalis/api-hooks / @aalis/api-contributions 导入。
宿主服务:appService、pluginsService。两类都由根激活经 provide 独占登记,共用同一套服务协议,都须显式 uses;上面六项的提供者按调用方激活交出接口,见 内置服务的登记。配置文档的 hostConfig 在 @aalis/api-host-config,由宿主提供。
interface LifecycleCap {
readonly id: string;
readonly signal: AbortSignal; // 取消信号:时机见 context.md 的 lifecycle 一节
onDrain(fn: () => void | Promise<void>, label?: string): () => void;
onDispose(fn: () => void | Promise<void>, label?: string): () => void;
}
interface ProvideOptions {
priority?: number;
exclusive?: boolean;
label?: unknown; // 展示值,core 原样转交
entryId?: string;
}
type Provide = <D extends ServiceDescriptor<any, any>>(
descriptor: D,
implementation: ProviderOf<D>,
options?: ProvideOptions,
) => () => void;AppService / PluginManagerService 见 app.md、plugin.md。六个管理动作返回 Promise<boolean>:正常运行中 false = 主体不在注册表或被状态 / 政策挡下(含定义或实例 id 校验失败),true = 请求已受理,含幂等;正常运行中已在途的 unload 仍 join。自 beginShutdown() 起新发起的六个动作都立即返回 false,不改条目状态或配置,也不加入额外拆卸;已有停机计划负责清理,完整完成信号是 app.stop()。正常运行中激活是否落定看 idle()。
扩展点
core 的扩展点只有 AalisEvents(core 自持基础设施事件,从来不空)。服务没有类型表——类型随描述符走。钩子与贡献点的扩展点随各自的契约包,增广目标分别是 declare module '@aalis/api-hooks' 与 declare module '@aalis/api-contributions'。
| 扩展点 | 所在包 | 含义 | 谁注入 |
|---|---|---|---|
AalisEvents | @aalis/core | 事件名 → 参数元组 | core 自持 service:* / plugin:* / app:*;业务事件由 -api 注入 |
HookContextMap | @aalis/api-hooks | 钩子名 → 中间件上下文 | 契约包内字面为空;api-agent / api-gateway / api-memory 等注入 |
ContributionPointMap | @aalis/api-contributions | 贡献点名 → spec(须含 id: string) | 如 api-agent 的 agent:prompt |
事件目录以 events.md 为准。谁注入了哪一族业务事件 / 钩子 / 贡献点,见 扩展点索引。
interface AalisEvents {
'service:changed': [name: string];
'plugin:loaded': [instanceId: string];
'plugin:unloaded': [instanceId: string];
'plugins:changed': [];
'app:ready': [];
'app:started': [];
'app:restarting': [];
'app:stopping': [];
}AalisEvents 类型封闭(没有 [key: string] 兜底)。动态事件名走模板字面量签名,见 events.md。
配置与日志
core 不持配置文档,也不导出配置类型;插件自己的配置视图是内置服务 config(Readonly<Record<string, unknown>>)。配置文档类型 AalisConfig 与读写面 HostConfig 在 @aalis/api-host-config,runtime 的 ConfigStore / ConfigProvider 见 运行态与配置文档。
表单词汇(ConfigSchema / SchemaField / …)在 @aalis/schema-config。能力词汇(CapabilityVisibility 等)在 @aalis/api-authority。
日志接口与通道:Logger / LogHub / DefaultLogger,日志记录类型 LogEntry / LogLevel。LogHub 的单个监听器抛错(含返回被拒的 Promise)不影响其余监听器,也不让日志调用抛出;监听器本身就是日志的去处,它的错误不再上报。DefaultLogger 把附加参数渲染到消息末尾:错误对象输出 stack,其后沿 cause 逐层另起一行、以 [cause] 名称: 消息 开头(至多 5 层,循环引用与超出层数时末行写明),AggregateError 另列 [errors] N 项 并逐项缩进列出(至多 10 条),多行消息原样续行;只有最外层带 stack,不展开错误对象的其它属性。行编解码 formatLogLine / parseLogLine 由 @aalis/schema-log 提供,它以 peer 依赖引用 Core 的记录类型。
编排与宿主 SPI
App / AppOptions / createApp;PluginEntry / PluginState / parseInstanceId;PluginRegistration(app.pluginAll 的条目);RestartStrategy。插件加载器 PluginLoader / PluginDescriptor 在 @aalis/runtime,插件包入口判定 pluginDefinitionOf 在 @aalis/api-plugin-source。
钩子的 Hooks / MiddlewareFn / MiddlewareNext 与贡献点的 Contributions / ContributionSpec / ContributionHandle 见 api-hooks、api-contributions。