import type { DevCompiler } from "./compiler.js"; import type { HotSwappableHandler } from "./hot-swappable-handler.js"; import type { ServiceReloadResult } from "./service-reloader.js"; import type { ModelReloadResult } from "./model-reloader.js"; import type { RouteReloaderApp, RouteReloaderMiddleware, MiddlewareRegistry, AdapterResolver, RoutesLoader, ErrorHandlerFactory, NotFoundHandlerFactory, BuiltinMiddlewareCreators } from "./route-reloader.js"; import type { ConfigureI18nFn } from "./i18n-reloader.js"; import type { MemoryReport } from "./memory-monitor.js"; import type { FileChangeInfo } from "./file-watcher.js"; /** * soft-reloader.ts — Soft Reload 完整流程编排器(Phase 2B) * * 封装 Soft Reload 的完整流程,包含: * * 1. 分级编译(Tier 1: transform 单文件 / Tier 2: rebuild 全量增量) * 2. require.cache 精确清除(反向依赖图 BFS) * 3. 级联爆炸检测(>80% 缓存失效 → 降级 Cold Restart) * 4. i18n 语言包热替换 * 5. 中间件定义重载 * 6. 选择性 Service 实例重载(仅 invalidated 的) * 7. 路由重载(Fresh Adapter 策略) * 8. requestHandler 原子替换(HotSwappableHandler.swap) * 9. 内存监控 * * 并发保护(v2.2): * - reload 锁 + 待处理队列 * - 快速连续保存时自动合并变更文件 * - 当前 reload 完成后自动处理队列 * * 降级策略: * - Soft Reload 任何步骤失败 → 不调用 swap(),旧 handler 继续服务 * - 级联爆炸检测 → 通过 IPC 请求 Cold Restart * - 编译错误 → 打印错误信息,等待用户修复后再次触发 * * @module lib/dev/soft-reloader * @see 11b-soft-reload.md §7(完整流程伪代码) * @see 11d-bootstrap-cli.md §3(createApp reload 能力) * @see 11e-edge-cases.md §1(Reload 失败回退) * @see IMPLEMENTATION-PLAN.md 任务 2.8 */ /** * 最小化的 Logger 接口 */ export interface SoftReloaderLogger { info(...args: unknown[]): void; warn(...args: unknown[]): void; debug(...args: unknown[]): void; error(...args: unknown[]): void; } /** * 中间件加载函数类型 * * 与 middleware-loader.ts 的 loadMiddlewares 签名兼容。 */ export type MiddlewareLoader = (middlewaresDir: string, declarations: unknown[], logger: SoftReloaderLogger, lifecycleLevel?: "concise" | "verbose") => Promise; /** * SoftReloader 依赖注入选项 * * 所有外部依赖通过构造选项注入,便于单元测试和解耦。 */ export interface SoftReloaderOptions { /** DevCompiler 实例(编译 + 路径映射) */ compiler: DevCompiler; /** HotSwappableHandler 实例(原子替换 handler) */ hotHandler: HotSwappableHandler; /** VextApp 实例(需要 services / logger / adapter / config) */ app: RouteReloaderApp; /** 框架运行时配置 */ config: Record; /** Logger 实例 */ logger: SoftReloaderLogger; /** Adapter 解析函数(创建全新 adapter 实例) */ resolveAdapter: AdapterResolver; /** 路由加载函数 */ loadRoutes: RoutesLoader; /** 中间件加载函数 */ loadMiddlewares: MiddlewareLoader; /** 错误处理器工厂 */ createErrorHandler: ErrorHandlerFactory; /** 404 处理器工厂 */ createNotFoundHandler: NotFoundHandlerFactory; /** 内置中间件创建器集合 */ builtinMiddlewares: BuiltinMiddlewareCreators; /** * i18n 配置回调(可选) * * 如果提供,soft reload 时会重新加载 locales/ 并调用此回调 * 将新语言包注册到 schema-dsl。 */ configureI18n?: ConfigureI18nFn; /** * 获取插件全局中间件列表的函数 * * 通常绑定为 () => internals.getGlobalMiddlewares() */ getGlobalMiddlewares: () => RouteReloaderMiddleware[]; /** * OpenAPI 配置(可选) * * 如果提供,soft reload 时会传递给 reloadRoutes(), * 使其在路由重载后自动重新生成 OpenAPI spec 并注册文档端点。 * 修复 BUG-022:热重载后 /docs 和 /openapi.json 返回 404。 */ openapiConfig?: Record; /** * Model 重载函数(可选) * * 如果提供,soft reload 时在 services 重载之后、routes 重载之前 * 调用此函数重新加载变更的 model 定义。 * 仅当 monSQLize 插件已加载时注入。 */ reloadModels?: (invalidated: Set) => Promise; } /** * Soft Reload 单次执行结果 */ export interface SoftReloadResult { /** 是否成功 */ success: boolean; /** 是否请求了 Cold Restart(级联爆炸) */ requestedColdRestart: boolean; /** 总耗时(毫秒) */ elapsed: number; /** 编译耗时(毫秒) */ compileTime: number; /** 缓存清除耗时(毫秒) */ cacheTime: number; /** i18n 重载耗时(毫秒) */ i18nTime: number; /** 中间件重载耗时(毫秒) */ middlewareTime: number; /** 服务重载耗时(毫秒) */ serviceTime: number; /** Model 重载耗时(毫秒) */ modelTime: number; /** 路由重载耗时(毫秒) */ routeTime: number; /** handler 替换耗时(毫秒) */ swapTime: number; /** 使用的 Tier(T1:code / T2:structural) */ tier: "T1:code" | "T2:structural"; /** 驱逐的模块数量 */ evictedModules: number; /** 服务重载结果 */ serviceResult?: ServiceReloadResult; /** Model 重载结果 */ modelResult?: ModelReloadResult; /** 内存报告 */ memoryReport?: MemoryReport; /** 错误信息(失败时) */ error?: string; } /** * SoftReloader — Soft Reload 编排器 * * 核心职责: * 1. 编排 Soft Reload 的完整流程(7 个步骤) * 2. 管理并发保护(reload 锁 + 待处理队列) * 3. 提供降级策略(失败回退 + 级联检测) * * 使用方式(dev-bootstrap.ts 中创建): * * ```ts * const softReloader = new SoftReloader({ * compiler, * hotHandler, * app, * config, * logger: app.logger, * resolveAdapter, * loadRoutes, * loadMiddlewares, * createErrorHandler, * createNotFoundHandler, * builtinMiddlewares, * configureI18n, * getGlobalMiddlewares: () => internals.getGlobalMiddlewares(), * }); * * // IPC 消息中调用 * process.on('message', async (msg) => { * if (msg.type === 'reload') { * await softReloader.reload(msg.files); * } * }); * ``` */ export declare class SoftReloader { private readonly compiler; private readonly hotHandler; private readonly app; private readonly config; private readonly logger; private readonly resolveAdapterFn; private readonly loadRoutesFn; private readonly loadMiddlewaresFn; private readonly createErrorHandlerFn; private readonly createNotFoundHandlerFn; private readonly builtinMiddlewares; private readonly configureI18n?; private readonly getGlobalMiddlewares; private readonly openapiConfig?; private readonly reloadModelsFn?; /** * v2.2 并发锁 — 防止多次 softReload 并行执行 * * 当 reload() 正在执行时,后续的 reload() 调用将变更文件 * 暂存到待处理队列中,当前 reload 完成后自动处理队列。 */ private reloadLock; /** * 待处理的变更文件队列 * * 在 reloadLock 为 true 时,新的变更文件被暂存到此队列。 * 当前 reload 完成后取出并执行。 * * 合并策略:按 path 去重,保留最新的 type。 */ private pendingReload; /** * 累计成功 reload 次数 */ private successCount; /** * 累计失败 reload 次数 */ private failureCount; private get lifecycleLevel(); constructor(options: SoftReloaderOptions); /** * reload — Soft Reload 入口(含并发保护) * * 如果当前正在 reload,将变更暂存到队列中等待。 * 当前 reload 完成后自动取出队列中的变更并执行。 * * @param changedFiles 变更文件信息列表 * @returns 最后一次 reload 的结果 */ reload(changedFiles: FileChangeInfo[]): Promise; /** * 获取累计成功 reload 次数 */ getSuccessCount(): number; /** * 获取累计失败 reload 次数 */ getFailureCount(): number; /** * 检查当前是否正在 reload */ isReloading(): boolean; /** * 检查是否有待处理的变更 */ hasPendingChanges(): boolean; /** * doSoftReload — 实际执行 Soft Reload(完整 7 步流程) * * 流程: * 0. 分级编译:modify → compileSingle (Tier 1, O(1)) * add/delete → rebuildWithNewEntryPoints (Tier 2, O(N)) * 1. 清除 require.cache(编译产物及其依赖者) * 2. 重载 i18n(如变更包含 locales/) * 3. 重载 middleware definitions * 4. 选择性重载 services(仅 invalidated 的实例) * 5. 创建新 adapter 实例 + 重载 routes + buildHandler * 6. 原子替换 handler * 7. 内存监控 * * 保持不变的:app、config、plugins、DB 连接、server socket、未变更的 service 实例 * * @param changedFiles 变更文件信息列表(FileChangeInfo[]) * @returns 单次 reload 结果 */ private doSoftReload; }