Skip to content

核心类型定义 ​

@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 包 与 服务。


插件定义 ​

typescript
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 的字段零感知,只原样带在定义上:

typescript
// @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)。

注册表条目 ​

typescript
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 读取。


描述符与绑定 ​

typescript
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,由宿主提供。

typescript
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 为准。谁注入了哪一族业务事件 / 钩子 / 贡献点,见 扩展点索引。

typescript
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。

文档对应 dev@c4e046e41,core 0.21.0,构建于 2026-11-02
基于 MIT 许可发布