# MM微内核核心 **Repository Path**: qiuwenwu91/mm_kernel_core ## Basic Information - **Project Name**: MM微内核核心 - **Description**: 构建系统所用的微内核核心,提供给微内核使用。 - **Primary Language**: NodeJS - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-23 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # mm_kernel_core mm 微内核的**能力机制层**:注册、解析、上下文、加载、契约、策略、埋点、调用上下文,以及「隔离缝」与「消息面」的接口约定。 只提供机制,**不含任何策略决策,也不含线程 / 进程 / HTTP 实现**。零运行时依赖,CommonJS,Node.js >= 18。 ## 公开面与内部面 本包有两个入口,边界是刻意的: | 入口 | 内容 | 使用方 | |---|---|---| | `require('mm_kernel_core')` | 只导出统一错误族与码表 | 宿主与所有模块 | | `require('mm_kernel_core/internal')` | 28 项机制件 | 官方扩展包与架构层 `mm_kernel` | 上层只需 `instanceof KernelError` 一处判断即可捕获全部内核错误,机制件则收进内部面,**不属公开契约,版本间可能变更**。 ```js const { KernelError, CODES } = require('mm_kernel_core'); const { Registry, createContext } = require('mm_kernel_core/internal'); ``` ## 错误族 `KernelError` 是**唯一根类型**,每个错误都带 `code` 与 `retryable`,跨线程边界时这两个字段不得丢失。 | 类 | `code` | 触发条件 | 附加字段 | |---|---|---|---| | `KernelError` | `KERNEL_ERROR` | 根类型 | — | | `MasError` | 构造参数决定 | 消息平面错误(邮箱背压、寻址、请求-响应) | `details` | | `AbilityNotFound` | `ABILITY_NOT_FOUND` | 能力不存在 | `ability` | | `ModuleLoadError` | `MODULE_LOAD_ERROR` | 模块加载失败 | `module` / `cause` | | `AbilityConflict` | `ABILITY_CONFLICT` | 同名能力冲突,仅 `on_conflict: 'throw'` | `ability` / `existing` / `incoming` | | `ContractError` | `CONTRACT_ERROR` | 契约非法,或入参、返回值不符 | `ability` / `method` / `phase` / `errors` | | `PermissionDenied` | `PERMISSION_DENIED` | 策略拒绝 | `action` / `module` / `ability` | | `ScopeDisposed` | `SCOPE_DISPOSED` | 作用域已释放 | `scope` | | `AbortedError` | `ABORTED` | 调用被 `AbortSignal` 中止 | `ability` | `MasError` 提供静态工厂 `MasError.of(code, message, details)`。 ## 错误码表(`CODES`) 冻结对象,共 **29 个码**;`retryable` 表示「调用方是否值得重试」,是上层做退避重试的唯一依据。 | 分组 | code | retryable | |---|---|---| | 通用 | `KERNEL_ERROR` / `INVALID_ARGUMENT` / `INVALID_STATE` | 否 | | 能力平面:注册与解析 | `ABILITY_NOT_FOUND` / `ABILITY_CONFLICT` | 否 | | 能力平面:加载与生命周期 | `MODULE_LOAD_ERROR` | **是** | | 能力平面:契约与权限 | `CONTRACT_ERROR` / `PERMISSION_DENIED` / `SCOPE_DISPOSED` | 否 | | 能力平面:调用中止 | `ABORTED` | 否 | | 消息平面:参与者和寻址 | `DUPLICATE_PARTICIPANT` / `UNKNOWN_PARTICIPANT` / `NO_ROUTE` / `NO_HANDLER` | 否 | | 消息平面:邮箱背压 | `MAILBOX_OVERFLOW` / `MAILBOX_BYTE_LIMIT` | **是** | | 消息平面:邮箱背压 | `MAILBOX_STOPPED` | 否 | | 消息平面:载荷与请求-响应 | `PAYLOAD_NOT_CLONEABLE` / `DUPLICATE_REPLY` | 否 | | 消息平面:载荷与请求-响应 | `REQUEST_TIMEOUT` / `PENDING_LIMIT` | **是** | | 消息平面:停机 | `SHUTDOWN_TIMEOUT` | 否 | | 线程承载:worker 生命周期 | `WORKER_START_FAILED` / `WORKER_READY_TIMEOUT` / `WORKER_EXITED` | **是** | | 线程承载:worker 生命周期 | `WORKER_STOP_TIMEOUT` | 否 | | 线程承载:隔离缝 | `TRANSPORT_NOT_REGISTERED` | 否 | | 线程承载:通道 | `IPC_INFLIGHT_LIMIT` | **是** | | 线程承载:通道 | `IPC_CHANNEL_CLOSED` | 否 | ```js try { await ctx.ability.call('db', 'query', [sql]); } catch (err) { if (err instanceof KernelError && err.retryable) { // 背压、超时、加载失败等,可退避重试 } } ``` ## 内部面:机制件 `require('mm_kernel_core/internal')` 导出 28 项,按职责分组: | 分组 | 导出 | |---|---| | 能力注册表与记录 | `Registry` / `createRecord` / `matchFilter` / `createItem` / `canDelete` | | 模块上下文 | `createContext` / `createRef` | | 加载与生命周期 | `Loader` | | 能力代理与显式调用 | `createProxy` / `shouldWrapInProcess` / `createWrapProxy` / `callAbility` / `streamAbility` | | 契约 | `applyContract` | | 策略 | `normalizePolicy` / `checkPolicy` | | 调用上下文(ALS) | `getContext` / `currentCall` / `runWithContext` / `runWithCall` | | 埋点 | `normalizeTracer` / `getTracer` / `setTracer` / `startSpan` / `endSpan` | | 隔离缝 | `TransportRegistry` | | 消息面接口 | `assertMessagePort` / `createDisabledMessagePort` | ## 关键机制 ### 能力记录与注册表 `createRecord(impl, meta)` 归一化能力记录,补齐元数据默认值: | 字段 | 默认值 | 说明 | |---|---|---| | `impl` | 入参 | 能力实现;隔离能力为 `null` | | `isolation` | `in-process` | 隔离级别 | | `transport` | `null` | 该能力的承载适配器 | | `endpoint` | `null` | 隔离端通信端点 | | `module` | `null` | 注册方模块名 | | `permissions` / `tags` | `[]` | 权限点与标签 | | `description` / `schema` / `effect` / `version` | `null` | 元数据 | | `visibility` | `internal` | 可见性,供 `list` 过滤 | | `contract` / `contract_call` | `null` | 注册期编译出的契约与调用期校验模式 | `Registry` 按名字存能力与元数据,**不持有总线**,因此不启用消息平面时零对象、零开销。 ```js const registry = new Registry({ on_conflict: 'replace', // 'replace' | 'warn' | 'throw' wrap_in_process: false, // 是否把进程内能力也包成动态代理 contract: { register: 'strict', // 注册期契约校验:'strict' | 'warn' | 'off' call: 'warn', // 调用期入参校验:'strict' | 'warn' | 'off' table: {} // 全局契约表 { 能力名: { 方法名: 契约 } } } }); ``` | 方法 | 说明 | |---|---| | `add(name, impl, meta)` | 注册能力;同名按 `on_conflict` 处理,声明契约时在注册期完成自检,随后发 `add:<能力名>` 事件 | | `bindContract(name, record)` | 按注册表配置解析并绑定契约 | | `list(filter)` | 列出清单,`filter` 支持 `visibility` / `module` / `effect` / `tag` | | `del(name, owner)` | 删除能力;`owner` 缺省视为宿主操作,声明后只允许删除自己注册的能力 | | `get(name)` | 取实现,不存在时抛 `AbilityNotFound` | | `getRecord(name)` | 取完整记录,供判断隔离级别 | | `has(name)` | 是否存在 | | `on` / `off` / `emit` | 事件订阅、取消与发布;单个监听器异常上报到 `error` 事件,不影响其它监听器 | 注册表只发 `add:<能力名>`、`del:<能力名>` 与 `error` 三类事件;模块崩溃由 `Loader` 发 `module:crashed`。 ### 模块上下文 `createContext(registry, module_name, options)` 为模块创建受限上下文,记录该模块注册的能力与资源,卸载时逐个回收: | 命名空间 | 方法 | 说明 | |---|---|---| | `ability` | `add` / `get` / `has` / `del` / `list` | 能力读写;`add` 自动写入注册方模块名,`del` 限本人能力 | | `ability` | `call(name, method, args, options)` | 显式调用,支持 `timeout` / `signal` / `meta` | | `ability` | `stream(name, method, args, options)` | 流式调用,返回 `AsyncIterable` | | `ability` | `current()` | 取当前调用信息,实现侧无需改签名即可感知调用方 | | `ability` | `ref(name)` | 稳定句柄,每次属性访问实时解析,`reload` 后自动取到新实现 | | `resource` | `add` / `del` | 登记资源句柄,按 `close` → `end` → `dispose` → `destroy` 挑清理器 | | `event` | `on` / `off` / `emit` | 进程内同步广播,监听器随上下文卸载自动取消 | | `event` | `publish` / `subscribe` | 寻址消息,委托消息面;未装配时**显式抛错**,不降级为本地广播 | `options` 支持 `policy`(鉴权函数)、`scope`(绑定作用域)、`message_port`(消息面)、`forward_event`(事件转发)。 ### 模块加载器 `Loader` 负责加载、卸载、重载模块,管理生命周期、缓存与隔离级别。 | 方法 | 说明 | |---|---| | `load(name, options)` | 按隔离级别分发;同时发起同一模块的加载会被去重 | | `unload(name, options)` | 释放资源、注销能力、清缓存;`options.dispose_timeout` 限 `dispose` 时长 | | `reload(name)` | 先卸载再加载,返回新的模块导出 | | `waitPending()` | 等待在途加载任务全部结束 | | `drain(timeout)` | 等待所有隔离端点在途调用结束,用于优雅关闭 | | `handleCrash(name, reason)` | 隔离端异常退出时回收能力与记录,并发 `module:crashed` | | `readManifest(name)` | 读取模块 `package.json` 声明 | | `decideIsolation(manifest)` | 隔离级别**决策**,转交架构层 `kernel.decideIsolation` | 同进程加载会查找离入口最近的 `package.json` 作为模块声明,查找**不得越过内核自身包根**,包名与解析目标不一致时视为无声明;加载与 `init` 两阶段都注入上下文,失败时清缓存并回滚。隔离加载只做「决策 → 取适配器 → 登记记录」,未注册该级别时抛 `TRANSPORT_NOT_REGISTERED`,不静默降级。 ### 能力代理与调用 `createProxy(record, name)` 是 `ability.get` 的唯一切换点: - 进程内、无契约 → 返回真实实现,零开销直连; - 进程内、有契约 → 转发前后按契约校验入参、返回值; - 隔离级别 → 交给 `record.transport.createProxy`,并在外层叠加契约校验;缺承载适配器时按 `TRANSPORT_NOT_REGISTERED` 显式抛错。 显式调用 `callAbility` / `streamAbility` 在转发前把调用信息(`name` / `method` / `args` / `meta` / `signal`)写入 AsyncLocalStorage,实现侧经 `ctx.ability.current()` 读取;`signal` 触发时以 `AbortedError` 收尾,`stream` 的实现必须返回 `AsyncIterable`。 ### 契约 契约采用 OpenAI 函数风格 JSON,以能力为单位聚合为 `{ 方法名: 契约 }`:`type` 必须是 `function`,`function.name` 与 `function.description` 必填,`parameters.properties` 非空且键名必须是合法标识符(键顺序即参数顺序),参数与返回值类型取 `string` / `number` / `boolean` / `object` / `array`,只校验第一层。 契约可选:未声明契约的能力不参与任何校验。来源按「能力自带 `schema` 优先,其次全局契约表」解析,自检不通过时不写入编译结果,调用期因此退化为不做校验。 ### 策略 策略点集中在 `createContext` 层,**注册表保持纯净不做鉴权**。宿主注入 `(ctx) => boolean`,`ctx` 含 `action` / `module` / `ability` / `meta`;动作有 `ability.add` / `ability.get` / `ability.del` / `event.emit` / `event.publish` / `event.subscribe`。 仅显式 `false` 视为拒绝;返回 thenable 时同样拒绝,避免未鉴权放行。未注入策略时全放行。 ### 调用上下文与埋点 调用上下文用一条 `AsyncLocalStorage` 异步链同时承载 `ctx`(模块上下文)与 `call`(当前调用信息),并发加载与并发调用互不串台。 埋点只负责在关键路径(`kernel.load` / `ability.call`)上开启 span 并写入链路元数据,落地方式由宿主的 tracer 决定;未设置 tracer 时全程空实现,调用点无需判空。 ### 隔离缝与消息面 两者都是 dependency inversion,core 因此保持零依赖: - `TransportRegistry` 定义隔离承载适配器的接口(`isolation` + `start` / `stop` / `createProxy`,可选 `handleMessage`)与注册点,按隔离级别注册;未注册即报错,避免「声明了隔离却悄悄跑在进程内」。 - `assertMessagePort` / `createDisabledMessagePort` 定义消息面接口(`publish` / `subscribe`)并给出「未启用」占位实现,让误用立刻暴露。 ## 依赖与安装 本包在仓库内以相对路径链接使用,**未发布到 npm**。作为宿主,通常直接引用架构层: ```json { "dependencies": { "mm_kernel": "file:../kernel/mm_kernel" } } ``` 只有在编写官方扩展包或替换内核机制时才需要直接引用 `mm_kernel_core`(及 `/internal`)。 ## 开发 ```bash npm test # 单元测试 npm run test:coverage # 覆盖率 npm run check # ESLint 校验 npm run lint # ESLint 校验并自动修复 npm run format # Prettier 格式化 ``` ## License [MIT](LICENSE) © qww