@faapi/faapi 0.0.0-canary.c6dc0f7 → 0.0.0-canary.e2ee43b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +630 -435
- package/dist/cli/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/router/constants.ts","../../src/utils/normalizePath.ts","../../src/router/parseRouteFile.ts","../../src/utils/importWithCacheBust.ts","../../src/middleware/loadMiddlewares.ts","../../src/router/scanRoutes.ts","../../src/router/sortRoutes.ts","../../src/router/detectRouteConflicts.ts","../../src/injection/resolveInjection.ts","../../src/injection/analyzeInjection.ts","../../src/runtime/inputType.ts","../../src/cli/generateTypes.ts","../../src/ast/resolveTypeNode.ts","../../src/ast/generateValidatorCode.ts","../../src/ast/createProgram.ts","../../src/ast/extractHandlerTypes.ts","../../src/validator/schemaName.ts","../../src/cli/collectRouteSchemaSources.ts","../../src/cli/generateSchema.ts","../../src/cli/generateRoutes.ts","../../src/cli/buildCommand.ts","../../../../node_modules/.pnpm/cac@6.7.14/node_modules/cac/dist/index.mjs","../../src/cli/normalizePatterns.ts","../../src/cli/parseArgs.ts","../../src/router/matchRoute.ts","../../src/loader/resolveExports.ts","../../src/loader/validateRouteModule.ts","../../src/loader/loadRouteModule.ts","../../src/runtime/sse.ts","../../src/runtime/createContext.ts","../../src/utils/queryToObject.ts","../../src/utils/parseJsonBody.ts","../../src/utils/parseMultipart.ts","../../src/errors/FaapiError.ts","../../src/errors/httpErrors.ts","../../src/runtime/resolveInput.ts","../../src/utils/isPlainObject.ts","../../src/response/toResponse.ts","../../src/injection/injectParams.ts","../../src/runtime/invokeHandler.ts","../../src/response/sendNodeResponse.ts","../../src/validator/schemaRegistry.ts","../../src/validator/coerceInput.ts","../../src/validator/validateInput.ts","../../src/utils/getClientIp.ts","../../src/middleware/cors.ts","../../src/server/serveStatic.ts","../../src/errors/formatErrorResponse.ts","../../src/server/serverUtils.ts","../../src/runtime/wsHandler.ts","../../src/server/handleWsUpgrade.ts","../../src/server/createServer.ts","../../src/server/startServer.ts","../../../../node_modules/.pnpm/readdirp@4.1.2/node_modules/readdirp/esm/index.js","../../../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/handler.js","../../../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js","../../src/cli/watcher.ts","../../src/config/loadConfig.ts","../../src/cli/loadPlugins.ts","../../src/cli/startCommand.ts","../../src/cli/index.ts"],"sourcesContent":["export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const;\n\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n\nconst HTTP_METHOD_SET: ReadonlySet<string> = new Set(HTTP_METHODS);\n\nexport function isHttpMethod(value: string): value is HttpMethod {\n return HTTP_METHOD_SET.has(value);\n}\n","/**\n * 标准化路径:\n * - 将反斜杠替换为正斜杠\n * - 去除重复的斜杠\n * - 去除尾部斜杠\n * - 确保以 / 开头(如果非空)\n */\nexport function normalizePath(path: string): string {\n if (!path) return '';\n\n // 将反斜杠替换为正斜杠\n let result = path.replace(/\\\\/g, '/');\n\n // 去除重复的斜杠\n result = result.replace(/\\/+/g, '/');\n\n // 去除尾部斜杠\n result = result.replace(/\\/+$/, '');\n\n // 确保以 / 开头(如果非空)\n if (result && !result.startsWith('/')) {\n result = '/' + result;\n }\n\n return result;\n}\n","import { normalizePath } from '../utils/normalizePath';\n\n/**\n * 将 [name] 格式的目录名转换为 :name 格式\n * '[id]' -> ':id'\n * '[...slug]' -> ':...slug'\n * 'login' -> 'login'\n */\nexport function dynamicSegmentToParam(segment: string): string {\n const match = segment.match(/^\\[(.+)\\]$/);\n if (match) {\n return ':' + match[1];\n }\n return segment;\n}\n\n/**\n * 从 URL 路径中提取动态参数名\n * '/user/:id' -> ['id']\n * '/auth/login' -> []\n * '/user/:id/posts/:postId' -> ['id', 'postId']\n * '/shop/:...slug' -> ['slug']\n */\nexport function extractParamNames(urlPath: string): string[] {\n const params: string[] = [];\n const segments = urlPath.split('/');\n for (const segment of segments) {\n if (segment.startsWith(':...')) {\n // catch-all 参数::...slug -> slug\n params.push(segment.slice(4));\n } else if (segment.startsWith(':')) {\n params.push(segment.slice(1));\n }\n }\n return params;\n}\n\n/**\n * 判断路径段是否为 catch-all 路由\n * '[...slug]' -> true\n * '[id]' -> false\n */\nexport function isCatchAllSegment(segment: string): boolean {\n return /^\\[\\.\\.\\..+\\]$/.test(segment);\n}\n\n/**\n * 判断路径段是否为路由分组\n * '(marketing)' -> true\n * 'login' -> false\n */\nexport function isRouteGroup(segment: string): boolean {\n return /^\\(.+\\)$/.test(segment);\n}\n\n/**\n * 将路由文件路径转换为 URL 路径\n * 输入: 相对于项目根目录的文件路径,如 'api/auth/login/handler.ts'\n * 输出: URL 路径,如 '/api/auth/login'\n *\n * 规则:\n * - 去掉 appDir 前缀(默认 '.',即项目根目录,不剥离)\n * - 去掉文件名(handler.ts 等)\n * - 将 [id] 转换为 :id\n * - 忽略路由分组 (groupName) — 不影响 URL\n * - 标准化路径\n *\n * 说明:CLI 默认扫描 src/api/(appDir='src'),底层 API 默认 '.'。\n * 无论 appDir 是 'src' 还是 '.',api/ 前缀都保留在 URL 中,因此 URL 始终带 /api 前缀。\n */\nexport function filePathToUrlPath(filePath: string, appDir: string = '.'): string {\n // 去掉 appDir 前缀(appDir='.' 时不剥离)\n const withoutPrefix = filePath.startsWith(appDir + '/')\n ? filePath.slice(appDir.length + 1)\n : filePath;\n\n // 去掉文件名(最后一个路径段)\n const lastSlashIndex = withoutPrefix.lastIndexOf('/');\n const dirPath = lastSlashIndex === -1 ? '' : withoutPrefix.slice(0, lastSlashIndex);\n\n if (!dirPath) {\n return '';\n }\n\n // 将每个路径段中的 [name] 转换为 :name,忽略路由分组 (name)\n const segments = dirPath\n .split('/')\n .filter((s) => !isRouteGroup(s)) // 过滤掉路由分组\n .map(dynamicSegmentToParam);\n\n // 拼接并标准化路径\n return normalizePath(segments.join('/'));\n}\n","import { pathToFileURL } from 'node:url';\n\n/**\n * 获取当前模块加载时间戳(watch 模式下用于绕过 ESM 缓存)\n *\n * 由 startCommand 在 watch 模式下设置到 globalThis.__FAAPI_LOAD_TS__。\n */\nexport function getLoadTimestamp(): number | undefined {\n return (globalThis as Record<string, unknown>).__FAAPI_LOAD_TS__ as number | undefined;\n}\n\n/**\n * 动态 import 文件,watch 模式下拼接时间戳绕过 ESM 缓存\n *\n * @param filePath 文件绝对路径\n * @returns 模块导出对象\n */\nexport async function importWithCacheBust(filePath: string): Promise<Record<string, unknown>> {\n let url = pathToFileURL(filePath).href;\n const ts = getLoadTimestamp();\n if (ts !== undefined) {\n url += `?t=${ts}`;\n }\n return (await import(url)) as Record<string, unknown>;\n}\n","import type { FaapiMiddleware } from './middlewareTypes';\nimport type { InjectorMap } from './injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\n/**\n * 中间件 + 注入器加载结果\n */\nexport interface LoadedMiddlewareBundle {\n middlewares: FaapiMiddleware[];\n injectors: InjectorMap;\n}\n\n/**\n * 中间件缓存,key 为 middlewares.ts 的绝对路径\n */\nconst middlewareCache = new Map<string, LoadedMiddlewareBundle>();\n\n/**\n * 失效所有中间件缓存(watch 模式下文件变化时调用)\n */\nexport function invalidateMiddlewareCache(): void {\n middlewareCache.clear();\n}\n\n/**\n * 从缓存中读取中间件 bundle(未命中返回 undefined)\n */\nexport function getCachedMiddlewares(absPath: string): LoadedMiddlewareBundle | undefined {\n return middlewareCache.get(absPath);\n}\n\n/**\n * 写入中间件缓存\n */\nexport function setCachedMiddlewares(absPath: string, bundle: LoadedMiddlewareBundle): void {\n middlewareCache.set(absPath, bundle);\n}\n\n/**\n * 从绝对路径加载 middlewares.ts 并校验\n *\n * 文件可导出:\n * - `default`:中间件数组(洋葱模型,每项为 async 函数)\n * - `injectors`:注入器映射表(按参数名匹配 handler 参数)\n *\n * 两者都是可选的,但至少要有一个。\n */\nexport async function loadMiddlewaresFile(filePath: string): Promise<LoadedMiddlewareBundle> {\n try {\n const module = await importWithCacheBust(filePath);\n\n // 加载中间件数组\n const middlewares = (module.default ?? module.middlewares ?? []) as unknown[];\n if (!Array.isArray(middlewares)) {\n console.warn(`[faapi] middlewares.ts 应导出数组,已忽略: ${filePath}`);\n return { middlewares: [], injectors: {} };\n }\n\n const validMiddlewares = middlewares.filter((m: unknown) => {\n if (typeof m !== 'function') {\n console.warn(`[faapi] 无效的中间件项(应为函数),已忽略: ${typeof m}`);\n return false;\n }\n return true;\n }) as FaapiMiddleware[];\n\n // 加载注入器映射表(可选命名导出)\n const injectors = (module.injectors ?? {}) as InjectorMap;\n if (typeof injectors !== 'object' || injectors === null) {\n console.warn(`[faapi] injectors 应导出对象,已忽略: ${filePath}`);\n return { middlewares: validMiddlewares, injectors: {} };\n }\n\n // 校验注入器:每个值必须是函数\n const validInjectors: InjectorMap = {};\n for (const [name, injector] of Object.entries(injectors)) {\n if (typeof injector !== 'function') {\n console.warn(`[faapi] 注入器 ${name} 应为函数,已忽略`);\n continue;\n }\n validInjectors[name] = injector;\n }\n\n return { middlewares: validMiddlewares, injectors: validInjectors };\n } catch {\n return { middlewares: [], injectors: {} };\n }\n}\n","import fg from 'fast-glob';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { RouteManifest, WsRouteManifest } from './routeTypes';\nimport { isHttpMethod, type HttpMethod } from './constants';\nimport { filePathToUrlPath, extractParamNames, isCatchAllSegment } from './parseRouteFile';\nimport {\n loadMiddlewaresFile,\n getCachedMiddlewares,\n setCachedMiddlewares,\n type LoadedMiddlewareBundle,\n} from '../middleware/loadMiddlewares';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\n/**\n * 从路由文件所在目录向上逐级查找 middlewares.ts,\n * 按从根到路由目录的顺序合并中间件和注入器(父级在前,子级在后)。\n *\n * 子级中间件包裹父级(洋葱模型下后注册的先执行 after);\n * 子级注入器覆盖父级同名注入器。\n */\nasync function findMergedMiddlewares(\n routeFilePath: string,\n rootDir: string,\n): Promise<{ middlewares: FaapiMiddleware[]; injectors: InjectorMap } | undefined> {\n const routeDir = path.dirname(routeFilePath);\n const resolvedRoot = path.resolve(rootDir);\n\n // 收集从根到路由目录的所有 middlewares.{ts,js} 路径\n // dev 模式扫 .ts,start 模式扫 .js(dist 产物)\n const mwPaths: string[] = [];\n let currentDir = path.resolve(rootDir, routeDir);\n while (true) {\n // 优先 .ts(dev),回退 .js(prd dist 产物)\n for (const ext of ['.ts', '.js']) {\n const mwPath = path.join(currentDir, `middlewares${ext}`);\n const absMwPath = path.resolve(rootDir, mwPath);\n if (fs.existsSync(absMwPath)) {\n mwPaths.push(absMwPath);\n break;\n }\n }\n if (currentDir === resolvedRoot) break;\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n\n if (mwPaths.length === 0) return undefined;\n\n // 从根到路由目录逐级加载(mwPaths 是从路由目录向上收集的,需反转)\n mwPaths.reverse();\n\n const mergedMiddlewares: FaapiMiddleware[] = [];\n const mergedInjectors: InjectorMap = {};\n\n for (const absMwPath of mwPaths) {\n let bundle: LoadedMiddlewareBundle | undefined = getCachedMiddlewares(absMwPath);\n if (bundle === undefined) {\n bundle = await loadMiddlewaresFile(absMwPath);\n setCachedMiddlewares(absMwPath, bundle);\n }\n // 子级中间件追加在父级之后(洋葱模型:后注册的中间件在内层)\n mergedMiddlewares.push(...bundle.middlewares);\n // 子级注入器覆盖父级同名注入器\n for (const [name, injector] of Object.entries(bundle.injectors)) {\n mergedInjectors[name] = injector;\n }\n }\n\n if (mergedMiddlewares.length === 0 && Object.keys(mergedInjectors).length === 0) {\n return undefined;\n }\n\n return { middlewares: mergedMiddlewares, injectors: mergedInjectors };\n}\n\n/**\n * 从 handler.ts 模块中提取导出的 HTTP 方法名\n */\nexport async function extractMethodsFromHandler(absPath: string): Promise<HttpMethod[]> {\n try {\n const module = await importWithCacheBust(absPath);\n const methods: HttpMethod[] = [];\n for (const key of Object.keys(module)) {\n if (isHttpMethod(key) && typeof module[key] === 'function') {\n methods.push(key);\n }\n }\n return methods;\n } catch (err) {\n // 模块加载失败时输出警告,避免静默吞没错误\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[faapi] 加载路由文件失败 ${absPath}: ${reason}`);\n return [];\n }\n}\n\n/**\n * 检测 handler.ts 模块是否导出 WS 函数\n *\n * WS 导出与 HTTP 方法导出(GET/POST 等)同级,导出名必须为 `WS`。\n */\nexport async function hasWsExport(absPath: string): Promise<boolean> {\n try {\n const module = await importWithCacheBust(absPath);\n return typeof module['WS'] === 'function';\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[faapi] 加载路由文件失败(WS 检测)${absPath}: ${reason}`);\n return false;\n }\n}\n\n/**\n * 扫描 api 目录,同时生成 HTTP 路由清单和 WebSocket 路由清单\n *\n * 路由文件格式:handler.ts,导出 HTTP 方法名作为 handler,也可导出 `WS` 函数声明 WebSocket 路由\n * ```ts\n * // api/user/handler.ts\n * export function GET() { return { list: [] } }\n * export function POST(body: any) { return { created: true } }\n *\n * // WebSocket 路由:导出 WS 函数\n * export function WS(ctx: WsContext) {\n * return { onMessage(ws, msg) { ws.send(`echo: ${msg}`) } };\n * }\n * ```\n * 一个 handler.ts 可同时导出 HTTP 方法(GET/POST...)和 WS 函数,\n * 分别生成 HTTP RouteRecord 和 WsRouteRecord。\n *\n * @param rootDir 项目根目录\n * @param patterns glob patterns\n * @param appDir app 目录前缀,默认 '.'(项目根目录);CLI 层默认 'src',传 undefined 时回退到 '.'\n */\nexport async function scanRoutes(\n rootDir: string,\n patterns: string[],\n appDir?: string,\n): Promise<{ routes: RouteManifest; wsRoutes: WsRouteManifest }> {\n const dir = appDir ?? '.';\n\n const files = await fg(patterns, {\n cwd: rootDir,\n onlyFiles: true,\n absolute: false,\n });\n\n const routes: RouteManifest = [];\n const wsRoutes: WsRouteManifest = [];\n\n for (const file of files) {\n const normalizedFile = file.replace(/\\\\/g, '/');\n const fileName = normalizedFile.split('/').pop()!;\n\n // 处理 handler.{ts,js} — API 路由 + WebSocket 路由\n // dev 模式扫 .ts,start 模式扫 .js(dist 产物)\n if (fileName === 'handler.ts' || fileName === 'handler.js') {\n const absPath = path.resolve(rootDir, normalizedFile);\n const urlPath = filePathToUrlPath(normalizedFile, dir);\n const paramNames = extractParamNames(urlPath);\n const isDynamic = paramNames.length > 0;\n const isCatchAll = normalizedFile.split('/').some(isCatchAllSegment);\n const middlewareBundle = await findMergedMiddlewares(normalizedFile, rootDir);\n\n // HTTP 方法导出\n const methods = await extractMethodsFromHandler(absPath);\n for (const method of methods) {\n routes.push({\n method,\n urlPath,\n filePath: normalizedFile,\n paramNames,\n isDynamic,\n isCatchAll: isCatchAll || undefined,\n middlewares: middlewareBundle?.middlewares,\n injectors: middlewareBundle?.injectors,\n });\n }\n\n // WS 导出\n const hasWs = await hasWsExport(absPath);\n if (hasWs) {\n wsRoutes.push({\n urlPath,\n filePath: normalizedFile,\n paramNames,\n isDynamic,\n isCatchAll: isCatchAll || undefined,\n middlewares: middlewareBundle?.middlewares,\n injectors: middlewareBundle?.injectors,\n });\n }\n continue;\n }\n }\n\n return { routes, wsRoutes };\n}\n","import type { RouteManifest } from './routeTypes';\n\n/**\n * 路由排序规则:\n * 1. 静态路由优先于动态路由\n * 2. 动态路由优先于 catch-all 路由\n * 3. 路径段数少的优先\n * 4. 字母序排列\n */\nexport function sortRoutes(routes: RouteManifest): RouteManifest {\n return [...routes].sort((a, b) => {\n // 1. 静态路由优先于动态路由\n if (a.isDynamic !== b.isDynamic) {\n return a.isDynamic ? 1 : -1;\n }\n\n // 2. catch-all 路由优先级最低(排在所有动态路由之后)\n if (a.isCatchAll !== b.isCatchAll) {\n return a.isCatchAll ? 1 : -1;\n }\n\n // 3. 路径段数少的优先\n const aSegments = a.urlPath.split('/').filter(Boolean).length;\n const bSegments = b.urlPath.split('/').filter(Boolean).length;\n if (aSegments !== bSegments) {\n return aSegments - bSegments;\n }\n\n // 4. 字母序排列\n return a.urlPath.localeCompare(b.urlPath);\n });\n}\n","import type { RouteManifest } from './routeTypes';\n\nexport interface RouteConflict {\n method: string;\n urlPath: string;\n files: string[];\n}\n\n/**\n * 检测路由冲突(相同 method + urlPath 的多个文件)\n */\nexport function detectRouteConflicts(routes: RouteManifest): RouteConflict[] {\n const map = new Map<string, RouteConflict>();\n\n for (const route of routes) {\n const key = `${route.method} ${route.urlPath}`;\n const existing = map.get(key);\n if (existing) {\n existing.files.push(route.filePath);\n } else {\n map.set(key, {\n method: route.method,\n urlPath: route.urlPath,\n files: [route.filePath],\n });\n }\n }\n\n // 只返回有冲突的(文件数 > 1)\n const conflicts: RouteConflict[] = [];\n for (const conflict of map.values()) {\n if (conflict.files.length > 1) {\n conflicts.push(conflict);\n }\n }\n\n return conflicts;\n}\n","import ts from 'typescript';\n\n/**\n * 参数注入类型\n */\nexport type InjectionType =\n | 'query'\n | 'body'\n | 'headers'\n | 'params'\n | 'context'\n | 'cookies'\n | 'ip'\n | 'files'\n | 'fields'\n | 'unknown';\n\n/**\n * 注入项信息\n */\nexport interface InjectionItem {\n name: string; // 参数名\n type: InjectionType; // 注入类型\n hasType: boolean; // 是否有类型标注(运行时类型已擦除,始终为 false)\n}\n\n/**\n * 参数名到注入类型的映射(单一来源,构建期和运行时共用)\n */\nexport const PARAM_TYPE_MAP: Record<string, InjectionType> = {\n query: 'query',\n body: 'body',\n headers: 'headers',\n params: 'params',\n context: 'context',\n ctx: 'context', // 别名\n cookies: 'cookies',\n ip: 'ip',\n files: 'files',\n fields: 'fields',\n};\n\n/**\n * 分析函数参数,决定需要注入什么内容\n *\n * 使用 TypeScript AST 解析 fn.toString() 的结果,\n * 正确处理解构参数、默认值、rest 参数等情况。\n *\n * 注意:运行时类型信息已被擦除,hasType 始终为 false。\n */\nexport function resolveInjection(fn: (...args: unknown[]) => unknown): InjectionItem[] {\n const fnStr = fn.toString();\n const params = extractParamsWithAst(fnStr);\n\n return params.map((param) => {\n const type = PARAM_TYPE_MAP[param.name] || 'unknown';\n return {\n name: param.name,\n type,\n hasType: false, // 运行时类型已擦除\n };\n });\n}\n\n/**\n * 使用 TypeScript AST 从函数字符串中提取参数名\n *\n * 相比正则解析,AST 能正确处理:\n * - 解构参数 `function GET({ page, size })` → page, size\n * - 默认值 `function GET(query = {})` → query\n * - rest 参数 `function GET(...args)` → args\n * - 含逗号的泛型(类型擦除后不存在该问题)\n */\nfunction extractParamsWithAst(fnStr: string): Array<{ name: string }> {\n // 包装成模块,让 TS 能解析\n const sourceFile = ts.createSourceFile(\n '__faapi_injection__.ts',\n fnStr,\n ts.ScriptTarget.Latest,\n true,\n );\n\n const paramNames: string[] = [];\n\n function visit(node: ts.Node): void {\n // 函数声明:function GET(query) {}\n if (ts.isFunctionDeclaration(node) && node.parameters.length > 0) {\n for (const param of node.parameters) {\n extractParamName(param, paramNames);\n }\n return;\n }\n\n // 箭头函数 / 函数表达式:(query) => {} 或 function(query) {}\n if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && node.parameters.length > 0) {\n for (const param of node.parameters) {\n extractParamName(param, paramNames);\n }\n return;\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n\n return paramNames.map((name) => ({ name }));\n}\n\n/**\n * 从单个参数节点提取参数名\n *\n * 支持的参数形式:\n * - 标识符:query → query\n * - 解构对象:{ page, size } → page, size(每个属性都作为一个注入项)\n * - 解构数组:[a, b] → a, b\n * - rest 参数:...args → args\n * - 默认值:query = {} → query\n */\nfunction extractParamName(param: ts.ParameterDeclaration, names: string[]): void {\n const name = param.name;\n\n // 标识符:query\n if (ts.isIdentifier(name)) {\n names.push(name.text);\n return;\n }\n\n // 解构对象:{ page, size }\n if (ts.isObjectBindingPattern(name)) {\n for (const element of name.elements) {\n if (ts.isBindingElement(element)) {\n const elemName = element.name;\n if (ts.isIdentifier(elemName)) {\n names.push(elemName.text);\n }\n }\n }\n return;\n }\n\n // 解构数组:[a, b]\n if (ts.isArrayBindingPattern(name)) {\n for (const element of name.elements) {\n if (element && ts.isBindingElement(element)) {\n const elemName = element.name;\n if (ts.isIdentifier(elemName)) {\n names.push(elemName.text);\n }\n }\n }\n return;\n }\n}\n","import ts from 'typescript';\nimport type { InjectionType } from './resolveInjection';\nimport { PARAM_TYPE_MAP } from './resolveInjection';\n\n/**\n * 参数元数据\n */\nexport interface ParamMeta {\n name: string; // 参数名\n type: InjectionType; // 注入类型\n typeName?: string; // 引用类型名(如 'Query')\n schema?: PropertyInfo[]; // 类型结构(内联类型时)\n}\n\n/**\n * 属性信息\n */\nexport interface PropertyInfo {\n name: string;\n type: string;\n optional: boolean;\n}\n\n/**\n * 注入元数据\n */\nexport interface InjectionMeta {\n params: ParamMeta[];\n}\n\n/**\n * AST 分析 handler 函数,提取参数注入元数据\n */\nexport function analyzeInjection(code: string, functionName: string): InjectionMeta {\n const sourceFile = ts.createSourceFile('temp.ts', code, ts.ScriptTarget.Latest, true);\n\n const params: ParamMeta[] = [];\n\n // 遍历 AST 查找目标函数\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isFunctionDeclaration(node) && node.name?.text === functionName) {\n // 分析参数\n for (const param of node.parameters) {\n const paramMeta = analyzeParam(param, sourceFile);\n params.push(paramMeta);\n }\n }\n });\n\n return { params };\n}\n\n/**\n * 分析单个参数\n */\nfunction analyzeParam(param: ts.ParameterDeclaration, sourceFile: ts.SourceFile): ParamMeta {\n const name = param.name.getText(sourceFile);\n const type = PARAM_TYPE_MAP[name] || 'unknown';\n\n const result: ParamMeta = { name, type };\n\n // 分析类型\n if (param.type) {\n if (ts.isTypeReferenceNode(param.type)) {\n // 引用类型:Query, Body 等\n result.typeName = param.type.typeName.getText(sourceFile);\n } else if (ts.isTypeLiteralNode(param.type)) {\n // 内联类型:{ page: number }\n result.schema = extractSchema(param.type, sourceFile);\n }\n }\n\n return result;\n}\n\n/**\n * 从类型字面量提取 schema\n */\nfunction extractSchema(typeNode: ts.TypeLiteralNode, sourceFile: ts.SourceFile): PropertyInfo[] {\n const schema: PropertyInfo[] = [];\n\n for (const member of typeNode.members) {\n if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {\n const propName = member.name.text;\n const optional = !!member.questionToken;\n const propType = member.type?.getText(sourceFile) || 'unknown';\n\n schema.push({\n name: propName,\n type: propType,\n optional,\n });\n }\n }\n\n return schema;\n}\n","/**\n * 根据 HTTP 方法判断主输入类型\n *\n * - GET / DELETE / HEAD:query(URL 查询参数)\n * - POST / PUT / PATCH:body(请求体)\n *\n * 注意:所有方法都可能同时有 query 和 body,\n * 这里返回的是\"主输入\"(用于校验和注入)。\n * DELETE 请求也支持 body(见 resolveInput.ts)。\n */\nexport function getInputTypeForMethod(method: string): 'query' | 'body' {\n const upper = method.toUpperCase();\n if (upper === 'GET' || upper === 'DELETE' || upper === 'HEAD') {\n return 'query';\n }\n return 'body';\n}\n\n/**\n * 判断方法是否有请求体\n *\n * POST / PUT / PATCH / DELETE 可能有 body\n * GET / HEAD 不应该有 body\n */\nexport function hasBody(method: string): boolean {\n const upper = method.toUpperCase();\n return upper === 'POST' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE';\n}\n","import type { RouteManifest } from '../router/routeTypes';\nimport { analyzeInjection } from '../injection/analyzeInjection';\nimport { getInputTypeForMethod } from '../runtime/inputType';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\ninterface RouteTypeInfo {\n method: string;\n urlPath: string;\n inputType: string; // TypeScript type string for input\n outputType: string; // TypeScript type string for output (unknown if can't infer)\n filePath: string;\n}\n\n/**\n * 从路由清单生成类型定义文件\n */\nexport async function generateTypes(\n routes: RouteManifest,\n rootDir: string,\n outputPath: string,\n): Promise<void> {\n const routeTypes: RouteTypeInfo[] = [];\n\n for (const route of routes) {\n const absolutePath = path.resolve(rootDir, route.filePath);\n let code: string;\n try {\n code = await fs.readFile(absolutePath, 'utf-8');\n } catch {\n continue;\n }\n\n const meta = analyzeInjection(code, route.method);\n const inputType = buildInputType(meta, route.method);\n\n routeTypes.push({\n method: route.method,\n urlPath: route.urlPath,\n inputType,\n outputType: 'unknown',\n filePath: route.filePath,\n });\n }\n\n const content = buildTypeFile(routeTypes);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, content, 'utf-8');\n}\n\nfunction buildInputType(\n meta: { params: Array<{ name: string; type: string; typeName?: string }> },\n method: string,\n): string {\n if (meta.params.length === 0) return 'void';\n\n const source = getInputTypeForMethod(method);\n const relevantParams = meta.params.filter((p) => p.type === source);\n\n if (relevantParams.length === 0) return 'void';\n\n // If there's a type name, reference it\n if (relevantParams.length === 1 && relevantParams[0].typeName) {\n return relevantParams[0].typeName;\n }\n\n return 'Record<string, unknown>';\n}\n\nfunction buildTypeFile(routes: RouteTypeInfo[]): string {\n const lines: string[] = [\n '// Auto-generated by faapi — do not edit',\n '// eslint-disable-next-line @typescript-eslint/no-namespace',\n 'export namespace FaapiRoutes {',\n '',\n ];\n\n for (const route of routes) {\n const key = routeKey(route.method, route.urlPath);\n lines.push(` interface ${key} {`);\n lines.push(` method: '${route.method}';`);\n lines.push(` path: '${route.urlPath}';`);\n lines.push(` input: ${route.inputType};`);\n lines.push(` output: ${route.outputType};`);\n lines.push(' }');\n lines.push('');\n }\n\n // Build route map type\n lines.push(' interface Routes {');\n for (const route of routes) {\n const key = routeKey(route.method, route.urlPath);\n lines.push(` '${route.method} ${route.urlPath}': ${key};`);\n }\n lines.push(' }');\n lines.push('}');\n lines.push('');\n\n // Generate typed client interface\n lines.push('export interface FaapiClient {');\n for (const route of routes) {\n lines.push(\n ` ${methodName(route.method)}('${route.urlPath}'${route.inputType === 'void' ? '' : ', input'}): Promise<${route.outputType}>;`,\n );\n }\n lines.push('}');\n\n return lines.join('\\n');\n}\n\nexport function routeKey(method: string, urlPath: string): string {\n const sanitized = urlPath\n .replace(/^\\//, '')\n .replace(/\\/:/g, '_')\n .replace(/\\//g, '_')\n .replace(/-/g, '_');\n return `${method}_${sanitized || 'root'}`;\n}\n\nexport function methodName(method: string): string {\n return method.toLowerCase();\n}\n","import ts from 'typescript';\n\n/**\n * Schema 提取错误\n *\n * 遇到无法解析或不支持运行时校验的类型时抛出,\n * 避免静默降级为 any 导致用户不知情。\n */\nexport class SchemaExtractionError extends Error {\n constructor(\n public readonly typeText: string,\n public readonly reason: string,\n options?: ErrorOptions,\n ) {\n super(`无法解析类型 \"${typeText}\": ${reason}`, options);\n this.name = 'SchemaExtractionError';\n }\n}\n\n/**\n * 运行时类型描述\n *\n * 用于校验器在运行时判断值的结构是否符合声明类型。\n * 相比单纯的字符串,能描述数组元素类型、嵌套对象、联合类型等。\n */\nexport type RuntimeType =\n | { kind: 'string' }\n | { kind: 'number' }\n | { kind: 'boolean' }\n | { kind: 'bigint' }\n | { kind: 'null' }\n | { kind: 'undefined' }\n | { kind: 'any' } // 不校验\n | { kind: 'unknown' } // 不校验\n | { kind: 'literal'; value: string | number | boolean } // 字面量\n | { kind: 'array'; element: RuntimeType }\n | { kind: 'tuple'; elements: TupleElement[] }\n | { kind: 'object'; properties: PropertyType[] }\n | { kind: 'union'; members: RuntimeType[] }\n | { kind: 'date' }\n | { kind: 'record'; key: RuntimeType; value: RuntimeType }\n | { kind: 'ref'; name: string }; // 命名类型引用(支持循环引用)\n\n/**\n * 元组元素类型\n *\n * - optional: 该位置元素可省略(如 `[string, number?]`)\n * - rest: 该位置是剩余元素(如 `[string, ...number[]]`),必须是数组类型,展开后逐个校验\n */\nexport interface TupleElement {\n type: RuntimeType;\n optional: boolean;\n rest: boolean;\n}\n\nexport interface PropertyType {\n name: string;\n type: RuntimeType;\n optional: boolean;\n}\n\n/**\n * 将 TypeScript 类型节点解析为运行时类型描述\n *\n * 支持的类型:\n * - 基础类型:string / number / boolean / null / undefined / any / unknown / void\n * - bigint:不支持(HTTP/JSON 不能传输),AST 提取阶段抛 SchemaExtractionError\n * - 字面量类型:'foo' / 42 / true\n * - 数组类型:T[] / Array<T>\n * - 元组类型:[string, number] / [string, number?] / [string, ...number[]](按位置校验)\n * - 对象类型:{ name: string; age?: number }\n * - 联合类型:string | null\n * - 交叉类型:A & B(按对象合并处理)\n * - 引用类型:Date / 其他 interface(递归解析)\n * - 工具类型:Record<K, V> / Partial<T>(best effort)\n * - Pick<T, K> / Omit<T, K>:K 支持字面量联合、类型别名、keyof T\n *\n * @param typeNode TypeScript 类型节点\n * @param checker 类型 checker(用于解析引用类型)\n * @param visited 防止递归循环\n */\nexport function resolveTypeNode(\n typeNode: ts.TypeNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const kind = typeNode.kind;\n\n // 基础类型\n switch (kind) {\n case ts.SyntaxKind.StringKeyword:\n return { kind: 'string' };\n case ts.SyntaxKind.NumberKeyword:\n return { kind: 'number' };\n case ts.SyntaxKind.BooleanKeyword:\n return { kind: 'boolean' };\n case ts.SyntaxKind.BigIntKeyword:\n // HTTP/JSON 不能传输 BigInt,在 AST 提取阶段就报错,避免运行时校验必然失败\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'bigint 无法通过 HTTP/JSON 传输,请改用 string 或 number',\n );\n case ts.SyntaxKind.SymbolKeyword:\n // HTTP/JSON 不能传输 Symbol\n throw new SchemaExtractionError(typeNode.getText(), 'symbol 无法通过 HTTP/JSON 传输');\n case ts.SyntaxKind.NullKeyword:\n return { kind: 'null' };\n case ts.SyntaxKind.UndefinedKeyword:\n return { kind: 'undefined' };\n case ts.SyntaxKind.UnknownKeyword:\n // unknown 是唯一允许的\"不校验\"显式声明\n return { kind: 'any' };\n case ts.SyntaxKind.AnyKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'any 不支持,请使用 unknown 表示不校验');\n case ts.SyntaxKind.VoidKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'void 不支持运行时校验');\n case ts.SyntaxKind.NeverKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'never 不支持运行时校验');\n case ts.SyntaxKind.ObjectKeyword:\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'object 不支持,请使用具体对象类型或 unknown',\n );\n }\n\n // 字面量类型\n if (ts.isLiteralTypeNode(typeNode)) {\n const literal = typeNode.literal;\n if (ts.isStringLiteral(literal)) {\n return { kind: 'literal', value: literal.text };\n }\n if (ts.isNumericLiteral(literal)) {\n return { kind: 'literal', value: Number(literal.text) };\n }\n if (literal.kind === ts.SyntaxKind.TrueKeyword) {\n return { kind: 'literal', value: true };\n }\n if (literal.kind === ts.SyntaxKind.FalseKeyword) {\n return { kind: 'literal', value: false };\n }\n if (literal.kind === ts.SyntaxKind.NullKeyword) {\n return { kind: 'null' };\n }\n throw new SchemaExtractionError(typeNode.getText(), '不支持的字面量类型');\n }\n\n // 数组类型:T[]\n if (ts.isArrayTypeNode(typeNode)) {\n return {\n kind: 'array',\n element: resolveTypeNode(typeNode.elementType, checker, visited),\n };\n }\n\n // 元组类型:[string, number] / [string, number?] / [string, ...number[]]\n if (ts.isTupleTypeNode(typeNode)) {\n const elements: TupleElement[] = typeNode.elements.map((e) => {\n // 剩余元素:...T\n if (ts.isRestTypeNode(e)) {\n const inner = resolveTypeNode(e.type, checker, visited);\n // ...T[] → 元素类型是 T 的数组元素\n if (inner.kind === 'array') {\n return { type: inner.element, optional: false, rest: true };\n }\n // ...T 但 T 不是数组(罕见,TS 通常要求 rest 是数组)\n return { type: inner, optional: false, rest: true };\n }\n // 命名元组成员:[name: string, age?: number]\n if (ts.isNamedTupleMember(e)) {\n return {\n type: resolveTypeNode(e.type, checker, visited),\n optional: !!e.questionToken,\n rest: false,\n };\n }\n // 可选元素:number?(无名称,有 ?)\n if (ts.isOptionalTypeNode(e)) {\n return {\n type: resolveTypeNode(e.type, checker, visited),\n optional: true,\n rest: false,\n };\n }\n // 普通元素\n return {\n type: resolveTypeNode(e, checker, visited),\n optional: false,\n rest: false,\n };\n });\n return { kind: 'tuple', elements };\n }\n\n // 联合类型:A | B\n if (ts.isUnionTypeNode(typeNode)) {\n const members = typeNode.types.map((t) => resolveTypeNode(t, checker, visited));\n return { kind: 'union', members };\n }\n\n // 交叉类型:A & B → 合并对象属性\n if (ts.isIntersectionTypeNode(typeNode)) {\n const properties: PropertyType[] = [];\n for (const t of typeNode.types) {\n const resolved = resolveTypeNode(t, checker, visited);\n if (resolved.kind === 'object') {\n properties.push(...resolved.properties);\n }\n }\n return { kind: 'object', properties };\n }\n\n // 内联对象类型:{ name: string; age?: number }\n if (ts.isTypeLiteralNode(typeNode)) {\n return resolveTypeLiteral(typeNode, checker, visited);\n }\n\n // keyof T — 用 checker 解析为字面量联合\n if (ts.isTypeOperatorNode(typeNode) && typeNode.operator === ts.SyntaxKind.KeyOfKeyword) {\n return resolveKeyOf(typeNode, checker);\n }\n\n // 引用类型:Date / 自定义 interface / Array<T> / Record<K,V> / Partial<T> 等\n if (ts.isTypeReferenceNode(typeNode)) {\n return resolveTypeReference(typeNode, checker, visited);\n }\n\n // 其他无法识别的语法节点\n throw new SchemaExtractionError(typeNode.getText(), '不支持的类型语法');\n}\n\n/**\n * 解析内联对象类型字面量\n */\nfunction resolveTypeLiteral(\n typeNode: ts.TypeLiteralNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const properties: PropertyType[] = [];\n\n for (const member of typeNode.members) {\n // 属性签名:name: string\n if (ts.isPropertySignature(member) && member.name) {\n const name = member.name.getText();\n const optional = !!member.questionToken;\n const type = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n properties.push({ name, type, optional });\n }\n // 索引签名:[key: string]: T → 转为 record\n if (ts.isIndexSignatureDeclaration(member)) {\n const keyType = member.parameters[0]?.type\n ? resolveTypeNode(member.parameters[0].type, checker, visited)\n : { kind: 'any' as const };\n const valueType = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n return { kind: 'record', key: keyType, value: valueType };\n }\n }\n\n return { kind: 'object', properties };\n}\n\n/**\n * 从 RuntimeType 提取字面量字符串集合\n * 用于 Pick<T, K> / Omit<T, K> 的 K 参数解析\n *\n * @returns 字面量值数组;无法解析时返回 null\n */\nfunction extractLiteralKeys(type: RuntimeType): string[] | null {\n if (type.kind === 'literal' && typeof type.value === 'string') {\n return [type.value];\n }\n if (type.kind === 'union') {\n const keys: string[] = [];\n for (const member of type.members) {\n if (member.kind === 'literal' && typeof member.value === 'string') {\n keys.push(member.value);\n } else {\n return null;\n }\n }\n return keys;\n }\n return null;\n}\n\n/**\n * 用 checker 解析 K 的最终类型,提取字面量字符串集合\n *\n * 用于 Pick<T, K> / Omit<T, K> 的 K 参数解析,覆盖 AST 无法直接拿到的场景:\n * - K 为类型别名(type Keys = 'id' | 'name')\n * - K 为 keyof T\n *\n * @returns 字面量值数组;无法解析时返回 null\n */\nfunction extractKeysFromChecker(typeNode: ts.TypeNode, checker?: ts.TypeChecker): string[] | null {\n if (!checker) return null;\n const type = checker.getTypeFromTypeNode(typeNode);\n\n if (type.isUnion()) {\n const keys: string[] = [];\n for (const member of type.types) {\n if (member.isStringLiteral()) {\n keys.push(member.value);\n } else if (member.isNumberLiteral()) {\n keys.push(String(member.value));\n } else {\n return null;\n }\n }\n return keys;\n }\n\n if (type.isStringLiteral()) {\n return [type.value];\n }\n if (type.isNumberLiteral()) {\n return [String(type.value)];\n }\n\n return null;\n}\n\n/**\n * 解析 keyof T — 用 checker 计算最终类型,返回字面量联合\n *\n * 例如 keyof { id: number; name: string } → 'id' | 'name'\n */\nfunction resolveKeyOf(typeNode: ts.TypeOperatorNode, checker?: ts.TypeChecker): RuntimeType {\n if (!checker) {\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 需要 checker 才能解析');\n }\n const type = checker.getTypeFromTypeNode(typeNode);\n\n if (type.isUnion()) {\n const members: RuntimeType[] = [];\n for (const member of type.types) {\n if (member.isStringLiteral()) {\n members.push({ kind: 'literal', value: member.value });\n } else if (member.isNumberLiteral()) {\n members.push({ kind: 'literal', value: member.value });\n } else {\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 的结果包含非字面量类型');\n }\n }\n return { kind: 'union', members };\n }\n\n if (type.isStringLiteral()) {\n return { kind: 'literal', value: type.value };\n }\n if (type.isNumberLiteral()) {\n return { kind: 'literal', value: type.value };\n }\n\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 的结果无法解析为字面量联合');\n}\n\n/**\n * 解析类型引用(Date / 自定义 interface / Array<T> / Record<K,V> 等)\n */\nfunction resolveTypeReference(\n typeNode: ts.TypeReferenceNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const typeName = typeNode.typeName.getText();\n\n // Date 类型\n if (typeName === 'Date') {\n return { kind: 'date' };\n }\n\n // Array<T>\n if (typeName === 'Array' && typeNode.typeArguments?.length === 1) {\n return {\n kind: 'array',\n element: resolveTypeNode(typeNode.typeArguments[0], checker, visited),\n };\n }\n\n // Record<K, V>\n if (typeName === 'Record' && typeNode.typeArguments?.length === 2) {\n return {\n kind: 'record',\n key: resolveTypeNode(typeNode.typeArguments[0], checker, visited),\n value: resolveTypeNode(typeNode.typeArguments[1], checker, visited),\n };\n }\n\n // Partial<T> / Required<T> / Readonly<T> — best effort,解析内部类型\n if (\n (typeName === 'Partial' || typeName === 'Required' || typeName === 'Readonly') &&\n typeNode.typeArguments?.length === 1\n ) {\n const inner = resolveTypeNode(typeNode.typeArguments[0], checker, visited);\n if (inner.kind === 'object' && typeName === 'Partial') {\n // Partial 所有字段变可选\n return {\n kind: 'object',\n properties: inner.properties.map((p) => ({ ...p, optional: true })),\n };\n }\n return inner;\n }\n\n // Pick<T, K> / Omit<T, K> — 解析 T 的字段,按 K 筛选/排除\n if ((typeName === 'Pick' || typeName === 'Omit') && typeNode.typeArguments?.length === 2) {\n const innerType = resolveTypeNode(typeNode.typeArguments[0], checker, visited);\n if (innerType.kind !== 'object') {\n throw new SchemaExtractionError(\n typeNode.getText(),\n `${typeName} 的 T 必须是对象类型,实际为 ${innerType.kind}`,\n );\n }\n\n // K 解析顺序:AST 字面量联合 → checker 解析(覆盖类型别名 / keyof T)\n const keyTypeNode = typeNode.typeArguments[1];\n let keys = extractLiteralKeys(resolveTypeNode(keyTypeNode, checker, visited));\n if (keys === null) {\n keys = extractKeysFromChecker(keyTypeNode, checker);\n }\n if (keys === null) {\n throw new SchemaExtractionError(typeNode.getText(), `${typeName} 的 K 无法解析为字面量集合`);\n }\n\n const keySet = new Set(keys);\n const properties =\n typeName === 'Pick'\n ? innerType.properties.filter((p) => keySet.has(p.name))\n : innerType.properties.filter((p) => !keySet.has(p.name));\n\n return { kind: 'object', properties };\n }\n\n // Map<K, V> / Set<T> — 运行时无法校验\n if (\n typeName === 'Map' ||\n typeName === 'Set' ||\n typeName === 'WeakMap' ||\n typeName === 'WeakSet'\n ) {\n throw new SchemaExtractionError(\n typeNode.getText(),\n `${typeName} 运行时无法校验,请改用对象或数组`,\n );\n }\n\n // Promise<T> — 运行时无法校验异步值\n if (typeName === 'Promise') {\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'Promise 运行时无法校验,请勿在 query/body 类型中使用',\n );\n }\n\n // Function — HTTP/JSON 不能传输函数\n if (typeName === 'Function') {\n throw new SchemaExtractionError(typeNode.getText(), 'Function 无法通过 HTTP/JSON 传输');\n }\n\n // 防止递归循环:遇到已访问的类型返回 ref,支持循环引用\n if (visited.has(typeName)) {\n return { kind: 'ref', name: typeName };\n }\n visited.add(typeName);\n\n // 使用 checker 解析引用类型(interface / type 别名)\n if (checker) {\n const symbol =\n typeNode.typeName.kind === ts.SyntaxKind.Identifier\n ? checker.getSymbolAtLocation(typeNode.typeName)\n : undefined;\n\n if (symbol) {\n const declaration = symbol.declarations?.[0];\n if (declaration) {\n // interface 声明\n if (ts.isInterfaceDeclaration(declaration)) {\n return resolveInterfaceDeclaration(declaration, checker, visited);\n }\n // type 别名声明\n if (ts.isTypeAliasDeclaration(declaration)) {\n return resolveTypeNode(declaration.type, checker, visited);\n }\n // enum 声明 → 字面量联合\n if (ts.isEnumDeclaration(declaration)) {\n return resolveEnumDeclaration(declaration);\n }\n }\n }\n }\n\n throw new SchemaExtractionError(typeNode.getText(), `无法解析的引用类型 \"${typeName}\"`);\n}\n\n/**\n * 解析 enum 声明为字面量联合类型\n *\n * - 字符串枚举:`enum Role { Admin = 'admin' }` → `'admin' | ...`\n * - 数值枚举:`enum Code { OK = 200 }` → `200 | ...`\n * - 隐式数值枚举:`enum Dir { Up, Down }` → `0 | 1 | ...`\n *\n * HTTP 视角:枚举值在 JSON 中是普通 string/number,按字面量联合校验即可。\n */\nfunction resolveEnumDeclaration(node: ts.EnumDeclaration): RuntimeType {\n const members: RuntimeType[] = [];\n let nextNumericValue = 0;\n\n for (const member of node.members) {\n if (member.initializer) {\n if (ts.isStringLiteral(member.initializer)) {\n members.push({ kind: 'literal', value: member.initializer.text });\n } else if (ts.isNumericLiteral(member.initializer)) {\n const num = Number(member.initializer.text);\n members.push({ kind: 'literal', value: num });\n nextNumericValue = num + 1;\n } else {\n throw new SchemaExtractionError(\n node.name.text,\n `enum 成员 \"${member.name.getText()}\" 的初始化值类型不支持,仅支持 string/number 字面量`,\n );\n }\n } else {\n // 隐式数值枚举:无初始化值,使用递增整数\n members.push({ kind: 'literal', value: nextNumericValue });\n nextNumericValue++;\n }\n }\n\n return { kind: 'union', members };\n}\n\n/**\n * 解析 interface 声明(含继承)\n */\nexport function resolveInterfaceDeclaration(\n node: ts.InterfaceDeclaration,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const properties: PropertyType[] = [];\n const propMap = new Map<string, PropertyType>();\n\n // 处理继承的父接口\n for (const heritageClause of node.heritageClauses ?? []) {\n if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const expr of heritageClause.types) {\n const parentType = resolveTypeNode(expr, checker, visited);\n if (parentType.kind === 'object') {\n for (const prop of parentType.properties) {\n propMap.set(prop.name, prop);\n }\n }\n }\n }\n }\n\n // 处理自身成员(覆盖继承的同名字段)\n for (const member of node.members) {\n if (ts.isPropertySignature(member) && member.name) {\n const name = member.name.getText();\n const optional = !!member.questionToken;\n const type = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n propMap.set(name, { name, type, optional });\n }\n // 索引签名 → record\n if (ts.isIndexSignatureDeclaration(member)) {\n const keyType = member.parameters[0]?.type\n ? resolveTypeNode(member.parameters[0].type, checker, visited)\n : { kind: 'any' as const };\n const valueType = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n return { kind: 'record', key: keyType, value: valueType };\n }\n }\n\n for (const prop of propMap.values()) {\n properties.push(prop);\n }\n\n return { kind: 'object', properties };\n}\n","import type { HandlerTypeInfo } from './extractHandlerTypes';\nimport type { RuntimeType, PropertyType } from './resolveTypeNode';\nimport { SchemaExtractionError } from './resolveTypeNode';\nimport type { ValidationIssue } from '../errors/httpErrors';\n\n/**\n * 将 RuntimeType 转为人类可读的类型描述字符串(用于 ValidationIssue.expected)\n *\n * 例如 'admin' | 'user' → \"'admin' | 'user'\"\n * string | null → \"string | null\"\n * Array<{ id: number }> → \"object[]\"\n */\nfunction runtimeTypeToExpected(type: RuntimeType): string {\n switch (type.kind) {\n case 'string':\n case 'number':\n case 'boolean':\n case 'null':\n case 'undefined':\n case 'bigint':\n case 'date':\n case 'any':\n case 'unknown':\n return type.kind;\n case 'literal':\n // 字符串字面量用单引号(符合 TS 习惯),数值/布尔直接输出\n return typeof type.value === 'string' ? `'${type.value}'` : String(type.value);\n case 'array':\n return `${runtimeTypeToExpected(type.element)}[]`;\n case 'tuple':\n return `[${type.elements\n .map((e) => (e.rest ? '...' : '') + runtimeTypeToExpected(e.type) + (e.optional ? '?' : ''))\n .join(', ')}]`;\n case 'object':\n return 'object';\n case 'union':\n return type.members.map(runtimeTypeToExpected).join(' | ');\n case 'record':\n return `Record<${runtimeTypeToExpected(type.key)}, ${runtimeTypeToExpected(type.value)}>`;\n case 'ref':\n return type.name;\n }\n}\n\n/**\n * 校验结果类型\n */\nexport interface ValidationResult {\n valid: boolean;\n issues: ValidationIssue[];\n data: Record<string, unknown>;\n}\n\n/**\n * schema 模块条目\n */\nexport interface SchemaModuleEntry {\n filePath: string;\n schemaName: string;\n typeInfo: HandlerTypeInfo | null;\n}\n\n/**\n * schema 模块导出格式\n */\nexport interface SchemaModuleExport {\n /** 校验函数表:'filePath#schemaName' -> ValidatorFn | null */\n validators: Record<string, ValidatorFn | null>;\n /** properties 表:'filePath#schemaName' -> PropertyType[](用于 coerce) */\n properties: Record<string, PropertyType[]>;\n}\n\n/**\n * 校验函数类型\n */\nexport type ValidatorFn = (input: unknown) => ValidationResult;\n\n/**\n * 类型解析器:根据类型名获取 RuntimeType\n *\n * 用于解析循环引用中的 ref。调用方负责提供(通常从 AST 提取)。\n */\nexport type TypeResolver = (name: string) => RuntimeType | undefined;\n\n/**\n * 生成单个类型的校验函数源码\n *\n * 返回的源码包含:\n * - 内部命名类型的 validate_X 函数声明(带循环引用保护)\n * - 名为 `validate` 的入口函数\n *\n * 循环引用保护:每个 validate_X 函数用 WeakSet 追踪已访问对象,\n * 遇到已访问的对象直接跳过,防止无限递归。\n *\n * @param typeInfo 类型信息\n * @param resolveType 类型解析器(可选,用于解析循环引用中的 ref)\n *\n * 用法:`new Function('input', source + '; return validate(input);')`\n */\nexport function generateValidatorSource(\n typeInfo: HandlerTypeInfo,\n resolveType?: TypeResolver,\n): string {\n const ctx = new CodeGenContext(resolveType);\n // 收集所有命名类型(用于生成 validate_X 函数)\n collectNamedTypes(typeInfo.runtimeType, typeInfo.name, ctx);\n // 生成入口函数(每次调用重置所有 validate_X 的 __visited,防止跨调用残留)\n const resetVisited = Array.from(ctx.namedTypes.keys())\n .map((name) => `validate_${name}.__visited = new WeakSet();`)\n .join('\\n ');\n const entryBody = generateObjectValidation(typeInfo.runtimeType, 'input', 'issues', ctx, \"''\");\n const entryFn = `function validate(input) {\n const issues = [];\n ${resetVisited}\n ${entryBody}\n return { valid: issues.length === 0, issues, data: (typeof input === 'object' && input !== null && !Array.isArray(input)) ? input : {} };\n}`;\n\n // 生成所有命名类型函数(带循环引用保护)\n const namedFns = Array.from(ctx.namedTypes.entries()).map(([name, type]) => {\n const body = generateObjectValidation(type, 'value', 'issues', ctx, 'path');\n return `function validate_${name}(value, path, issues) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n issues.push({ path, code: 'TYPE_MISMATCH', expected: 'object', received: typeof value, message: '期望对象' });\n return;\n }\n if (!validate_${name}.__visited) validate_${name}.__visited = new WeakSet();\n if (validate_${name}.__visited.has(value)) return;\n validate_${name}.__visited.add(value);\n ${body}\n}`;\n });\n\n return [...namedFns, entryFn].join('\\n\\n');\n}\n\n/**\n * 生成完整 JS 模块源码\n *\n * 包含所有命名类型函数 + validators 导出对象\n *\n * @param entries schema 条目\n * @param resolveType 类型解析器(可选,用于解析循环引用中的 ref)\n */\nexport function generateSchemaModule(\n entries: SchemaModuleEntry[],\n resolveType?: TypeResolver,\n): string {\n const ctx = new CodeGenContext(resolveType);\n const validatorEntries: string[] = [];\n const propertyEntries: string[] = [];\n\n // 先收集所有命名类型\n for (const entry of entries) {\n if (entry.typeInfo === null) continue;\n collectNamedTypes(entry.typeInfo.runtimeType, entry.typeInfo.name, ctx);\n }\n\n // 为每个 entry 生成重置 __visited 的代码\n const resetVisitedCode = Array.from(ctx.namedTypes.keys())\n .map((name) => `validate_${name}.__visited = new WeakSet();`)\n .join('\\n ');\n\n for (const entry of entries) {\n const key = `${entry.filePath}#${entry.schemaName}`;\n if (entry.typeInfo === null) {\n validatorEntries.push(` ${JSON.stringify(key)}: null,`);\n continue;\n }\n const body = generateObjectValidation(entry.typeInfo.runtimeType, 'input', 'issues', ctx, \"''\");\n validatorEntries.push(` ${JSON.stringify(key)}: (input) => {\n const issues = [];\n ${resetVisitedCode}\n ${body}\n return { valid: issues.length === 0, issues, data: (typeof input === 'object' && input !== null && !Array.isArray(input)) ? input : {} };\n },`);\n // 导出 properties(用于 coerce)\n propertyEntries.push(` ${JSON.stringify(key)}: ${JSON.stringify(entry.typeInfo.properties)},`);\n }\n\n // 生成所有命名类型函数(去重,带循环引用保护)\n const namedFns = Array.from(ctx.namedTypes.entries()).map(([name, type]) => {\n const body = generateObjectValidation(type, 'value', 'issues', ctx, 'path');\n return `function validate_${name}(value, path, issues) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n issues.push({ path, code: 'TYPE_MISMATCH', expected: 'object', received: typeof value, message: '期望对象' });\n return;\n }\n if (!validate_${name}.__visited) validate_${name}.__visited = new WeakSet();\n if (validate_${name}.__visited.has(value)) return;\n validate_${name}.__visited.add(value);\n ${body}\n}`;\n });\n\n return `${namedFns.join('\\n\\n')}\n\nconst validators = {\n${validatorEntries.join('\\n')}\n};\n\nconst properties = {\n${propertyEntries.join('\\n')}\n};\n\nexport { validators, properties };\n`;\n}\n\n/**\n * 代码生成上下文\n */\nclass CodeGenContext {\n // collected 在 collectNamedTypes 等外部函数中访问,故不设为 private\n /** 命名类型集合:类型名 -> RuntimeType */\n namedTypes = new Map<string, RuntimeType>();\n /** 已收集的类型(防重复) */\n collected = new Set<string>();\n /** 类型解析器(用于解析 ref) */\n private resolveType?: TypeResolver;\n /** 变量名计数器(防止嵌套数组变量名遮蔽) */\n private varId = 0;\n\n constructor(resolveType?: TypeResolver) {\n this.resolveType = resolveType;\n }\n\n /** 生成唯一变量 ID */\n nextVarId(): number {\n return ++this.varId;\n }\n\n /**\n * 解析 ref:通过 resolveType 回调获取类型定义\n */\n resolveRef(name: string): RuntimeType | undefined {\n return this.resolveType?.(name);\n }\n}\n\n/**\n * 收集所有命名 object 类型\n *\n * 遇到 object 类型时注册为命名类型,递归收集属性中的命名类型。\n * 遇到 ref 时通过 resolveType 回调获取类型定义并收集。\n *\n * 同时检测必填直接循环引用(会导致无限递归,无法自然终止):\n * - `next: LinkedList`(必填 ref)→ 抛错\n * - `next?: LinkedList`(可选 ref)→ 合法(undefined 可终止)\n * - `children: LinkedList[]`(数组 ref)→ 合法(空数组可终止)\n * - `next: LinkedList | null`(联合中的 ref)→ 合法(null 可终止)\n */\nfunction collectNamedTypes(type: RuntimeType, name: string, ctx: CodeGenContext): void {\n if (ctx.collected.has(name)) return;\n ctx.collected.add(name);\n\n if (type.kind === 'object') {\n ctx.namedTypes.set(name, type);\n for (const prop of type.properties) {\n detectRequiredRef(prop, name);\n collectNamedTypesFromType(prop.type, ctx);\n }\n }\n}\n\n/**\n * 检测必填直接循环引用并抛错\n *\n * 只检测 `!optional && type.kind === 'ref'`。\n * 数组元素、联合成员中的 ref 不检测(它们有自然终止条件)。\n */\nfunction detectRequiredRef(prop: PropertyType, ownerName: string): void {\n if (!prop.optional && prop.type.kind === 'ref') {\n throw new SchemaExtractionError(\n ownerName,\n `属性 \"${prop.name}\" 是必填的循环引用(类型 ${prop.type.name}),会导致无限递归。请改为可选(${prop.name}?: ${prop.type.name})或数组(${prop.name}: ${prop.type.name}[])。`,\n );\n }\n}\n\n/**\n * 从任意类型中收集命名类型\n */\nfunction collectNamedTypesFromType(type: RuntimeType, ctx: CodeGenContext): void {\n switch (type.kind) {\n case 'array':\n collectNamedTypesFromType(type.element, ctx);\n break;\n case 'tuple':\n for (const elem of type.elements) {\n collectNamedTypesFromType(elem.type, ctx);\n }\n break;\n case 'union':\n for (const member of type.members) {\n collectNamedTypesFromType(member, ctx);\n }\n break;\n case 'object':\n // 匿名 object,不需要生成 validate_X,但仍需检测必填 ref\n for (const prop of type.properties) {\n detectRequiredRef(prop, '<匿名对象>');\n collectNamedTypesFromType(prop.type, ctx);\n }\n break;\n case 'record':\n collectNamedTypesFromType(type.value, ctx);\n break;\n case 'ref': {\n // 命名类型引用:通过 resolveType 获取定义并收集\n if (!ctx.collected.has(type.name)) {\n const resolved = ctx.resolveRef(type.name);\n if (resolved) {\n collectNamedTypes(resolved, type.name, ctx);\n }\n }\n break;\n }\n }\n}\n\n/**\n * 生成对象类型的校验代码\n *\n * @param pathExpr 当前路径表达式(入口为 \"''\",命名类型函数体为 \"path\")\n */\nfunction generateObjectValidation(\n type: RuntimeType,\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr: string,\n): string {\n if (type.kind !== 'object') {\n return generateValueValidation(type, varName, issuesVar, ctx, pathExpr);\n }\n\n const lines: string[] = [];\n for (const prop of type.properties) {\n // 入口路径为空字符串时,子属性路径直接用字面量;否则用 pathExpr 拼接\n const propPath = pathExpr === \"''\" ? `'${prop.name}'` : `${pathExpr} + '.${prop.name}'`;\n const propAccess = `${varName}['${prop.name}']`;\n const hasCheck = `'${prop.name}' in ${varName}`;\n\n if (!prop.optional) {\n lines.push(\n `if (!${hasCheck}) ${issuesVar}.push({ path: ${propPath}, code: 'MISSING_FIELD', expected: '${prop.name}', received: 'undefined', message: '缺少必填字段 \"${prop.name}\"' });`,\n );\n lines.push(`else {`);\n } else {\n lines.push(`if (${hasCheck} && ${propAccess} !== undefined) {`);\n }\n\n lines.push(` ${generateValueValidation(prop.type, propAccess, issuesVar, ctx, propPath)}`);\n\n lines.push(`}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * 生成值类型的校验代码\n */\nfunction generateValueValidation(\n type: RuntimeType,\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr?: string,\n): string {\n const path = pathExpr ?? \"''\";\n\n switch (type.kind) {\n case 'any':\n case 'unknown':\n return ''; // 不校验\n\n case 'string':\n return `if (typeof ${varName} !== 'string') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'string', received: typeof ${varName}, message: '期望 string,实际 ' + typeof ${varName} });`;\n\n case 'number':\n return `if (typeof ${varName} !== 'number' || Number.isNaN(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'number', received: typeof ${varName}, message: '期望 number,实际 ' + typeof ${varName} });`;\n\n case 'boolean':\n return `if (typeof ${varName} !== 'boolean') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'boolean', received: typeof ${varName}, message: '期望 boolean,实际 ' + typeof ${varName} });`;\n\n case 'bigint':\n // HTTP 不能传输 BigInt,声明 bigint 的字段必然校验失败\n return `if (typeof ${varName} !== 'bigint') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'bigint', received: typeof ${varName}, message: '期望 bigint,实际 ' + typeof ${varName} });`;\n\n case 'null':\n return `if (${varName} !== null) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'null', received: typeof ${varName}, message: '期望 null,实际 ' + typeof ${varName} });`;\n\n case 'undefined':\n return `if (${varName} !== undefined) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'undefined', received: typeof ${varName}, message: '期望 undefined' });`;\n\n case 'literal':\n return `if (${varName} !== ${JSON.stringify(type.value)}) ${issuesVar}.push({ path: ${path}, code: 'INVALID_VALUE', expected: ${JSON.stringify(JSON.stringify(type.value))}, received: JSON.stringify(${varName}), message: '期望字面量 ${JSON.stringify(type.value)},实际 ' + JSON.stringify(${varName}) });`;\n\n case 'date':\n // HTTP 传输的是 ISO 字符串,允许 Date 实例或合法 ISO 8601 字符串\n // 类型不符 -> TYPE_MISMATCH; 类型对但格式非法 -> INVALID_FORMAT\n return `if (${varName} instanceof Date) { /* Date 实例,通过 */ }\nelse if (typeof ${varName} !== 'string') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'Date | ISO 8601 string', received: typeof ${varName}, message: '期望 Date 或 ISO 8601 字符串,实际 ' + typeof ${varName} });\nelse if (!/^\\\\d{4}-\\\\d{2}-\\\\d{2}(T\\\\d{2}:\\\\d{2}:\\\\d{2}(\\\\.\\\\d{1,3})?(Z|[+-]\\\\d{2}:?\\\\d{2})?)?$/.test(${varName}) || isNaN(new Date(${varName}).getTime())) ${issuesVar}.push({ path: ${path}, code: 'INVALID_FORMAT', expected: 'ISO 8601', received: String(${varName}), message: '不是合法的 ISO 8601 日期字符串: ' + ${varName} });`;\n\n case 'array': {\n const id = ctx.nextVarId();\n const itemVar = `item${id}`;\n const indexVar = `i${id}`;\n const elemPath = `${path} + '[' + ${indexVar} + ']'`;\n const elemValidation = generateValueValidation(\n type.element,\n itemVar,\n issuesVar,\n ctx,\n elemPath,\n );\n return `if (!Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'array', received: typeof ${varName}, message: '期望数组,实际 ' + typeof ${varName} });\nelse for (let ${indexVar} = 0; ${indexVar} < ${varName}.length; ${indexVar}++) { const ${itemVar} = ${varName}[${indexVar}]; ${elemValidation} }`;\n }\n\n case 'tuple': {\n // 元组:按位置校验,支持可选元素和剩余元素\n // - 必填元素:缺失报 MISSING_FIELD\n // - 可选元素:缺失不报错\n // - 剩余元素:之后的元素都按 rest 类型校验\n const minRequired = type.elements.filter((e) => !e.optional && !e.rest).length;\n const fixedCount = type.elements.filter((e) => !e.rest).length;\n const restElement = type.elements.find((e) => e.rest);\n const id = ctx.nextVarId();\n const itemVar = `t${id}`;\n const indexVar = `ti${id}`;\n\n // 数组类型检查 + 长度检查\n const lines: string[] = [];\n lines.push(\n `if (!Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'tuple', received: typeof ${varName}, message: '期望元组(数组),实际 ' + typeof ${varName} });`,\n );\n lines.push(`else {`);\n // 最小长度检查(必填元素数量)\n lines.push(\n `if (${varName}.length < ${minRequired}) ${issuesVar}.push({ path: ${path}, code: 'MISSING_FIELD', expected: 'tuple length >= ${minRequired}', received: 'length ' + ${varName}.length, message: '元组长度不足,期望至少 ${minRequired},实际 ' + ${varName}.length });`,\n );\n // 最大长度检查(无 rest 时不能超过固定元素数量)\n if (!restElement) {\n lines.push(\n `if (${varName}.length > ${fixedCount}) ${issuesVar}.push({ path: ${path}, code: 'INVALID_VALUE', expected: 'tuple length = ${fixedCount}', received: 'length ' + ${varName}.length, message: '元组长度超出,期望 ${fixedCount},实际 ' + ${varName}.length });`,\n );\n }\n\n // 按位置校验固定元素\n for (let i = 0; i < type.elements.length; i++) {\n const elem = type.elements[i];\n if (elem.rest) continue; // rest 元素单独处理\n const elemPath = `${path} + '[' + ${i} + ']'`;\n const elemAccess = `${varName}[${i}]`;\n if (elem.optional) {\n lines.push(`if (${i} < ${varName}.length && ${elemAccess} !== undefined) {`);\n } else {\n lines.push(`if (${i} < ${varName}.length) {`);\n }\n lines.push(` ${generateValueValidation(elem.type, elemAccess, issuesVar, ctx, elemPath)}`);\n lines.push(`}`);\n }\n\n // 剩余元素校验\n if (restElement) {\n const restPath = `${path} + '[' + ${indexVar} + ']'`;\n const restValidation = generateValueValidation(\n restElement.type,\n itemVar,\n issuesVar,\n ctx,\n restPath,\n );\n lines.push(\n `for (let ${indexVar} = ${fixedCount}; ${indexVar} < ${varName}.length; ${indexVar}++) { const ${itemVar} = ${varName}[${indexVar}]; ${restValidation} }`,\n );\n }\n\n lines.push(`}`);\n return lines.join('\\n');\n }\n\n case 'union': {\n // 联合类型:生成临时 issues 数组,任一成员匹配即可\n const tempVar = `tempIssues_${Math.random().toString(36).slice(2, 8)}`;\n const memberChecks = type.members.map((member) => {\n const check = generateValueValidation(member, varName, tempVar, ctx, path);\n return `(() => { const ${tempVar} = []; ${check}; return ${tempVar}.length === 0; })()`;\n });\n const expected = runtimeTypeToExpected(type);\n return `if (!(${memberChecks.join(' || ')})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: ${JSON.stringify(expected)}, received: typeof ${varName}, message: '值 ' + JSON.stringify(${varName}) + ' 不匹配联合类型 ${expected.replace(/'/g, \"\\\\'\")}' });`;\n }\n\n case 'record': {\n const valuePath = `${path} + '.' + key`;\n const valueValidation = generateValueValidation(type.value, 'val', issuesVar, ctx, valuePath);\n return `if (typeof ${varName} !== 'object' || ${varName} === null || Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'object', received: typeof ${varName}, message: '期望对象,实际 ' + typeof ${varName} });\nelse for (const [key, val] of Object.entries(${varName})) { ${valueValidation} }`;\n }\n\n case 'object': {\n // 匿名 object:内联校验\n return generateInlineObjectValidation(type, varName, issuesVar, ctx, path);\n }\n\n case 'ref': {\n // 命名类型引用:调用 validate_X 函数(支持循环引用递归)\n return `validate_${type.name}(${varName}, ${path}, ${issuesVar});`;\n }\n }\n}\n\n/**\n * 生成内联对象校验代码(匿名 object)\n */\nfunction generateInlineObjectValidation(\n type: RuntimeType & { kind: 'object' },\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr: string,\n): string {\n const lines: string[] = [];\n lines.push(\n `if (typeof ${varName} !== 'object' || ${varName} === null || Array.isArray(${varName})) ${issuesVar}.push({ path: ${pathExpr}, code: 'TYPE_MISMATCH', expected: 'object', received: typeof ${varName}, message: '期望对象,实际 ' + typeof ${varName} });`,\n );\n lines.push('else {');\n for (const prop of type.properties) {\n const propPath = `${pathExpr} + '.${prop.name}'`;\n const propAccess = `${varName}['${prop.name}']`;\n const hasCheck = `'${prop.name}' in ${varName}`;\n\n if (!prop.optional) {\n lines.push(\n ` if (!${hasCheck}) ${issuesVar}.push({ path: ${propPath}, code: 'MISSING_FIELD', expected: '${prop.name}', received: 'undefined', message: '缺少必填字段 \"${prop.name}\"' });`,\n );\n lines.push(` else {`);\n } else {\n lines.push(` if (${hasCheck} && ${propAccess} !== undefined) {`);\n }\n lines.push(` ${generateValueValidation(prop.type, propAccess, issuesVar, ctx, propPath)}`);\n lines.push(` }`);\n }\n lines.push('}');\n return lines.join('\\n');\n}\n","import ts from 'typescript';\n\n/**\n * Program 缓存,key 为文件路径\n *\n * watch 模式下通过 invalidateProgramCache() 全量清理。\n * 同一文件多次创建 Program 时复用缓存,避免重复解析。\n */\nconst programCache = new Map<string, ts.Program>();\n\n/**\n * 清理所有 Program 缓存(watch 模式下文件变化时调用)\n *\n * 全量清理而非增量清理,理由:\n * - 简单可靠,无状态一致性问题\n * - 跨文件类型引用需要所有文件的 Program 同步更新\n * - dev 模式文件量有限,全量重建在百毫秒级\n */\nexport function invalidateProgramCache(): void {\n programCache.clear();\n}\n\n/**\n * 为指定文件创建 TypeScript Program(带缓存)\n *\n * @param filePath 要分析的 .ts 文件绝对路径\n */\nexport function createProgram(filePath: string): ts.Program {\n const cached = programCache.get(filePath);\n if (cached) {\n return cached;\n }\n\n const program = ts.createProgram([filePath], {\n strict: true,\n target: ts.ScriptTarget.ES2022,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n skipLibCheck: true,\n noEmit: true,\n });\n\n programCache.set(filePath, program);\n return program;\n}\n","import ts from 'typescript';\nimport {\n resolveTypeNode,\n resolveInterfaceDeclaration,\n type PropertyType,\n type RuntimeType,\n SchemaExtractionError,\n} from './resolveTypeNode';\n\nexport interface HandlerTypeInfo {\n name: string; // 类型名,如 'GETQuery'\n properties: PropertyType[];\n /** 完整的运行时类型描述(用于嵌套校验) */\n runtimeType: RuntimeType;\n}\n\n/**\n * 从源文件中提取指定名称的类型信息\n *\n * 支持的类型声明:\n * - interface 声明(含继承)\n * - type 别名(type Query = { ... })\n *\n * 遇到不支持的类型时抛 `SchemaExtractionError`,错误信息包含文件路径和类型名。\n *\n * @param program TypeScript Program\n * @param filePath 源文件路径\n * @param typeName 类型名,如 'GETQuery'\n */\nexport function extractTypeInfo(\n program: ts.Program,\n filePath: string,\n typeName: string,\n): HandlerTypeInfo | null {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) return null;\n\n const checker = program.getTypeChecker();\n\n // 1. 查找 interface 声明\n let result: HandlerTypeInfo | null = null;\n\n ts.forEachChild(sourceFile, (node) => {\n if (result) return;\n\n if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) {\n const visited = new Set<string>();\n visited.add(typeName); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, typeName, () =>\n resolveInterfaceDeclaration(node, checker, visited),\n );\n result = {\n name: typeName,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n };\n return;\n }\n\n // 2. 查找 type 别名\n if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {\n const visited = new Set<string>();\n visited.add(typeName); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, typeName, () =>\n resolveTypeNode(node.type, checker, visited),\n );\n result = {\n name: typeName,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n };\n return;\n }\n });\n\n return result;\n}\n\n/**\n * 从源文件中提取所有 interface 和 type 别名的类型信息\n *\n * 用于:\n * - 生成 schema 模块时遍历所有命名类型\n * - 作为 typeResolver 提供给 generateValidatorCode,解析循环引用中的 ref\n *\n * @returns Map<类型名, HandlerTypeInfo>\n */\nexport function extractAllTypes(\n program: ts.Program,\n filePath: string,\n): Map<string, HandlerTypeInfo> {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) return new Map();\n\n const checker = program.getTypeChecker();\n const result = new Map<string, HandlerTypeInfo>();\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isInterfaceDeclaration(node)) {\n const visited = new Set<string>();\n visited.add(node.name.text); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, node.name.text, () =>\n resolveInterfaceDeclaration(node, checker, visited),\n );\n result.set(node.name.text, {\n name: node.name.text,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n });\n return;\n }\n\n if (ts.isTypeAliasDeclaration(node)) {\n const visited = new Set<string>();\n visited.add(node.name.text); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, node.name.text, () =>\n resolveTypeNode(node.type, checker, visited),\n );\n result.set(node.name.text, {\n name: node.name.text,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n });\n return;\n }\n });\n\n return result;\n}\n\n/**\n * 包装类型解析,捕获 SchemaExtractionError 并补充文件路径和类型名上下文\n *\n * 只包装一次(最外层),避免嵌套调用时重复包装。\n */\nfunction withFileContext<T>(filePath: string, typeName: string, fn: () => T): T {\n try {\n return fn();\n } catch (err) {\n if (err instanceof SchemaExtractionError) {\n // 补充文件路径和类型名,只包装一次\n const fileName = filePath.split('/').pop() ?? filePath;\n const enriched = new SchemaExtractionError(\n err.typeText,\n `${err.reason}(文件: ${fileName}, 类型: ${typeName})`,\n { cause: err },\n );\n throw enriched;\n }\n throw err;\n }\n}\n","/**\n * 根据 HTTP 方法和输入类型生成 schema 类型名\n * GET + query -> GETQuery\n * POST + body -> POSTBody\n * GET + params -> GETParams\n */\nexport function getSchemaName(method: string, inputType: 'query' | 'body' | 'params'): string {\n return `${method.toUpperCase()}${inputType.charAt(0).toUpperCase() + inputType.slice(1)}`;\n}\n","import { createProgram } from '../ast/createProgram';\nimport { extractTypeInfo, extractAllTypes, type HandlerTypeInfo } from '../ast/extractHandlerTypes';\nimport { getInputTypeForMethod } from '../runtime/inputType';\nimport { getSchemaName } from '../validator/schemaName';\nimport { analyzeInjection } from '../injection/analyzeInjection';\nimport type { RouteManifest } from '../router/routeTypes';\nimport path from 'node:path';\n\n/**\n * 单个路由的 schema 提取结果\n */\nexport interface RouteSchemaSource {\n filePath: string;\n schemaName: string;\n typeInfo: HandlerTypeInfo | null;\n}\n\n/**\n * 从路由清单收集 schema 提取所需的原始数据\n *\n * dev 和 prd 共享的核心提取流程:\n * 1. 按文件分组遍历路由\n * 2. 对每个文件 createProgram + extractAllTypes 收集所有类型\n * 3. 用 analyzeInjection + extractTypeInfo 提取每个路由的 schema 类型\n * 4. 同时返回按文件分组的 allTypesMap 和合并后的全局 allTypes\n *\n * 调用方基于返回的 sources 和 allTypes 各自做最终转换:\n * - dev:编译 validator 函数 → SchemaManifest(用 mergedAllTypes)\n * - prd:生成 JS 模块代码 → SchemaModuleEntry[](用 allTypesByFile)\n */\nexport function collectRouteSchemaSources(\n routes: RouteManifest,\n rootDir?: string,\n): {\n sources: RouteSchemaSource[];\n /** 按文件分组的类型映射(prd writeSchemaModule 用) */\n allTypesByFile: Map<string, Map<string, HandlerTypeInfo>>;\n /** 合并后的全局类型映射(dev typeInfoToSchemaEntry 用) */\n mergedAllTypes: Map<string, HandlerTypeInfo>;\n} {\n // 按文件分组收集方法(去重)\n const methodsByFile = new Map<string, Set<string>>();\n for (const route of routes) {\n const filePath = rootDir ? path.resolve(rootDir, route.filePath) : route.filePath;\n let methods = methodsByFile.get(filePath);\n if (!methods) {\n methods = new Set();\n methodsByFile.set(filePath, methods);\n }\n methods.add(route.method);\n }\n\n // 先收集所有文件的类型\n const programByFile = new Map<string, ReturnType<typeof createProgram>>();\n const allTypesByFile = new Map<string, Map<string, HandlerTypeInfo>>();\n const mergedAllTypes = new Map<string, HandlerTypeInfo>();\n for (const filePath of methodsByFile.keys()) {\n const program = createProgram(filePath);\n programByFile.set(filePath, program);\n const allTypes = extractAllTypes(program, filePath);\n allTypesByFile.set(filePath, allTypes);\n for (const [name, info] of allTypes) {\n mergedAllTypes.set(name, info);\n }\n }\n\n // 每个文件提取 schema\n const sources: RouteSchemaSource[] = [];\n for (const [filePath, methods] of methodsByFile) {\n const program = programByFile.get(filePath)!;\n const sourceFile = program.getSourceFile(filePath);\n const code = sourceFile?.text ?? '';\n for (const method of methods) {\n const inputType = getInputTypeForMethod(method);\n const schemaName = getSchemaName(method, inputType);\n const meta = analyzeInjection(code, method);\n const param = meta.params.find((p) => p.type === inputType);\n const typeInfo = param?.typeName ? extractTypeInfo(program, filePath, param.typeName) : null;\n sources.push({ filePath, schemaName, typeInfo });\n }\n }\n\n return { sources, allTypesByFile, mergedAllTypes };\n}\n","import {\n generateValidatorSource,\n generateSchemaModule,\n type SchemaModuleEntry,\n} from '../ast/generateValidatorCode';\nimport type { HandlerTypeInfo } from '../ast/extractHandlerTypes';\nimport type { RouteManifest } from '../router/routeTypes';\nimport type { SchemaManifest, SchemaEntry } from '../validator/schemaRegistry';\nimport { collectRouteSchemaSources } from './collectRouteSchemaSources';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/**\n * 从路由清单提取完整 manifest,并生成校验函数\n *\n * 同一文件的多个方法合并到同一 FileSchemas。\n *\n * 与 prd 的 writeSchemaModule 一致:先收集所有文件的类型并合并为全局 allTypes,\n * 再传给每个文件的 schema 生成,确保跨文件类型引用可解析(与 prd 行为一致)。\n *\n * @param routes 路由清单(filePath 为相对路径)\n * @param rootDir 项目根目录,传入时将 filePath 转为绝对路径(与 validateInput 调用一致)\n */\nexport function extractSchemasForRoutes(routes: RouteManifest, rootDir?: string): SchemaManifest {\n const { sources, mergedAllTypes } = collectRouteSchemaSources(routes, rootDir);\n\n // 按文件分组,合并为 FileSchemas\n const manifest: SchemaManifest = new Map();\n for (const { filePath, schemaName, typeInfo } of sources) {\n let fileSchemas = manifest.get(filePath);\n if (!fileSchemas) {\n fileSchemas = new Map();\n manifest.set(filePath, fileSchemas);\n }\n fileSchemas.set(schemaName, typeInfoToSchemaEntry(typeInfo, mergedAllTypes));\n }\n\n return manifest;\n}\n\n/**\n * 将 HandlerTypeInfo 转为 SchemaEntry(包含 properties 和 validator)\n *\n * typeInfo 为 null 时返回 null(跳过校验)。\n * typeInfo 非 null 时生成校验函数源码并用 new Function 创建。\n */\nfunction typeInfoToSchemaEntry(\n typeInfo: HandlerTypeInfo | null,\n allTypes: Map<string, HandlerTypeInfo>,\n): SchemaEntry {\n if (typeInfo === null) return null;\n\n const source = generateValidatorSource(typeInfo, (name) => allTypes.get(name)?.runtimeType);\n // 用 new Function 创建校验函数\n const validator = new Function('input', `${source}\\nreturn validate(input);`) as (\n input: unknown,\n ) => ReturnType<typeof Object>;\n return {\n properties: typeInfo.properties,\n validator: validator as SchemaEntry extends { validator: infer F } ? F : never,\n };\n}\n\n/**\n * 生成 schema JS 模块并写入文件\n *\n * @param entries schema 模块条目(包含 typeInfo)\n * @param allTypesMap 每个文件对应的所有类型(用于解析循环引用)\n * @param outputPath 输出路径(如 dist/faapi-schema.js)\n */\nexport async function writeSchemaModule(\n entries: SchemaModuleEntry[],\n allTypesMap: Map<string, Map<string, HandlerTypeInfo>>,\n outputPath: string,\n): Promise<void> {\n // 合并所有文件的类型解析器\n const allTypes = new Map<string, HandlerTypeInfo>();\n for (const types of allTypesMap.values()) {\n for (const [name, info] of types) {\n allTypes.set(name, info);\n }\n }\n\n const source = generateSchemaModule(entries, (name) => allTypes.get(name)?.runtimeType);\n\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, source, 'utf-8');\n}\n\n/**\n * 读取 schema JS 模块并转为 SchemaManifest\n *\n * 动态 import JS 模块,获取 validators 和 properties 对象。\n */\nexport async function readManifestFile(inputPath: string): Promise<SchemaManifest> {\n const fileUrl = `file://${inputPath}`;\n const mod = await import(fileUrl);\n const validators = mod.validators as Record<string, ((input: unknown) => unknown) | null>;\n const properties = (mod.properties ?? {}) as Record<string, unknown[]>;\n\n const manifest: SchemaManifest = new Map();\n for (const [key, validator] of Object.entries(validators)) {\n const [filePath, schemaName] = key.split('#');\n if (!filePath || !schemaName) continue;\n\n let fileSchemas = manifest.get(filePath);\n if (!fileSchemas) {\n fileSchemas = new Map();\n manifest.set(filePath, fileSchemas);\n }\n\n if (validator === null) {\n fileSchemas.set(schemaName, null);\n } else {\n fileSchemas.set(schemaName, {\n properties: (properties[key] ?? []) as SchemaEntry extends { properties: infer P }\n ? P\n : never,\n validator: validator as SchemaEntry extends { validator: infer F } ? F : never,\n });\n }\n }\n\n return manifest;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { RouteManifest, WsRouteManifest, RouteRecord, WsRouteRecord } from '../router/routeTypes';\nimport type { HttpMethod } from '../router/constants';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport {\n loadMiddlewaresFile,\n getCachedMiddlewares,\n setCachedMiddlewares,\n} from '../middleware/loadMiddlewares';\nimport type { LoadedMiddlewareBundle } from '../middleware/loadMiddlewares';\n\n/**\n * 序列化路由记录(可写入 JS 模块,无函数引用)\n *\n * build 时生成,start 时读取。filePath/middlewarePaths 已转为 prd 形式(dist 前缀 + .js)。\n */\nexport interface SerializedRouteRecord {\n method: HttpMethod;\n urlPath: string;\n filePath: string;\n paramNames: string[];\n isDynamic: boolean;\n isCatchAll?: boolean;\n /** 从根到路由目录的中间件文件绝对路径列表(已排序,根在前) */\n middlewarePaths: string[];\n}\n\nexport interface SerializedWsRouteRecord {\n urlPath: string;\n filePath: string;\n paramNames: string[];\n isDynamic: boolean;\n isCatchAll?: boolean;\n middlewarePaths: string[];\n}\n\nexport interface SerializedRouteManifest {\n routes: SerializedRouteRecord[];\n wsRoutes: SerializedWsRouteRecord[];\n}\n\n/**\n * 把 dev 形式的 filePath(api/health/handler.ts)转为 prd 形式(dist/api/health/handler.js)\n */\nfunction toProdFilePath(filePath: string): string {\n const jsPath = filePath.replace(/\\.ts$/, '.js');\n return jsPath.startsWith('dist/') ? jsPath : `dist/${jsPath}`;\n}\n\n/**\n * 序列化路由清单为可写入 JS 模块的结构\n *\n * - filePath 转为 prd 形式\n * - middlewares/injectors 不序列化(函数无法序列化),改为 middlewarePaths(中间件文件绝对路径列表)\n * - middlewarePaths 已排序(根在前,路由目录在后),start 时按序加载即可还原洋葱模型\n *\n * @param rootDir 项目根目录,用于检查中间件文件是否存在\n */\nexport function serializeRoutes(\n routes: RouteManifest,\n wsRoutes: WsRouteManifest,\n rootDir: string,\n): SerializedRouteManifest {\n const serialize = <T extends RouteRecord | WsRouteRecord>(\n route: T,\n ): T extends RouteRecord ? SerializedRouteRecord : SerializedWsRouteRecord => {\n const middlewarePaths = extractMiddlewarePaths(route.filePath, rootDir);\n const serialized = {\n urlPath: route.urlPath,\n filePath: toProdFilePath(route.filePath),\n paramNames: route.paramNames,\n isDynamic: route.isDynamic,\n isCatchAll: route.isCatchAll,\n middlewarePaths,\n };\n if ('method' in route) {\n (serialized as SerializedRouteRecord).method = (route as RouteRecord).method;\n }\n return serialized as T extends RouteRecord ? SerializedRouteRecord : SerializedWsRouteRecord;\n };\n\n return {\n routes: routes.map(serialize) as SerializedRouteRecord[],\n wsRoutes: wsRoutes.map(serialize) as SerializedWsRouteRecord[],\n };\n}\n\n/**\n * 从路由文件路径,向上查找所有中间件文件绝对路径(根在前,路由目录在后)\n *\n * 与 scanRoutes.findMergedMiddlewares 的收集逻辑一致,但只返回路径不加载。\n * build 时调用,检查 dev 形式(.ts)中间件文件是否存在,返回 prd 形式(.js)绝对路径。\n */\nfunction extractMiddlewarePaths(routeFilePath: string, rootDir: string): string[] {\n const routeDir = path.dirname(routeFilePath);\n const resolvedRoot = path.resolve(rootDir);\n\n const paths: string[] = [];\n let currentDir = path.resolve(rootDir, routeDir);\n while (true) {\n // 优先 .ts(dev),回退 .js(prd 残留)\n for (const ext of ['.ts', '.js']) {\n const mwPath = path.join(currentDir, `middlewares${ext}`);\n const absMwPath = path.resolve(rootDir, mwPath);\n if (fs.existsSync(absMwPath)) {\n // 转 prd 形式绝对路径:先转相对(toProdFilePath 按相对路径设计),再 resolve 回绝对\n const relMwPath = path.relative(rootDir, absMwPath);\n const prodAbsPath = path.resolve(rootDir, toProdFilePath(relMwPath));\n paths.push(prodAbsPath);\n break;\n }\n }\n if (currentDir === resolvedRoot) break;\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n\n // paths 是从路由目录向上收集的,需反转为根在前\n paths.reverse();\n return paths;\n}\n\n/**\n * 把序列化的路由清单写入 JS 模块\n *\n * 生成 ESM 模块,start 时通过 import() 加载。\n */\nexport async function writeRoutesModule(\n manifest: SerializedRouteManifest,\n outputPath: string,\n): Promise<void> {\n const dir = path.dirname(outputPath);\n await fs.promises.mkdir(dir, { recursive: true });\n\n // 用 JSON.stringify 嵌入,保证字符串转义安全\n const content = `// 自动生成,请勿手动编辑(faapi build 产物)\nexport const routes = ${JSON.stringify(manifest.routes, null, 2)};\nexport const wsRoutes = ${JSON.stringify(manifest.wsRoutes, null, 2)};\n`;\n\n await fs.promises.writeFile(outputPath, content, 'utf-8');\n}\n\n/**\n * 从序列化清单水合路由(加载中间件,还原 RouteRecord)\n *\n * start 时调用,对每条路由按 middlewarePaths 加载中间件文件。\n */\nexport async function hydrateRoutes(\n manifest: SerializedRouteManifest,\n): Promise<{ routes: RouteManifest; wsRoutes: WsRouteManifest }> {\n const hydrateRoute = async (\n serialized: SerializedRouteRecord,\n ): Promise<RouteRecord> => {\n const bundle = await loadMiddlewarePaths(serialized.middlewarePaths);\n return {\n method: serialized.method,\n urlPath: serialized.urlPath,\n filePath: serialized.filePath,\n paramNames: serialized.paramNames,\n isDynamic: serialized.isDynamic,\n isCatchAll: serialized.isCatchAll,\n middlewares: bundle?.middlewares,\n injectors: bundle?.injectors,\n };\n };\n\n const hydrateWsRoute = async (\n serialized: SerializedWsRouteRecord,\n ): Promise<WsRouteRecord> => {\n const bundle = await loadMiddlewarePaths(serialized.middlewarePaths);\n return {\n urlPath: serialized.urlPath,\n filePath: serialized.filePath,\n paramNames: serialized.paramNames,\n isDynamic: serialized.isDynamic,\n isCatchAll: serialized.isCatchAll,\n middlewares: bundle?.middlewares,\n injectors: bundle?.injectors,\n };\n };\n\n const routes = await Promise.all(manifest.routes.map(hydrateRoute));\n const wsRoutes = await Promise.all(manifest.wsRoutes.map(hydrateWsRoute));\n return { routes, wsRoutes };\n}\n\n/**\n * 按路径列表加载并合并中间件(根在前,路由目录在后)\n *\n * 与 scanRoutes.findMergedMiddlewares 的合并逻辑一致:\n * - 中间件:父级在前,子级追加在后(洋葱模型内层)\n * - 注入器:子级覆盖父级同名\n */\nasync function loadMiddlewarePaths(\n middlewarePaths: string[],\n): Promise<{ middlewares: FaapiMiddleware[]; injectors: InjectorMap } | undefined> {\n if (middlewarePaths.length === 0) return undefined;\n\n const mergedMiddlewares: FaapiMiddleware[] = [];\n const mergedInjectors: InjectorMap = {};\n\n for (const absMwPath of middlewarePaths) {\n let bundle: LoadedMiddlewareBundle | undefined = getCachedMiddlewares(absMwPath);\n if (bundle === undefined) {\n bundle = await loadMiddlewaresFile(absMwPath);\n setCachedMiddlewares(absMwPath, bundle);\n }\n mergedMiddlewares.push(...bundle.middlewares);\n for (const [name, injector] of Object.entries(bundle.injectors)) {\n mergedInjectors[name] = injector;\n }\n }\n\n return { middlewares: mergedMiddlewares, injectors: mergedInjectors };\n}\n","import { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { detectRouteConflicts } from '../router/detectRouteConflicts';\nimport { generateTypes } from './generateTypes';\nimport { writeSchemaModule } from './generateSchema';\nimport { serializeRoutes, writeRoutesModule } from './generateRoutes';\nimport { collectRouteSchemaSources } from './collectRouteSchemaSources';\nimport type { SchemaModuleEntry } from '../ast/generateValidatorCode';\nimport type { HandlerTypeInfo } from '../ast/extractHandlerTypes';\nimport type { RouteManifest } from '../router/routeTypes';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport fg from 'fast-glob';\n\n/**\n * 构建命令选项\n */\nexport interface BuildOptions {\n rootDir: string; // 项目根目录\n patterns: string[]; // 路由模式\n appDir: string; // app 目录\n outdir: string; // 输出目录\n types?: string; // 类型文件输出路径\n}\n\n/**\n * 执行构建命令\n *\n * faapi 是文件路由模式,无统一入口。build 命令逐个编译路由文件(保持目录结构),\n * 而非 bundle 成单文件,确保运行时动态 import 路径仍然有效。\n */\nexport async function buildCommand(options: BuildOptions): Promise<void> {\n const { rootDir, patterns, appDir, outdir, types } = options;\n\n console.log('faapi build started');\n console.log(`- Root: ${rootDir}`);\n console.log(`- Patterns: ${patterns.join(', ')}`);\n console.log(`- Output: ${outdir}`);\n\n // 1. 扫描路由\n console.log('\\n[1/5] Scanning routes...');\n const { routes, wsRoutes } = await scanRoutes(rootDir, patterns, appDir);\n const sorted = sortRoutes(routes);\n console.log(` Found ${sorted.length} routes, ${wsRoutes.length} WS routes`);\n\n // 检测路由冲突\n const conflicts = detectRouteConflicts(sorted);\n if (conflicts.length > 0) {\n console.warn('! 检测到路由冲突:');\n for (const conflict of conflicts) {\n console.warn(` ${conflict.method} ${conflict.urlPath}`);\n for (const file of conflict.files) {\n console.warn(` - ${file}`);\n }\n }\n }\n\n // 2. 生成类型文件\n console.log('\\n[2/5] Generating types...');\n const typesPath = types ? path.resolve(rootDir, types) : path.resolve(rootDir, 'faapi-types.ts');\n await generateTypes(sorted, rootDir, typesPath);\n console.log(` Written to ${typesPath}`);\n\n // 3. 生成 schema 模块(prd 运行时类型校验的数据来源)\n console.log('\\n[3/5] Generating schema module...');\n const schemaPath = path.resolve(rootDir, outdir, 'faapi-schema.js');\n const { entries, allTypesByFile } = extractSchemaEntries(sorted, rootDir);\n await writeSchemaModule(entries, allTypesByFile, schemaPath);\n console.log(` Written to ${schemaPath}`);\n\n // 4. 生成路由清单(prd 启动时直接读取,不再 scanRoutes)\n console.log('\\n[4/5] Generating routes manifest...');\n const routesPath = path.resolve(rootDir, outdir, 'faapi-routes.js');\n const serialized = serializeRoutes(sorted, wsRoutes, rootDir);\n await writeRoutesModule(serialized, routesPath);\n console.log(` Written to ${routesPath}`);\n\n // 5. 编译 TypeScript(逐文件编译,保持目录结构)\n console.log('\\n[5/5] Compiling TypeScript...');\n await compileTypeScript(rootDir, patterns, appDir, outdir);\n console.log(' Done');\n\n console.log('\\nfaapi build completed');\n}\n\n/**\n * 编译 TypeScript 文件\n *\n * 使用 esbuild 逐文件编译(不 bundle),保持目录结构,\n * 这样运行时动态 import 的文件路径在编译后仍然有效。\n */\nasync function compileTypeScript(\n rootDir: string,\n patterns: string[],\n appDir: string,\n outdir: string,\n): Promise<void> {\n const esbuild = await import('esbuild');\n\n // 收集所有需要编译的 .ts 文件(路由文件 + 中间件文件)\n const allPatterns = [...patterns, `${appDir}/**/middlewares.ts`];\n const files = await fg(allPatterns, {\n cwd: rootDir,\n onlyFiles: true,\n absolute: true,\n });\n\n if (files.length === 0) {\n console.log(' No TypeScript files to compile');\n return;\n }\n\n // 确保输出目录存在\n const absOutdir = path.resolve(rootDir, outdir);\n await fs.promises.mkdir(absOutdir, { recursive: true });\n\n // 逐文件编译,保持目录结构(outbase 保证相对路径)\n await esbuild.build({\n entryPoints: files,\n outdir: absOutdir,\n outbase: rootDir,\n bundle: false, // 不 bundle,逐文件编译\n platform: 'node',\n format: 'esm',\n sourcemap: true,\n packages: 'external', // 依赖保持外部引用\n logLevel: 'info',\n });\n}\n\n/**\n * 从路由清单提取 schema entries 和 allTypesByFile\n *\n * 用于 build 时生成 schema JS 模块。\n */\nfunction extractSchemaEntries(\n routes: RouteManifest,\n rootDir: string,\n): {\n entries: SchemaModuleEntry[];\n allTypesByFile: Map<string, Map<string, HandlerTypeInfo>>;\n} {\n const { sources, allTypesByFile } = collectRouteSchemaSources(routes, rootDir);\n const entries: SchemaModuleEntry[] = sources.map(({ filePath, schemaName, typeInfo }) => ({\n filePath,\n schemaName,\n typeInfo,\n }));\n return { entries, allTypesByFile };\n}\n\n/**\n * 解析构建命令参数\n */\nexport function parseBuildArgs(argv: string[]): BuildOptions {\n const rootDir = process.cwd();\n let outdir = 'dist';\n let appDir = 'src';\n let types: string | undefined;\n const patterns: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--outdir' || arg === '-o') {\n outdir = argv[++i];\n } else if (arg === '--app-dir') {\n appDir = argv[++i];\n } else if (arg === '--types') {\n types = argv[++i];\n } else if (!arg.startsWith('-')) {\n patterns.push(arg);\n }\n }\n\n // 默认扫描 <appDir>/api/**/*.ts(与 parseArgs 保持一致)\n // --app-dir . 时为 api/**/*.ts\n const defaultPattern = appDir === '.' ? 'api/**/*.ts' : `${appDir}/api/**/*.ts`;\n\n return {\n rootDir,\n patterns: patterns.length > 0 ? patterns : [defaultPattern],\n appDir,\n outdir,\n types,\n };\n}\n","import { EventEmitter } from 'events';\n\nfunction toArr(any) {\n\treturn any == null ? [] : Array.isArray(any) ? any : [any];\n}\n\nfunction toVal(out, key, val, opts) {\n\tvar x, old=out[key], nxt=(\n\t\t!!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))\n\t\t: typeof val === 'boolean' ? val\n\t\t: !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))\n\t\t: (x = +val,x * 0 === 0) ? x : val\n\t);\n\tout[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);\n}\n\nfunction mri2 (args, opts) {\n\targs = args || [];\n\topts = opts || {};\n\n\tvar k, arr, arg, name, val, out={ _:[] };\n\tvar i=0, j=0, idx=0, len=args.length;\n\n\tconst alibi = opts.alias !== void 0;\n\tconst strict = opts.unknown !== void 0;\n\tconst defaults = opts.default !== void 0;\n\n\topts.alias = opts.alias || {};\n\topts.string = toArr(opts.string);\n\topts.boolean = toArr(opts.boolean);\n\n\tif (alibi) {\n\t\tfor (k in opts.alias) {\n\t\t\tarr = opts.alias[k] = toArr(opts.alias[k]);\n\t\t\tfor (i=0; i < arr.length; i++) {\n\t\t\t\t(opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (i=opts.boolean.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.boolean[i]] || [];\n\t\tfor (j=arr.length; j-- > 0;) opts.boolean.push(arr[j]);\n\t}\n\n\tfor (i=opts.string.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.string[i]] || [];\n\t\tfor (j=arr.length; j-- > 0;) opts.string.push(arr[j]);\n\t}\n\n\tif (defaults) {\n\t\tfor (k in opts.default) {\n\t\t\tname = typeof opts.default[k];\n\t\t\tarr = opts.alias[k] = opts.alias[k] || [];\n\t\t\tif (opts[name] !== void 0) {\n\t\t\t\topts[name].push(k);\n\t\t\t\tfor (i=0; i < arr.length; i++) {\n\t\t\t\t\topts[name].push(arr[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst keys = strict ? Object.keys(opts.alias) : [];\n\n\tfor (i=0; i < len; i++) {\n\t\targ = args[i];\n\n\t\tif (arg === '--') {\n\t\t\tout._ = out._.concat(args.slice(++i));\n\t\t\tbreak;\n\t\t}\n\n\t\tfor (j=0; j < arg.length; j++) {\n\t\t\tif (arg.charCodeAt(j) !== 45) break; // \"-\"\n\t\t}\n\n\t\tif (j === 0) {\n\t\t\tout._.push(arg);\n\t\t} else if (arg.substring(j, j + 3) === 'no-') {\n\t\t\tname = arg.substring(j + 3);\n\t\t\tif (strict && !~keys.indexOf(name)) {\n\t\t\t\treturn opts.unknown(arg);\n\t\t\t}\n\t\t\tout[name] = false;\n\t\t} else {\n\t\t\tfor (idx=j+1; idx < arg.length; idx++) {\n\t\t\t\tif (arg.charCodeAt(idx) === 61) break; // \"=\"\n\t\t\t}\n\n\t\t\tname = arg.substring(j, idx);\n\t\t\tval = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);\n\t\t\tarr = (j === 2 ? [name] : name);\n\n\t\t\tfor (idx=0; idx < arr.length; idx++) {\n\t\t\t\tname = arr[idx];\n\t\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);\n\t\t\t\ttoVal(out, name, (idx + 1 < arr.length) || val, opts);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (defaults) {\n\t\tfor (k in opts.default) {\n\t\t\tif (out[k] === void 0) {\n\t\t\t\tout[k] = opts.default[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (alibi) {\n\t\tfor (k in out) {\n\t\t\tarr = opts.alias[k] || [];\n\t\t\twhile (arr.length > 0) {\n\t\t\t\tout[arr.shift()] = out[k];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\nconst removeBrackets = (v) => v.replace(/[<[].+/, \"\").trim();\nconst findAllBrackets = (v) => {\n const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;\n const SQUARE_BRACKET_RE_GLOBAL = /\\[([^\\]]+)\\]/g;\n const res = [];\n const parse = (match) => {\n let variadic = false;\n let value = match[1];\n if (value.startsWith(\"...\")) {\n value = value.slice(3);\n variadic = true;\n }\n return {\n required: match[0].startsWith(\"<\"),\n value,\n variadic\n };\n };\n let angledMatch;\n while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {\n res.push(parse(angledMatch));\n }\n let squareMatch;\n while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {\n res.push(parse(squareMatch));\n }\n return res;\n};\nconst getMriOptions = (options) => {\n const result = {alias: {}, boolean: []};\n for (const [index, option] of options.entries()) {\n if (option.names.length > 1) {\n result.alias[option.names[0]] = option.names.slice(1);\n }\n if (option.isBoolean) {\n if (option.negated) {\n const hasStringTypeOption = options.some((o, i) => {\n return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === \"boolean\";\n });\n if (!hasStringTypeOption) {\n result.boolean.push(option.names[0]);\n }\n } else {\n result.boolean.push(option.names[0]);\n }\n }\n }\n return result;\n};\nconst findLongest = (arr) => {\n return arr.sort((a, b) => {\n return a.length > b.length ? -1 : 1;\n })[0];\n};\nconst padRight = (str, length) => {\n return str.length >= length ? str : `${str}${\" \".repeat(length - str.length)}`;\n};\nconst camelcase = (input) => {\n return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {\n return p1 + p2.toUpperCase();\n });\n};\nconst setDotProp = (obj, keys, val) => {\n let i = 0;\n let length = keys.length;\n let t = obj;\n let x;\n for (; i < length; ++i) {\n x = t[keys[i]];\n t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(\".\") || !(+keys[i + 1] > -1) ? {} : [];\n }\n};\nconst setByType = (obj, transforms) => {\n for (const key of Object.keys(transforms)) {\n const transform = transforms[key];\n if (transform.shouldTransform) {\n obj[key] = Array.prototype.concat.call([], obj[key]);\n if (typeof transform.transformFunction === \"function\") {\n obj[key] = obj[key].map(transform.transformFunction);\n }\n }\n }\n};\nconst getFileName = (input) => {\n const m = /([^\\\\\\/]+)$/.exec(input);\n return m ? m[1] : \"\";\n};\nconst camelcaseOptionName = (name) => {\n return name.split(\".\").map((v, i) => {\n return i === 0 ? camelcase(v) : v;\n }).join(\".\");\n};\nclass CACError extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === \"function\") {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = new Error(message).stack;\n }\n }\n}\n\nclass Option {\n constructor(rawName, description, config) {\n this.rawName = rawName;\n this.description = description;\n this.config = Object.assign({}, config);\n rawName = rawName.replace(/\\.\\*/g, \"\");\n this.negated = false;\n this.names = removeBrackets(rawName).split(\",\").map((v) => {\n let name = v.trim().replace(/^-{1,2}/, \"\");\n if (name.startsWith(\"no-\")) {\n this.negated = true;\n name = name.replace(/^no-/, \"\");\n }\n return camelcaseOptionName(name);\n }).sort((a, b) => a.length > b.length ? 1 : -1);\n this.name = this.names[this.names.length - 1];\n if (this.negated && this.config.default == null) {\n this.config.default = true;\n }\n if (rawName.includes(\"<\")) {\n this.required = true;\n } else if (rawName.includes(\"[\")) {\n this.required = false;\n } else {\n this.isBoolean = true;\n }\n }\n}\n\nconst processArgs = process.argv;\nconst platformInfo = `${process.platform}-${process.arch} node-${process.version}`;\n\nclass Command {\n constructor(rawName, description, config = {}, cli) {\n this.rawName = rawName;\n this.description = description;\n this.config = config;\n this.cli = cli;\n this.options = [];\n this.aliasNames = [];\n this.name = removeBrackets(rawName);\n this.args = findAllBrackets(rawName);\n this.examples = [];\n }\n usage(text) {\n this.usageText = text;\n return this;\n }\n allowUnknownOptions() {\n this.config.allowUnknownOptions = true;\n return this;\n }\n ignoreOptionDefaultValue() {\n this.config.ignoreOptionDefaultValue = true;\n return this;\n }\n version(version, customFlags = \"-v, --version\") {\n this.versionNumber = version;\n this.option(customFlags, \"Display version number\");\n return this;\n }\n example(example) {\n this.examples.push(example);\n return this;\n }\n option(rawName, description, config) {\n const option = new Option(rawName, description, config);\n this.options.push(option);\n return this;\n }\n alias(name) {\n this.aliasNames.push(name);\n return this;\n }\n action(callback) {\n this.commandAction = callback;\n return this;\n }\n isMatched(name) {\n return this.name === name || this.aliasNames.includes(name);\n }\n get isDefaultCommand() {\n return this.name === \"\" || this.aliasNames.includes(\"!\");\n }\n get isGlobalCommand() {\n return this instanceof GlobalCommand;\n }\n hasOption(name) {\n name = name.split(\".\")[0];\n return this.options.find((option) => {\n return option.names.includes(name);\n });\n }\n outputHelp() {\n const {name, commands} = this.cli;\n const {\n versionNumber,\n options: globalOptions,\n helpCallback\n } = this.cli.globalCommand;\n let sections = [\n {\n body: `${name}${versionNumber ? `/${versionNumber}` : \"\"}`\n }\n ];\n sections.push({\n title: \"Usage\",\n body: ` $ ${name} ${this.usageText || this.rawName}`\n });\n const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;\n if (showCommands) {\n const longestCommandName = findLongest(commands.map((command) => command.rawName));\n sections.push({\n title: \"Commands\",\n body: commands.map((command) => {\n return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;\n }).join(\"\\n\")\n });\n sections.push({\n title: `For more info, run any command with the \\`--help\\` flag`,\n body: commands.map((command) => ` $ ${name}${command.name === \"\" ? \"\" : ` ${command.name}`} --help`).join(\"\\n\")\n });\n }\n let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];\n if (!this.isGlobalCommand && !this.isDefaultCommand) {\n options = options.filter((option) => option.name !== \"version\");\n }\n if (options.length > 0) {\n const longestOptionName = findLongest(options.map((option) => option.rawName));\n sections.push({\n title: \"Options\",\n body: options.map((option) => {\n return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? \"\" : `(default: ${option.config.default})`}`;\n }).join(\"\\n\")\n });\n }\n if (this.examples.length > 0) {\n sections.push({\n title: \"Examples\",\n body: this.examples.map((example) => {\n if (typeof example === \"function\") {\n return example(name);\n }\n return example;\n }).join(\"\\n\")\n });\n }\n if (helpCallback) {\n sections = helpCallback(sections) || sections;\n }\n console.log(sections.map((section) => {\n return section.title ? `${section.title}:\n${section.body}` : section.body;\n }).join(\"\\n\\n\"));\n }\n outputVersion() {\n const {name} = this.cli;\n const {versionNumber} = this.cli.globalCommand;\n if (versionNumber) {\n console.log(`${name}/${versionNumber} ${platformInfo}`);\n }\n }\n checkRequiredArgs() {\n const minimalArgsCount = this.args.filter((arg) => arg.required).length;\n if (this.cli.args.length < minimalArgsCount) {\n throw new CACError(`missing required args for command \\`${this.rawName}\\``);\n }\n }\n checkUnknownOptions() {\n const {options, globalCommand} = this.cli;\n if (!this.config.allowUnknownOptions) {\n for (const name of Object.keys(options)) {\n if (name !== \"--\" && !this.hasOption(name) && !globalCommand.hasOption(name)) {\n throw new CACError(`Unknown option \\`${name.length > 1 ? `--${name}` : `-${name}`}\\``);\n }\n }\n }\n }\n checkOptionValue() {\n const {options: parsedOptions, globalCommand} = this.cli;\n const options = [...globalCommand.options, ...this.options];\n for (const option of options) {\n const value = parsedOptions[option.name.split(\".\")[0]];\n if (option.required) {\n const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));\n if (value === true || value === false && !hasNegated) {\n throw new CACError(`option \\`${option.rawName}\\` value is missing`);\n }\n }\n }\n }\n}\nclass GlobalCommand extends Command {\n constructor(cli) {\n super(\"@@global@@\", \"\", {}, cli);\n }\n}\n\nvar __assign = Object.assign;\nclass CAC extends EventEmitter {\n constructor(name = \"\") {\n super();\n this.name = name;\n this.commands = [];\n this.rawArgs = [];\n this.args = [];\n this.options = {};\n this.globalCommand = new GlobalCommand(this);\n this.globalCommand.usage(\"<command> [options]\");\n }\n usage(text) {\n this.globalCommand.usage(text);\n return this;\n }\n command(rawName, description, config) {\n const command = new Command(rawName, description || \"\", config, this);\n command.globalCommand = this.globalCommand;\n this.commands.push(command);\n return command;\n }\n option(rawName, description, config) {\n this.globalCommand.option(rawName, description, config);\n return this;\n }\n help(callback) {\n this.globalCommand.option(\"-h, --help\", \"Display this message\");\n this.globalCommand.helpCallback = callback;\n this.showHelpOnExit = true;\n return this;\n }\n version(version, customFlags = \"-v, --version\") {\n this.globalCommand.version(version, customFlags);\n this.showVersionOnExit = true;\n return this;\n }\n example(example) {\n this.globalCommand.example(example);\n return this;\n }\n outputHelp() {\n if (this.matchedCommand) {\n this.matchedCommand.outputHelp();\n } else {\n this.globalCommand.outputHelp();\n }\n }\n outputVersion() {\n this.globalCommand.outputVersion();\n }\n setParsedInfo({args, options}, matchedCommand, matchedCommandName) {\n this.args = args;\n this.options = options;\n if (matchedCommand) {\n this.matchedCommand = matchedCommand;\n }\n if (matchedCommandName) {\n this.matchedCommandName = matchedCommandName;\n }\n return this;\n }\n unsetMatchedCommand() {\n this.matchedCommand = void 0;\n this.matchedCommandName = void 0;\n }\n parse(argv = processArgs, {\n run = true\n } = {}) {\n this.rawArgs = argv;\n if (!this.name) {\n this.name = argv[1] ? getFileName(argv[1]) : \"cli\";\n }\n let shouldParse = true;\n for (const command of this.commands) {\n const parsed = this.mri(argv.slice(2), command);\n const commandName = parsed.args[0];\n if (command.isMatched(commandName)) {\n shouldParse = false;\n const parsedInfo = __assign(__assign({}, parsed), {\n args: parsed.args.slice(1)\n });\n this.setParsedInfo(parsedInfo, command, commandName);\n this.emit(`command:${commandName}`, command);\n }\n }\n if (shouldParse) {\n for (const command of this.commands) {\n if (command.name === \"\") {\n shouldParse = false;\n const parsed = this.mri(argv.slice(2), command);\n this.setParsedInfo(parsed, command);\n this.emit(`command:!`, command);\n }\n }\n }\n if (shouldParse) {\n const parsed = this.mri(argv.slice(2));\n this.setParsedInfo(parsed);\n }\n if (this.options.help && this.showHelpOnExit) {\n this.outputHelp();\n run = false;\n this.unsetMatchedCommand();\n }\n if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {\n this.outputVersion();\n run = false;\n this.unsetMatchedCommand();\n }\n const parsedArgv = {args: this.args, options: this.options};\n if (run) {\n this.runMatchedCommand();\n }\n if (!this.matchedCommand && this.args[0]) {\n this.emit(\"command:*\");\n }\n return parsedArgv;\n }\n mri(argv, command) {\n const cliOptions = [\n ...this.globalCommand.options,\n ...command ? command.options : []\n ];\n const mriOptions = getMriOptions(cliOptions);\n let argsAfterDoubleDashes = [];\n const doubleDashesIndex = argv.indexOf(\"--\");\n if (doubleDashesIndex > -1) {\n argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);\n argv = argv.slice(0, doubleDashesIndex);\n }\n let parsed = mri2(argv, mriOptions);\n parsed = Object.keys(parsed).reduce((res, name) => {\n return __assign(__assign({}, res), {\n [camelcaseOptionName(name)]: parsed[name]\n });\n }, {_: []});\n const args = parsed._;\n const options = {\n \"--\": argsAfterDoubleDashes\n };\n const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;\n let transforms = Object.create(null);\n for (const cliOption of cliOptions) {\n if (!ignoreDefault && cliOption.config.default !== void 0) {\n for (const name of cliOption.names) {\n options[name] = cliOption.config.default;\n }\n }\n if (Array.isArray(cliOption.config.type)) {\n if (transforms[cliOption.name] === void 0) {\n transforms[cliOption.name] = Object.create(null);\n transforms[cliOption.name][\"shouldTransform\"] = true;\n transforms[cliOption.name][\"transformFunction\"] = cliOption.config.type[0];\n }\n }\n }\n for (const key of Object.keys(parsed)) {\n if (key !== \"_\") {\n const keys = key.split(\".\");\n setDotProp(options, keys, parsed[key]);\n setByType(options, transforms);\n }\n }\n return {\n args,\n options\n };\n }\n runMatchedCommand() {\n const {args, options, matchedCommand: command} = this;\n if (!command || !command.commandAction)\n return;\n command.checkUnknownOptions();\n command.checkOptionValue();\n command.checkRequiredArgs();\n const actionArgs = [];\n command.args.forEach((arg, index) => {\n if (arg.variadic) {\n actionArgs.push(args.slice(index));\n } else {\n actionArgs.push(args[index]);\n }\n });\n actionArgs.push(options);\n return command.commandAction.apply(this, actionArgs);\n }\n}\n\nconst cac = (name = \"\") => new CAC(name);\n\nexport default cac;\nexport { CAC, Command, cac };\n","/**\n * 将逗号分隔的 pattern 字符串拆分为数组\n * 'api/auth/*,api/novel/*' -> ['api/auth/*', 'api/novel/*']\n * 'api/auth/*' -> ['api/auth/*']\n */\nexport function normalizePatterns(patterns: string[]): string[] {\n return patterns\n .flatMap((p) => p.split(','))\n .map((p) => p.trim())\n .filter((p) => p.length > 0);\n}\n","import { cac } from 'cac';\nimport { normalizePatterns } from './normalizePatterns';\n\nexport type CliMode = 'dev' | 'start';\n\nexport interface CliArgs {\n /** 启动模式:dev=开发模式(加载 .ts),start=生产模式(加载 dist/*.js) */\n mode: CliMode;\n patterns: string[];\n port: number;\n appDir: string;\n cors: boolean;\n staticDir?: string;\n types?: string;\n config?: string;\n}\n\n/** 命令词 → mode 映射 */\nconst COMMAND_MODES: Record<string, CliMode> = {\n dev: 'dev',\n start: 'start',\n};\n\n/**\n * 解析 CLI 参数\n * 支持:\n * - faapi # dev 模式,扫描 src/api 下的 .ts\n * - faapi dev # 同上\n * - faapi start # prd 模式,加载 dist 下的 .js(需先 faapi build)\n * - faapi api/auth/ # 指定 patterns\n * - faapi --port 3000 api/auth/\n * - faapi --app-dir . api/auth/ # 显式回退到项目根目录\n *\n * 端口优先级:--port > PORT 环境变量 > 默认 3000\n */\nexport function parseArgs(argv: string[]): CliArgs {\n const cli = cac('faapi');\n\n cli\n .option('--port <port>', 'Server port (env: PORT)')\n .option('--app-dir <dir>', 'App directory (src by default)', { default: 'src' })\n .option('--cors', 'Enable CORS (default in dev mode)')\n .option('--no-cors', 'Disable CORS')\n .option('--static <dir>', 'Static files directory', { default: undefined })\n .option('--no-static', 'Disable static file serving')\n .option('--types <path>', 'Output path for generated types file')\n .option('--config <path>', 'Path to config file (faapi.config.ts)');\n\n const { args, options } = cli.parse(['', '', ...argv]);\n\n // 第一个非命令词的位置参数为 patterns,其余为命令词\n // 命令词仅 dev/start,其他词(如 'build')由上层 cli/index.ts 分发,不进 parseArgs\n let mode: CliMode = 'dev';\n const rawPatterns: string[] = [];\n for (const arg of args) {\n const str = String(arg);\n if (str in COMMAND_MODES) {\n mode = COMMAND_MODES[str];\n } else {\n rawPatterns.push(str);\n }\n }\n const patterns = normalizePatterns(rawPatterns);\n\n // 端口优先级:--port > PORT 环境变量 > 3000\n const port = options.port ? Number(options.port) : Number(process.env.PORT) || 3000;\n\n const appDir = String(options.appDir ?? 'src');\n\n // CORS: --no-cors 显式禁用,否则默认启用\n const cors = options.cors !== false;\n\n // Static: --no-static 显式禁用,--static <dir> 指定目录\n const staticDir: string | undefined =\n options.static === false ? undefined : (options.static as string | undefined);\n\n // 默认扫描 patterns\n // dev 模式:扫描 <appDir>/api/**/*.ts(--app-dir . 时为 api/**/*.ts)\n // start 模式:加载 dist 下的 .js,由 startCommand.adjustForProd 调整\n const defaultPattern = appDir === '.' ? 'api/**/*.ts' : `${appDir}/api/**/*.ts`;\n\n return {\n mode,\n patterns: patterns.length > 0 ? patterns : [defaultPattern],\n port,\n appDir,\n cors,\n staticDir,\n types: options.types as string | undefined,\n config: options.config as string | undefined,\n };\n}\n","import type { RouteManifest, RouteMatch, WsRouteManifest, WsRouteMatch } from './routeTypes';\n\n/**\n * 根据请求路径和方法匹配路由\n * @param routes 已排序的路由清单\n * @param method HTTP 方法\n * @param path 请求路径\n * @returns 匹配结果,包含路由记录和参数\n */\nexport function matchRoute(routes: RouteManifest, method: string, path: string): RouteMatch | null {\n for (const route of routes) {\n // 方法不匹配,跳过\n if (route.method !== method) {\n continue;\n }\n\n // 静态路由直接比较\n if (!route.isDynamic) {\n if (route.urlPath === path) {\n return { route, params: {} };\n }\n continue;\n }\n\n // 动态路由匹配\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n return { route, params };\n }\n }\n\n return null;\n}\n\n/**\n * 匹配 WebSocket 路由(无 HTTP 方法维度)\n *\n * WS 路由只按路径匹配,协议升级时调用。\n * @param wsRoutes WebSocket 路由清单\n * @param path 请求路径\n */\nexport function matchWsRoute(wsRoutes: WsRouteManifest, path: string): WsRouteMatch | null {\n for (const route of wsRoutes) {\n // 静态路由直接比较\n if (!route.isDynamic) {\n if (route.urlPath === path) {\n return { route, params: {} };\n }\n continue;\n }\n\n // 动态路由匹配\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n return { route, params };\n }\n }\n\n return null;\n}\n\n/**\n * 动态路径匹配\n * 将路由模式(如 /user/:id)与请求路径(如 /user/123)匹配\n * 支持 catch-all 路由(如 /shop/:...slug 匹配 /shop/clothes/tops)\n * 返回提取的参数对象,不匹配返回 null\n */\nexport function matchDynamicPath(\n pattern: string,\n path: string,\n paramNames: string[],\n isCatchAll?: boolean,\n): Record<string, string> | null {\n const patternSegments = pattern.split('/').filter(Boolean);\n const pathSegments = path.split('/').filter(Boolean);\n\n // catch-all 路由:最后一个模式段为 :...slug\n if (isCatchAll) {\n // catch-all 前面的静态/动态段必须匹配\n // catch-all 段至少匹配一个路径段\n const nonCatchAllCount = patternSegments.length - 1;\n if (pathSegments.length <= nonCatchAllCount) {\n return null;\n }\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < nonCatchAllCount; i++) {\n const patternSeg = patternSegments[i];\n const pathSeg = pathSegments[i];\n\n if (patternSeg.startsWith(':')) {\n const paramName = patternSeg.slice(1);\n params[paramName] = pathSeg;\n } else if (patternSeg !== pathSeg) {\n return null;\n }\n }\n\n // catch-all 段:剩余所有路径段用 / 连接\n const catchAllValue = pathSegments.slice(nonCatchAllCount).join('/');\n const catchAllParamName = patternSegments[nonCatchAllCount].slice(4); // 去掉 ':...'\n params[catchAllParamName] = catchAllValue;\n\n if (Object.keys(params).length !== paramNames.length) {\n return null;\n }\n\n return params;\n }\n\n // 普通动态路由:段数必须一致\n if (patternSegments.length !== pathSegments.length) {\n return null;\n }\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSeg = patternSegments[i];\n const pathSeg = pathSegments[i];\n\n if (patternSeg.startsWith(':')) {\n // 动态段,提取参数值\n const paramName = patternSeg.slice(1);\n params[paramName] = pathSeg;\n } else if (patternSeg !== pathSeg) {\n // 静态段不匹配\n return null;\n }\n }\n\n // 确保所有参数名都被提取到\n if (Object.keys(params).length !== paramNames.length) {\n return null;\n }\n\n return params;\n}\n","/**\n * 从模块中解析出指定名称的导出\n *\n * 解析顺序:\n * 1. 具名导出:export function GET() {}\n * 2. 默认导出的对象属性:export default { GET() {} }\n *\n * @param module 动态 import 得到的模块对象\n * @param exportName 导出名(如 'GET')\n */\nexport function resolveExport(module: Record<string, unknown>, exportName: string): unknown {\n // 1. 具名导出\n if (exportName in module && typeof module[exportName] !== 'undefined') {\n return module[exportName];\n }\n\n // 2. 默认导出的对象属性\n const defaultExport = module.default;\n if (defaultExport !== null && typeof defaultExport === 'object') {\n const value = (defaultExport as Record<string, unknown>)[exportName];\n if (value !== undefined) {\n return value;\n }\n }\n\n return undefined;\n}\n","/**\n * 校验导出值是否为合法的 handler 函数\n */\nexport function validateRouteModule(\n value: unknown,\n method: string,\n filePath: string,\n): asserts value is (...args: unknown[]) => unknown {\n if (typeof value !== 'function') {\n throw new Error(\n `Route module \"${filePath}\" does not export a valid handler for method \"${method}\". ` +\n `Expected a function, got ${typeof value}.`,\n );\n }\n}\n","import type { HttpMethod } from '../router/constants';\nimport { resolveExport } from './resolveExports';\nimport { validateRouteModule } from './validateRouteModule';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\nexport interface RouteModule {\n handler: (...args: unknown[]) => unknown;\n method: HttpMethod;\n}\n\n/**\n * 动态 import 路由文件并提取 handler\n * @param filePath 路由文件的绝对路径\n * @param method HTTP 方法名(也是导出名)\n */\nexport async function loadRouteModule(filePath: string, method: HttpMethod): Promise<RouteModule> {\n let module: Record<string, unknown>;\n try {\n module = await importWithCacheBust(filePath);\n } catch (err: unknown) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load route module \"${filePath}\": ${reason}`, { cause: err });\n }\n\n const handler = resolveExport(module, method);\n validateRouteModule(handler, method, filePath);\n\n return { handler, method };\n}\n","/**\n * SSE(Server-Sent Events)支持\n *\n * 让 handler 能向客户端推送流式事件,用于 LLM token 流、进度通知等场景。\n *\n * 核心导出:\n * - `encodeSseEvent(event)`:把 SSE 事件对象编码为符合 HTML5 SSE 规范的字符串\n * - `createSseWriter()`:创建一个 SseWriter,封装 ReadableStream + Response,提供 send/close/sendError API\n * - `SseWriter`:writer 类型,ctx.sse() 返回此类型\n *\n * 设计要点:\n * - writer 内部用 ReadableStream + TextEncoder,send 时 enqueue,close 时 close controller\n * - response 预设 text/event-stream、no-cache、keep-alive 头,状态码默认 200\n * - close 后再 send 静默忽略,避免 handler 异步流程中误写已关闭的流\n * - sendError 向流写入 event: error 后关闭,用于流式输出中报错的优雅终止\n *\n * 与 ctx 的集成:\n * - ctx.sse() 调用 createSseWriter(),并把 response 缓存到 ctx 内部字段\n * - invokeHandler 在 handler 返回后检查 ctx 是否持有 SSE response,有则优先使用\n */\n\n/**\n * SSE 事件字段\n *\n * 遵循 HTML5 SSE 规范:\n * - `data`:消息数据,多行时每行加 `data: ` 前缀;对象自动 JSON.stringify\n * - `event`:事件类型,客户端可用 addEventListener(event) 监听\n * - `id`:事件 ID,客户端断线重连时通过 Last-Event-ID 头发送\n * - `retry`:重连等待时间(毫秒)\n * - `comment`:注释行(以 `:` 开头),用于 keep-alive 心跳,不传递给客户端消息\n */\nexport interface SseEvent {\n /** 消息数据。字符串原样输出;对象自动 JSON.stringify;多行时每行加 data: 前缀 */\n data?: unknown;\n /** 事件类型,客户端可用 addEventListener 监听 */\n event?: string;\n /** 事件 ID,客户端断线重连时通过 Last-Event-ID 头发送 */\n id?: string | number;\n /** 重连等待时间(毫秒) */\n retry?: number;\n /** 注释行(以 : 开头),用于 keep-alive 心跳 */\n comment?: string;\n}\n\n/**\n * 把 SSE 事件对象编码为符合 HTML5 SSE 规范的字符串\n *\n * 字段顺序固定:comment > event > id > retry > data,末尾空行分隔事件。\n *\n * @param event SSE 事件对象\n * @returns 编码后的字符串(含末尾空行)\n */\nexport function encodeSseEvent(event: SseEvent): string {\n let out = '';\n\n // comment(注释行,以 : 开头)\n if (event.comment !== undefined) {\n out += `: ${event.comment}\\n`;\n }\n\n // event\n if (event.event !== undefined) {\n out += `event: ${event.event}\\n`;\n }\n\n // id\n if (event.id !== undefined) {\n out += `id: ${event.id}\\n`;\n }\n\n // retry\n if (event.retry !== undefined) {\n out += `retry: ${event.retry}\\n`;\n }\n\n // data:对象 JSON.stringify,多行每行加前缀\n if (event.data !== undefined) {\n let dataStr: string;\n if (typeof event.data === 'string') {\n dataStr = event.data;\n } else if (event.data === null) {\n dataStr = 'null';\n } else {\n dataStr = JSON.stringify(event.data);\n }\n // 多行 data:每行加 data: 前缀\n const lines = dataStr.split('\\n');\n for (const line of lines) {\n out += `data: ${line}\\n`;\n }\n }\n\n // 空行结束事件\n out += '\\n';\n return out;\n}\n\n/**\n * SSE writer:封装流式推送 API\n *\n * 通过 `ctx.sse()` 创建,handler 调用 `send` 推送事件,`close` 关闭流。\n * 框架在 handler 返回后,自动使用 writer.response 作为 HTTP 响应。\n */\nexport interface SseWriter {\n /** 推送一个 SSE 事件 */\n send(event: SseEvent): void;\n /** 推送一个 error 事件并关闭流(用于流式输出中报错的优雅终止) */\n sendError(error: unknown): void;\n /** 关闭流(多次调用安全) */\n close(): void;\n /** 流是否已关闭(handler 主动 close 或框架自动 close) */\n readonly closed: boolean;\n /** 客户端是否已断开(ReadableStream 被 cancel) */\n readonly aborted: boolean;\n /** 对应的 HTTP Response(由框架使用,用户一般不需要直接访问) */\n readonly response: Response;\n}\n\n/**\n * 创建一个 SSE writer\n *\n * 内部用 ReadableStream + TextEncoder 实现,send 时把编码后的事件 enqueue 到流,\n * close 时关闭 controller。response 预设标准 SSE 头。\n *\n * aborted 检测:监听 ReadableStream 的 cancel 钩子,客户端断开(cancel)时置为 true。\n * 此时 send 静默忽略,handler 可通过 writer.aborted 退出循环。\n */\nexport function createSseWriter(): SseWriter {\n const encoder = new TextEncoder();\n let controller: ReadableStreamDefaultController<Uint8Array> | null = null;\n let closed = false;\n let aborted = false;\n\n const stream = new ReadableStream<Uint8Array>({\n start(c) {\n controller = c;\n },\n cancel() {\n // 客户端断开连接(cancel ReadableStream)\n aborted = true;\n closed = true;\n controller = null;\n },\n });\n\n const response = new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n\n const writer: SseWriter = {\n send(event: SseEvent): void {\n if (closed || !controller) return;\n const text = encodeSseEvent(event);\n controller.enqueue(encoder.encode(text));\n },\n\n sendError(error: unknown): void {\n if (closed || !controller) return;\n const message = error instanceof Error ? error.message : String(error);\n const text = encodeSseEvent({ event: 'error', data: message });\n try {\n controller.enqueue(encoder.encode(text));\n } finally {\n writer.close();\n }\n },\n\n close(): void {\n if (closed) return;\n closed = true;\n if (controller) {\n try {\n controller.close();\n } catch {\n // controller 可能已关闭,忽略\n }\n controller = null;\n }\n },\n\n get closed(): boolean {\n return closed;\n },\n\n get aborted(): boolean {\n return aborted;\n },\n\n get response(): Response {\n return response;\n },\n };\n\n return writer;\n}\n","import type { FaapiContext, ResponseMeta, CookieOptions } from './contextTypes';\nimport { createSseWriter, type SseWriter } from './sse';\n\n/**\n * 解析 Cookie 请求头为 Map\n */\nfunction parseCookies(cookieHeader: string): Map<string, string> {\n const cookies = new Map<string, string>();\n if (!cookieHeader) return cookies;\n for (const pair of cookieHeader.split(';')) {\n const [name, ...rest] = pair.split('=');\n const trimmed = name?.trim();\n if (trimmed) {\n cookies.set(trimmed, rest.join('=').trim());\n }\n }\n return cookies;\n}\n\n/**\n * 格式化 Set-Cookie 值\n */\nfunction formatSetCookie(name: string, value: string, options?: CookieOptions): string {\n let cookie = `${name}=${value}`;\n if (options?.domain) cookie += `; Domain=${options.domain}`;\n if (options?.path) cookie += `; Path=${options.path}`;\n if (options?.maxAge !== undefined) cookie += `; Max-Age=${options.maxAge}`;\n if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;\n if (options?.httpOnly) cookie += `; HttpOnly`;\n if (options?.secure) cookie += `; Secure`;\n if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;\n return cookie;\n}\n\n/**\n * 从 Request 对象创建 FaapiContext\n * @param request Web Request 对象\n * @param params 动态路由参数\n * @param config 自定义业务配置(来自 faapi.config.ts)\n * @param ip 客户端 IP(由调用方从 IncomingMessage 提取,HTTP/WS 握手均通过 utils/getClientIp)\n */\nexport function createContext(\n request: Request,\n params: Record<string, string>,\n config: Record<string, unknown> = {},\n ip: string = '',\n): FaapiContext {\n const url = new URL(request.url);\n const meta: ResponseMeta = { headers: {}, setCookies: [] };\n const parsedCookies = parseCookies(request.headers.get('cookie') ?? '');\n const cookiesObj: Record<string, string> = {};\n for (const [key, val] of parsedCookies) {\n cookiesObj[key] = val;\n }\n\n const ctx = {\n request,\n params,\n query: url.searchParams,\n headers: request.headers,\n method: request.method,\n path: url.pathname,\n ip,\n cookies: cookiesObj,\n config,\n meta,\n\n setStatus(status: number) {\n meta.status = status;\n },\n\n setHeader(key: string, value: string) {\n meta.headers[key] = value;\n },\n\n redirect(url: string, status = 302): Response {\n return new Response(null, {\n status,\n headers: { Location: url },\n });\n },\n\n json(data: unknown, status?: number): Response {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n return new Response(JSON.stringify(data), {\n status: status ?? 200,\n headers,\n });\n },\n\n html(html: string, status?: number): Response {\n const headers: Record<string, string> = { 'Content-Type': 'text/html; charset=utf-8' };\n return new Response(html, {\n status: status ?? 200,\n headers,\n });\n },\n\n getCookie(name: string): string | undefined {\n return parsedCookies.get(name);\n },\n\n setCookie(name: string, value: string, options?: CookieOptions): void {\n meta.setCookies.push(formatSetCookie(name, value, options));\n },\n\n deleteCookie(name: string): void {\n meta.setCookies.push(formatSetCookie(name, '', { maxAge: 0 }));\n },\n\n /**\n * 创建 SSE writer,用于流式推送事件\n *\n * handler 调用此方法后,通过返回的 writer 推送事件,框架自动把 writer.response\n * 作为 HTTP 响应(Content-Type: text/event-stream)。\n *\n * 与 ctx.json / ctx.html 互斥:一个 handler 只能用一种响应方式。\n */\n sse(): SseWriter {\n const writer = createSseWriter();\n const ctxWithSse = ctx as FaapiContext & {\n __sseResponse?: Response;\n __sseWriter?: SseWriter;\n };\n ctxWithSse.__sseResponse = writer.response;\n ctxWithSse.__sseWriter = writer;\n return writer;\n },\n } as FaapiContext & { meta: ResponseMeta; __sseResponse?: Response; __sseWriter?: SseWriter };\n\n // 执行用户自定义的 ctx 扩展钩子(config.extendContext)\n const extend = config?.extendContext;\n if (typeof extend === 'function') {\n extend(ctx);\n }\n\n return ctx;\n}\n","export function queryToObject(params: URLSearchParams): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of params) {\n result[key] = value;\n }\n return result;\n}\n","export type JsonParseResult = { success: true; data: unknown } | { success: false; error: string };\n\nexport function parseJsonBody(text: string): JsonParseResult {\n try {\n const data = JSON.parse(text);\n return { success: true, data };\n } catch {\n return { success: false, error: 'Invalid JSON body' };\n }\n}\n","/**\n * 解析 multipart/form-data 请求\n * 使用 Web 标准 Request.formData() API\n */\n\nexport interface UploadedFile {\n name: string; // 字段名\n filename: string; // 原始文件名\n type: string; // MIME 类型\n size: number; // 文件大小(字节)\n arrayBuffer: () => Promise<ArrayBuffer>; // 获取文件内容\n}\n\nexport interface MultipartResult {\n /** 表单字段(同名字段用数组收集,单值保持 string) */\n fields: Record<string, string | string[]>;\n files: UploadedFile[];\n}\n\n/**\n * 解析 multipart/form-data\n *\n * 同名字段的处理:\n * - 第一次出现:string\n * - 第二次出现:string[](包含所有同名字段的值)\n * - 文件始终收集到 files 数组(通过 name 字段标识归属)\n */\nexport async function parseMultipart(request: Request): Promise<MultipartResult> {\n const formData = await request.formData();\n const fields: Record<string, string | string[]> = {};\n const files: UploadedFile[] = [];\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n files.push({\n name: key,\n filename: value.name,\n type: value.type,\n size: value.size,\n arrayBuffer: () => value.arrayBuffer(),\n });\n } else {\n // 同名字段收集为数组\n if (key in fields) {\n const existing = fields[key];\n if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n fields[key] = [existing, value];\n }\n } else {\n fields[key] = value;\n }\n }\n }\n\n return { fields, files };\n}\n","import type { ErrorCode } from './errorCodes';\n\nexport class FaapiError extends Error {\n constructor(\n public readonly code: ErrorCode,\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'FaapiError';\n }\n}\n","import { FaapiError } from './FaapiError';\n\n/**\n * 根据 issues 中的 code 推导 HTTP 状态码\n *\n * 语义参考 RFC 7807 / Rails / Laravel / Spring:\n * - 400 Bad Request:请求语法错误或结构不完整\n * - INVALID_FORMAT:JSON 格式错误、Date 非 ISO 8601\n * - MISSING_FIELD:缺少必填字段\n * - 422 Unprocessable Entity:请求语法正确但语义错误\n * - TYPE_MISMATCH:类型不匹配(string 期望 number)\n * - INVALID_VALUE:值不在允许范围(字面量/enum 不匹配)\n * - COERCE_FAILED:query 字符串转换失败\n *\n * 多个 issue 时取最高严重度(400 优先于 422)。\n */\nfunction deriveStatusCode(issues: ValidationIssue[]): number {\n // 有 400 类 issue → 400;否则 422\n const has400 = issues.some((i) => i.code === 'INVALID_FORMAT' || i.code === 'MISSING_FIELD');\n return has400 ? 400 : 422;\n}\n\nexport class ValidationError extends FaapiError {\n constructor(\n message: string,\n public readonly issues: ValidationIssue[],\n ) {\n super('VALIDATION_ERROR', message, deriveStatusCode(issues));\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends FaapiError {\n constructor(path: string) {\n super('ROUTE_NOT_FOUND', `Route not found: ${path}`, 404);\n this.name = 'RouteNotFoundError';\n }\n}\n\nexport class MethodNotAllowedError extends FaapiError {\n constructor(\n method: string,\n path: string,\n public readonly allowedMethods: string[],\n ) {\n super('METHOD_NOT_ALLOWED', `Method ${method} not allowed for ${path}`, 405);\n this.name = 'MethodNotAllowedError';\n }\n}\n\nexport class InternalError extends FaapiError {\n constructor(message: string) {\n super('INTERNAL_ERROR', message, 500);\n this.name = 'InternalError';\n }\n}\n\nexport class ModuleLoadError extends FaapiError {\n constructor(filePath: string, reason: string) {\n super('MODULE_LOAD_ERROR', `Failed to load module ${filePath}: ${reason}`, 500);\n this.name = 'ModuleLoadError';\n }\n}\n\n/**\n * 校验问题类型\n *\n * 结构化错误信息,便于上层(errorFormat/前端)按 code 做不同处理,\n * 不依赖字符串解析。message 仅为人类可读的兜底描述。\n *\n * code 与 HTTP 状态码的映射(由 ValidationError 推导):\n * - INVALID_FORMAT / MISSING_FIELD → 400 Bad Request\n * - TYPE_MISMATCH / INVALID_VALUE / COERCE_FAILED → 422 Unprocessable Entity\n */\nexport interface ValidationIssue {\n /** 字段路径,如 'user.address.city' */\n path: string;\n /** 错误码,机器可读的契约 */\n code: ValidationErrorCode;\n /** 期望类型/值,如 'number' / '\"admin\" | \"user\"' */\n expected: string;\n /** 实际类型/值,如 'string' / 'undefined' */\n received: string;\n /** 人类可读的本地化消息(兜底,不保证稳定) */\n message: string;\n}\n\nexport type ValidationErrorCode =\n | 'TYPE_MISMATCH' // 类型不匹配(string 期望 number) → 422\n | 'MISSING_FIELD' // 缺少必填字段 → 400\n | 'INVALID_FORMAT' // 格式错误(JSON 解析失败、Date 非 ISO 等) → 400\n | 'INVALID_VALUE' // 值不在允许范围(字面量/enum 不匹配) → 422\n | 'COERCE_FAILED'; // 类型转换失败(query 字符串转 number/boolean 失败) → 422\n","import { queryToObject } from '../utils/queryToObject';\nimport { parseJsonBody } from '../utils/parseJsonBody';\nimport { parseMultipart } from '../utils/parseMultipart';\nimport { getInputTypeForMethod } from './inputType';\nimport { ValidationError } from '../errors/httpErrors';\n\n/**\n * 根据 HTTP 方法解析主输入\n *\n * - GET / DELETE / HEAD:主输入是 query(URL 查询参数)\n * - POST / PUT / PATCH:主输入是 body(请求体)\n *\n * 注意:DELETE 也可能有 body,但主输入(用于校验)是 query。\n * body 通过 injectParams 单独注入。\n *\n * HTTP 传输语义:\n * - 空请求体(或纯空白)视为无 body,返回 null(handler 可不声明 body 参数)\n * - 请求体非空但 JSON 格式非法,抛 ValidationError(code=INVALID_FORMAT),\n * 不再静默返回 null 导致后续报\"字段缺失\"\n *\n * @param method HTTP 方法\n * @param request Request 对象\n * @returns 解析后的输入值(query 对象或 body 对象)\n * @throws {ValidationError} 当请求体非空但 JSON 格式非法时\n */\nexport async function resolveInput(method: string, request: Request): Promise<unknown> {\n const inputType = getInputTypeForMethod(method);\n\n // 主输入是 body 的方法:解析请求体\n if (inputType === 'body') {\n const contentType = request.headers.get('content-type') ?? '';\n\n // multipart/form-data:字段 + 文件\n if (contentType.includes('multipart/form-data')) {\n return parseMultipart(request);\n }\n\n // application/x-www-form-urlencoded:表单字段\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const text = await request.text();\n if (text.trim() === '') return null;\n const params = new URLSearchParams(text);\n const obj: Record<string, string> = {};\n for (const [key, value] of params) {\n obj[key] = value;\n }\n return obj;\n }\n\n // 默认按 JSON 解析(application/json 及其它未明确类型)\n const text = await request.text();\n\n // 空请求体:视为无 body(handler 可不声明 body 参数)\n if (text.trim() === '') {\n return null;\n }\n\n // 非空请求体:必须能解析为 JSON,否则是格式错误\n const result = parseJsonBody(text);\n if (!result.success) {\n throw new ValidationError('请求体不是合法的 JSON', [\n {\n path: 'body',\n code: 'INVALID_FORMAT',\n expected: 'JSON',\n received: 'text',\n message: '请求体不是合法的 JSON',\n },\n ]);\n }\n return result.data;\n }\n\n // 主输入是 query 的方法(GET / DELETE / HEAD):从 URL 提取 query\n const url = new URL(request.url);\n return queryToObject(url.searchParams);\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n // 数组不是普通对象\n if (Array.isArray(value)) {\n return false;\n }\n\n // 检查原型链:普通对象的 prototype 是 Object.prototype 或 null(Object.create(null))\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n","import { isPlainObject } from '../utils/isPlainObject';\nimport type { ResponseMeta } from '../runtime/contextTypes';\n\n/**\n * 将 handler 返回值统一转换为 Response\n *\n * 规则:\n * - Response 对象:原样返回\n * - ReadableStream:直接作为 body\n * - Buffer / Uint8Array:作为二进制 body\n * - 普通对象/数组:JSON.stringify,Content-Type: application/json\n * - string:text/plain\n * - number/boolean:text/plain,String(value)\n * - null/undefined:204 No Content\n * - Promise:await 后再处理\n *\n * 如果传入了 meta,会将 ctx.setStatus / ctx.setHeader 的设置合并到 Response 中\n */\nexport async function toResponse(value: unknown, meta?: ResponseMeta): Promise<Response> {\n // Promise:await 后再处理\n if (value instanceof Promise) {\n return toResponse(await value, meta);\n }\n\n // 辅助函数:将 meta headers 和 setCookies 合并到 Headers 对象\n const applyMeta = (headers: Headers): void => {\n if (!meta) return;\n for (const [key, val] of Object.entries(meta.headers)) {\n headers.set(key, val);\n }\n for (const cookie of meta.setCookies ?? []) {\n headers.append('set-cookie', cookie);\n }\n };\n\n // Response 对象:原样返回(但合并 meta headers)\n if (value instanceof Response) {\n if (\n meta &&\n (meta.status !== undefined ||\n Object.keys(meta.headers).length > 0 ||\n meta.setCookies.length > 0)\n ) {\n const headers = new Headers(value.headers);\n applyMeta(headers);\n return new Response(value.body, {\n status: meta.status ?? value.status,\n headers,\n });\n }\n return value;\n }\n\n // null/undefined:204 No Content\n if (value === null || value === undefined) {\n const status = meta?.status ?? 204;\n const headers = new Headers();\n applyMeta(headers);\n return new Response(null, { status, headers });\n }\n\n // ReadableStream:直接作为 body\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // Buffer / Uint8Array:作为二进制 body\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value as BodyInit, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n if (value instanceof Uint8Array) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value as BodyInit, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // 普通对象/数组:JSON.stringify,Content-Type: application/json\n if (isPlainObject(value) || Array.isArray(value)) {\n const body = JSON.stringify(value);\n const headers = new Headers({ 'Content-Type': 'application/json' });\n applyMeta(headers);\n return new Response(body, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // string:text/plain\n if (typeof value === 'string') {\n const headers = new Headers({ 'Content-Type': 'text/plain' });\n applyMeta(headers);\n return new Response(value, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // number/boolean:text/plain,String(value)\n if (typeof value === 'number' || typeof value === 'boolean') {\n const headers = new Headers({ 'Content-Type': 'text/plain' });\n applyMeta(headers);\n return new Response(String(value), {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // 其他类型 fallback:JSON.stringify\n const body = JSON.stringify(value);\n const headers = new Headers({ 'Content-Type': 'application/json' });\n applyMeta(headers);\n return new Response(body, {\n status: meta?.status ?? 200,\n headers,\n });\n}\n","import type { FaapiContext } from '../runtime/contextTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { resolveInjection, type InjectionType } from './resolveInjection';\nimport { queryToObject } from '../utils/queryToObject';\nimport type { MultipartResult } from '../utils/parseMultipart';\n\n/**\n * 根据注入类型获取对应的值(内置)\n */\nfunction getBuiltinInjectionValue(type: InjectionType, ctx: FaapiContext, body?: unknown): unknown {\n switch (type) {\n case 'query':\n return queryToObject(ctx.query);\n case 'params':\n return ctx.params;\n case 'headers':\n return ctx.headers;\n case 'context':\n return ctx;\n case 'cookies':\n return ctx.cookies;\n case 'ip':\n return ctx.ip;\n case 'body':\n return body;\n case 'files':\n if (body && typeof body === 'object' && 'files' in body) {\n return (body as MultipartResult).files;\n }\n return [];\n case 'fields':\n if (body && typeof body === 'object' && 'fields' in body) {\n return (body as MultipartResult).fields;\n }\n return {};\n default:\n return undefined;\n }\n}\n\n/**\n * 根据注入信息,准备参数值并调用 handler(异步版本)\n *\n * 支持 async handler。内置注入优先于注入器(避免 query/body 等被覆盖)。\n * 非内置参数从注入器注册表按参数名查找,按需执行。\n */\nexport async function injectParamsAsync(\n handler: (...args: unknown[]) => unknown,\n ctx: FaapiContext,\n body?: unknown,\n injectors?: InjectorMap,\n): Promise<unknown> {\n const injections = resolveInjection(handler);\n\n if (injections.length === 0) {\n return await handler();\n }\n\n const args = await Promise.all(\n injections.map(async (injection) => {\n // 内置注入优先\n if (injection.type !== 'unknown') {\n return getBuiltinInjectionValue(injection.type, ctx, body);\n }\n // 注入器按参数名匹配\n if (injectors && injection.name in injectors) {\n return await injectors[injection.name](ctx);\n }\n return undefined;\n }),\n );\n\n return await handler(...args);\n}\n","import type { FaapiContext } from './contextTypes';\nimport type { ResponseMeta } from './contextTypes';\nimport type { SseWriter } from './sse';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { toResponse } from '../response/toResponse';\nimport { injectParamsAsync } from '../injection/injectParams';\n\n/**\n * 将 ctx.meta(setStatus/setHeader/setCookie 设置的响应元数据)合并到 Response\n *\n * 用于中间件返回 Response 时,确保用户通过 ctx.setStatus/setHeader 设置的\n * 状态码、响应头、cookie 能正确附加到中间件返回的 Response 上。\n */\nexport function mergeMeta(response: Response, meta: ResponseMeta): Response {\n const hasMeta =\n meta.status !== undefined || Object.keys(meta.headers).length > 0 || meta.setCookies.length > 0;\n if (!hasMeta) return response;\n\n const headers = new Headers(response.headers);\n for (const [key, value] of Object.entries(meta.headers)) {\n headers.set(key, value);\n }\n for (const cookie of meta.setCookies) {\n headers.append('set-cookie', cookie);\n }\n return new Response(response.body, {\n status: meta.status ?? response.status,\n headers,\n });\n}\n\n/**\n * 洋葱模型调度:将中间件链包装成 next 函数\n *\n * 每个中间件的 `await next()` 会执行下一个中间件并返回其 Response;\n * 最内层的 next 执行 handler(含参数注入)。\n *\n * 中间件返回 Response 的语义:\n * - 在 await next() 之前返回:拦截请求(不执行后续中间件和 handler)\n * - 在 await next() 之后返回:替换内层返回的响应\n * - 在 catch 块中返回:作为错误响应\n *\n * 中间件返回 void/undefined:使用 await next() 返回的内层响应。\n * 中间件不调用 next() 也不返回 Response:抛错(语义模糊,禁止使用)。\n *\n * 中间件返回 Response 时会合并 ctx.meta(setStatus/setHeader/setCookie 的设置),\n * 确保 ctx 便捷方法在中间件拦截场景下也生效。\n */\nexport async function compose(\n middlewares: FaapiMiddleware[],\n ctx: FaapiContext,\n finalHandler: () => Promise<Response>,\n): Promise<Response> {\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n let index = -1;\n\n async function dispatch(i: number): Promise<Response> {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n // 所有中间件执行完,运行 handler\n if (i >= middlewares.length) {\n return await finalHandler();\n }\n\n const mw = middlewares[i];\n // next() 返回内层 Response,中间件可选择使用或替换\n let innerResponse: Response | undefined;\n const next = async (): Promise<Response> => {\n innerResponse = await dispatch(i + 1);\n return innerResponse;\n };\n\n const result = await mw(ctx, next);\n\n // 中间件返回 Response:使用它(拦截或替换),并合并 ctx.meta\n if (result instanceof Response) {\n return mergeMeta(result, meta);\n }\n // 中间件返回 void:使用 next() 返回的内层响应\n if (innerResponse !== undefined) {\n return innerResponse;\n }\n // 中间件既没返回 Response 也没调用 next():语义模糊,禁止\n throw new Error('中间件必须 await next() 或返回 Response');\n }\n\n return await dispatch(0);\n}\n\n/**\n * 调用路由 handler 并将返回值转为 Response\n *\n * 流程(洋葱模型):\n * 1. 中间件按洋葱模型执行:mw1.before → mw2.before → ... → handler → ... → mw2.after → mw1.after\n * 2. 中间件不调用 next() 即拦截请求(必须返回 Response)\n * 3. 中间件可用 try/catch 捕获内层错误\n * 4. 最内层执行注入器(按需)→ handler\n *\n * 注入器与中间件解耦:\n * - 注入器按 handler 参数名匹配,只执行需要的\n * - 注入器可读取中间件塞进 ctx 的值\n */\nexport async function invokeHandler(\n handler: (...args: unknown[]) => unknown,\n ctx: FaapiContext,\n body?: unknown,\n middlewares?: FaapiMiddleware[],\n injectors?: InjectorMap,\n): Promise<Response> {\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n /**\n * 若 handler 调用了 ctx.sse(),优先使用 SSE Response\n * (handler 返回值被忽略,SSE 流由 writer 控制)\n *\n * 同时执行自动 close 兜底:若 handler 返回时 writer 仍未关闭,自动调用 close(),\n * 避免连接泄漏。handler 异步循环未退出、忘记 close、或抛错的场景由这里兜底。\n */\n const pickSseAndAutoClose = (): Response | null => {\n const sseWriter = (ctx as FaapiContext & { __sseWriter?: SseWriter }).__sseWriter;\n if (!sseWriter) return null;\n // 兜底:handler 未显式 close 时自动关闭\n if (!sseWriter.closed && !sseWriter.aborted) {\n sseWriter.close();\n }\n return mergeMeta(sseWriter.response, meta);\n };\n\n // 抛错时也保证 writer 被关闭(避免流泄漏)\n const autoCloseSseOnError = (): void => {\n const sseWriter = (ctx as FaapiContext & { __sseWriter?: SseWriter }).__sseWriter;\n if (sseWriter && !sseWriter.closed && !sseWriter.aborted) {\n sseWriter.close();\n }\n };\n\n // 无中间件:直接执行 handler\n if (!middlewares || middlewares.length === 0) {\n try {\n const result = await injectParamsAsync(handler, ctx, body, injectors);\n const sseResponse = pickSseAndAutoClose();\n if (sseResponse) return sseResponse;\n return toResponse(result, meta);\n } catch (err) {\n // handler 抛错时关闭未完成的 SSE 流,避免泄漏\n autoCloseSseOnError();\n throw err;\n }\n }\n\n // 有中间件:洋葱模型调度\n const finalHandler = async (): Promise<Response> => {\n try {\n const result = await injectParamsAsync(handler, ctx, body, injectors);\n const sseResponse = pickSseAndAutoClose();\n if (sseResponse) return sseResponse;\n return toResponse(result, meta);\n } catch (err) {\n // handler 抛错时关闭未完成的 SSE 流,避免泄漏\n autoCloseSseOnError();\n throw err;\n }\n };\n\n return await compose(middlewares, ctx, finalHandler);\n}\n","import type { ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\n\n/**\n * 将 Web Response 写入 Node.js ServerResponse\n *\n * 使用 stream pipe 处理背压,避免高并发下内存膨胀。\n */\nexport async function sendNodeResponse(response: Response, res: ServerResponse): Promise<void> {\n // 设置状态码\n res.statusCode = response.status;\n\n // 设置 headers\n for (const [key, value] of response.headers) {\n if (key.toLowerCase() === 'set-cookie') {\n // Set-Cookie 使用 appendHeader 支持多个值\n res.appendHeader(key, value);\n } else {\n res.setHeader(key, value);\n }\n }\n\n // 写入 body(使用 pipe 处理背压)\n if (response.body) {\n // TS 5.7 lib.dom 的 ReadableStream 与 node:stream/web 的 ReadableStream 是不同类型,cast 绕过\n const nodeStream = Readable.fromWeb(response.body as never);\n await new Promise<void>((resolve, reject) => {\n nodeStream.on('error', reject);\n res.on('error', reject);\n res.on('finish', resolve);\n nodeStream.pipe(res);\n });\n return;\n }\n\n res.end();\n}\n","import type { ValidatorFn } from '../ast/generateValidatorCode';\nimport type { PropertyType } from '../ast/resolveTypeNode';\n\n/**\n * 单个 schema 条目\n * - SchemaEntry:有类型声明,包含 properties(用于 coerce)和 validator(用于校验)\n * - null:handler 无类型声明(如 GET() 无参数),跳过校验\n */\nexport type SchemaEntry = { properties: PropertyType[]; validator: ValidatorFn } | null;\n\n/**\n * 单个文件的所有 schema:schemaName -> SchemaEntry\n * schemaName 由 method + inputType 生成,如 'GETQuery'、'POSTBody'\n */\nexport type FileSchemas = Map<string, SchemaEntry>;\n\n/**\n * 完整 manifest:filePath -> FileSchemas\n */\nexport type SchemaManifest = Map<string, FileSchemas>;\n\n/**\n * Schema 注册表(单例)\n *\n * 统一管理 handler 的校验函数,作为 validateInput 的唯一数据来源。\n * - prd 模式:从 dist/faapi-schema.js import 加载\n * - dev 模式:启动时全量提取并生成函数,watch 时全量重建\n *\n * 三种状态区分:\n * - get() 返回 SchemaEntry:有类型声明,校验\n * - get() 返回 null:无类型声明,跳过校验\n * - get() 返回 undefined:manifest 不完整,抛错\n */\nclass SchemaRegistry {\n private manifest: SchemaManifest = new Map();\n\n /**\n * 批量加载 manifest\n * 覆盖已有数据\n */\n loadManifest(manifest: SchemaManifest): void {\n this.manifest.clear();\n for (const [filePath, fileSchemas] of manifest) {\n const copy: FileSchemas = new Map();\n fileSchemas.forEach((value, key) => copy.set(key, value));\n this.manifest.set(filePath, copy);\n }\n }\n\n /**\n * 查询单条 schema\n * @returns SchemaEntry | null | undefined\n * - SchemaEntry:有类型声明\n * - null:无类型声明(跳过校验)\n * - undefined:manifest 不完整(抛错)\n */\n get(filePath: string, schemaName: string): SchemaEntry | undefined {\n const fileSchemas = this.manifest.get(filePath);\n if (!fileSchemas) return undefined;\n return fileSchemas.get(schemaName);\n }\n\n /**\n * 设置单个文件的所有 schema\n * 覆盖该文件的已有数据\n */\n set(filePath: string, schemas: FileSchemas): void {\n const copy: FileSchemas = new Map();\n schemas.forEach((value, key) => copy.set(key, value));\n this.manifest.set(filePath, copy);\n }\n\n /**\n * 删除单个文件(文件被删除时)\n */\n delete(filePath: string): void {\n this.manifest.delete(filePath);\n }\n\n /**\n * 判断文件是否已注册\n */\n hasFile(filePath: string): boolean {\n return this.manifest.has(filePath);\n }\n\n /**\n * 清空(测试用 / watch 全量重建前)\n */\n clear(): void {\n this.manifest.clear();\n }\n\n /**\n * 已注册的文件数量\n */\n get size(): number {\n return this.manifest.size;\n }\n}\n\n/**\n * 全局单例\n */\nexport const schemaRegistry = new SchemaRegistry();\n","import type { PropertyType } from '../ast/resolveTypeNode';\nimport type { RuntimeType } from '../ast/resolveTypeNode';\nimport type { ValidationIssue } from '../errors/httpErrors';\n\nexport interface CoerceResult {\n data: Record<string, unknown>;\n issues: ValidationIssue[];\n}\n\n/**\n * 将输入值根据类型信息做类型转换(coerce)\n * 主要用于 query/params,这些来源的值都是 string\n *\n * 转换规则:\n * - string → number:Number() 转换,NaN 则失败\n * - string → boolean:'true'/'1' → true,'false'/'0' → false,其他失败\n * - string → string:不转换\n * - string[] → number[]:逐元素转换\n * - 其他类型:不转换\n *\n * @param input 输入值\n * @param properties 属性类型列表(来自 SchemaEntry.properties)\n */\nexport function coerceInput(\n input: Record<string, unknown>,\n properties: PropertyType[],\n): CoerceResult {\n const issues: ValidationIssue[] = [];\n const data: Record<string, unknown> = { ...input };\n\n for (const prop of properties) {\n const value = data[prop.name];\n const isPresent = prop.name in data;\n\n // 不存在的字段不转换\n if (!isPresent || value === undefined) continue;\n\n data[prop.name] = coerceValue(value, prop.type, prop.name, issues);\n }\n\n return { data, issues };\n}\n\n/**\n * 递归 coerce 值\n */\nfunction coerceValue(\n value: unknown,\n type: RuntimeType,\n path: string,\n issues: ValidationIssue[],\n): unknown {\n switch (type.kind) {\n case 'number':\n if (typeof value === 'string') {\n return coerceStringToNumber(value, path, issues);\n }\n return value;\n\n case 'boolean':\n if (typeof value === 'string') {\n return coerceStringToBoolean(value, path, issues);\n }\n return value;\n\n case 'array':\n // query 中的数组可能是逗号分隔字符串或重复 key\n if (typeof value === 'string') {\n // 单个字符串无法直接转为数组,保持原样\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((item, i) => coerceValue(item, type.element, `${path}[${i}]`, issues));\n }\n return value;\n\n case 'tuple': {\n // 元组按位置 coerce 每个元素\n // - 非-rest 元素:用 type.elements[i] 对应类型\n // - rest 范围内的元素:用 rest.type;否则不应出现(validator 会报错)\n if (!Array.isArray(value)) return value;\n const restElement = type.elements.find((e) => e.rest);\n return value.map((item, i) => {\n const elem = type.elements[i];\n if (elem && !elem.rest) {\n return coerceValue(item, elem.type, `${path}[${i}]`, issues);\n }\n // rest 范围内的元素\n if (restElement) {\n return coerceValue(item, restElement.type, `${path}[${i}]`, issues);\n }\n return item;\n });\n }\n\n case 'union':\n // 尝试 coerce 到联合类型中的每个成员,返回第一个成功的\n for (const member of type.members) {\n const tempIssues: ValidationIssue[] = [];\n const coerced = coerceValue(value, member, path, tempIssues);\n if (tempIssues.length === 0) {\n return coerced;\n }\n }\n return value;\n\n case 'literal':\n // 数值字面量(来自数值枚举):将 query 字符串转为数字,由 validator 检查是否匹配\n if (typeof type.value === 'number' && typeof value === 'string' && value.trim() !== '') {\n const num = Number(value);\n if (!Number.isNaN(num)) return num;\n }\n return value;\n\n case 'object':\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const obj = value as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n for (const prop of type.properties) {\n if (prop.name in obj) {\n result[prop.name] = coerceValue(\n obj[prop.name],\n prop.type,\n `${path}.${prop.name}`,\n issues,\n );\n }\n }\n return { ...obj, ...result };\n }\n return value;\n\n default:\n // string / date / record / any / null / undefined / bigint / tuple 不转换\n return value;\n }\n}\n\n/**\n * string → number\n */\nfunction coerceStringToNumber(\n value: string,\n path: string,\n issues: ValidationIssue[],\n): number | string {\n if (value.trim() === '') {\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'number',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 number`,\n });\n return value;\n }\n const num = Number(value);\n if (Number.isNaN(num)) {\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'number',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 number`,\n });\n return value;\n }\n return num;\n}\n\n/**\n * string → boolean\n */\nfunction coerceStringToBoolean(\n value: string,\n path: string,\n issues: ValidationIssue[],\n): boolean | string {\n if (value === 'true' || value === '1') {\n return true;\n }\n if (value === 'false' || value === '0') {\n return false;\n }\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'boolean',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 boolean`,\n });\n return value;\n}\n","import { schemaRegistry } from './schemaRegistry';\nimport { getSchemaName } from './schemaName';\nimport { coerceInput } from './coerceInput';\nimport { InternalError } from '../errors/httpErrors';\nimport type { ValidationResult } from '../ast/generateValidatorCode';\n\n/**\n * 校验输入参数\n *\n * 流程:从 schemaRegistry 查询 schema → 类型转换(仅 query)→ 调用校验函数\n *\n * schema 来源由调用方确保已注册:\n * - dev 模式:启动时全量提取并生成函数,watch 时全量重建\n * - prd 模式:启动时从 dist/faapi-schema.js import 加载\n *\n * 三种状态:\n * - SchemaEntry:执行校验\n * - null:无类型声明,跳过校验\n * - undefined:manifest 不完整,抛 InternalError\n *\n * @param filePath 路由文件路径\n * @param method HTTP 方法\n * @param inputType 输入类型\n * @param input 输入值\n */\nexport async function validateInput(\n filePath: string,\n method: string,\n inputType: 'query' | 'body' | 'params',\n input: unknown,\n): Promise<ValidationResult> {\n const schemaName = getSchemaName(method, inputType);\n const entry = schemaRegistry.get(filePath, schemaName);\n\n // manifest 不完整:schema 未注册\n if (entry === undefined) {\n throw new InternalError(`Schema 未注册: ${filePath}#${schemaName}`);\n }\n\n // 无类型声明:跳过校验\n if (entry === null) {\n const data =\n typeof input === 'object' && input !== null && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n return { valid: true, issues: [], data };\n }\n\n const inputObj =\n typeof input === 'object' && input !== null && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n\n // 类型转换(coerce):仅 query 需要,因为 URL 参数都是 string\n let dataToValidate = inputObj;\n if (inputType === 'query') {\n const { data: coercedData, issues: coerceIssues } = coerceInput(inputObj, entry.properties);\n\n if (coerceIssues.length > 0) {\n return {\n valid: false,\n issues: coerceIssues,\n data: coercedData,\n };\n }\n dataToValidate = coercedData;\n }\n\n // 调用校验函数\n return entry.validator(dataToValidate);\n}\n","import type { IncomingMessage } from 'node:http';\n\n/**\n * 从 IncomingMessage 提取客户端 IP\n *\n * 优先级:\n * 1. `x-forwarded-for` 第一个 IP(反向代理场景,如 nginx/CDN)\n * 2. `req.socket.remoteAddress`(直连场景)\n *\n * `x-forwarded-for` 格式:`client, proxy1, proxy2`,取第一个即客户端真实 IP。\n * 注意:仅在受信任的反向代理后才有效;若客户端直连且未经过代理,该 header 可被伪造。\n *\n * @returns 客户端 IP,无法获取时返回空字符串\n */\nexport function getClientIp(req: IncomingMessage): string {\n // 1. x-forwarded-for 优先(反向代理场景)\n const xff = req.headers['x-forwarded-for'];\n if (typeof xff === 'string' && xff.length > 0) {\n const first = xff.split(',')[0]?.trim();\n if (first) return first;\n }\n\n // 2. 直连 socket IP\n const remote = req.socket.remoteAddress;\n if (remote) {\n // 去掉 IPv6 前缀 ::ffff:,统一返回 IPv4 形式\n if (remote.startsWith('::ffff:')) {\n return remote.slice(7);\n }\n return remote;\n }\n\n return '';\n}\n","import type { FaapiMiddleware } from './middlewareTypes';\n\nexport interface CorsOptions {\n origin?: string | string[] | true;\n methods?: string[];\n allowedHeaders?: string[];\n exposeHeaders?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\nconst DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];\n\n/**\n * 创建 CORS 中间件(洋葱模型)\n *\n * - origin=true: 允许所有来源(反射请求的 Origin)\n * - origin=string: 允许指定来源\n * - origin=string[]: 允许多个来源\n *\n * OPTIONS 预检请求直接返回 204,不调用 next()。\n */\nexport function cors(options: CorsOptions = {}): FaapiMiddleware {\n const {\n origin = true,\n methods = DEFAULT_METHODS,\n allowedHeaders,\n exposeHeaders,\n credentials = false,\n maxAge,\n } = options;\n\n return async (ctx, next) => {\n const reqOrigin = ctx.headers.get('origin');\n if (!reqOrigin) {\n await next();\n return;\n }\n\n // 确定允许的来源\n let allowOrigin: string | null = null;\n if (origin === true) {\n allowOrigin = reqOrigin; // 反射 Origin\n } else if (typeof origin === 'string') {\n allowOrigin = reqOrigin === origin ? origin : null;\n } else if (Array.isArray(origin)) {\n allowOrigin = origin.includes(reqOrigin) ? reqOrigin : null;\n }\n\n if (!allowOrigin) {\n await next();\n return;\n }\n\n // 设置 CORS 响应头\n ctx.setHeader('Access-Control-Allow-Origin', allowOrigin);\n\n // 当 origin 为动态值(true 或数组)时,必须设置 Vary: Origin,\n // 防止 CDN/浏览器错误缓存针对某个 Origin 的响应给其他 Origin\n if (origin === true || Array.isArray(origin)) {\n const existingVary = ctx.headers.get('vary');\n if (existingVary) {\n if (!existingVary.toLowerCase().includes('origin')) {\n ctx.setHeader('Vary', `${existingVary}, Origin`);\n }\n } else {\n ctx.setHeader('Vary', 'Origin');\n }\n }\n\n ctx.setHeader('Access-Control-Allow-Methods', methods.join(', '));\n\n if (allowedHeaders) {\n ctx.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));\n } else {\n // 反射请求头\n const requestHeaders = ctx.headers.get('access-control-request-headers');\n if (requestHeaders) {\n ctx.setHeader('Access-Control-Allow-Headers', requestHeaders);\n }\n }\n\n if (exposeHeaders && exposeHeaders.length > 0) {\n ctx.setHeader('Access-Control-Expose-Headers', exposeHeaders.join(', '));\n }\n\n if (credentials) {\n ctx.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n\n if (maxAge !== undefined) {\n ctx.setHeader('Access-Control-Max-Age', String(maxAge));\n }\n\n // 处理 preflight 请求:直接返回 204,不调用 next()\n if (ctx.method === 'OPTIONS') {\n return new Response(null, { status: 204 });\n }\n\n await next();\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { createReadStream } from 'node:fs';\nimport { Readable } from 'node:stream';\n\n/**\n * MIME 类型映射表\n *\n * 覆盖常见的 Web 静态资源类型。\n */\nconst MIME_TYPES: Record<string, string> = {\n // 文本\n '.html': 'text/html; charset=utf-8',\n '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.cjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.json5': 'application/json5',\n '.txt': 'text/plain; charset=utf-8',\n '.md': 'text/markdown; charset=utf-8',\n '.csv': 'text/csv; charset=utf-8',\n '.xml': 'application/xml; charset=utf-8',\n '.yaml': 'application/x-yaml',\n '.yml': 'application/x-yaml',\n '.toml': 'application/toml',\n\n // 图片\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n '.heic': 'image/heic',\n\n // 字体\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject',\n\n // 音频\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.oga': 'audio/ogg',\n '.flac': 'audio/flac',\n '.m4a': 'audio/mp4',\n '.aac': 'audio/aac',\n\n // 视频\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogv': 'video/ogg',\n '.mov': 'video/quicktime',\n '.m4v': 'video/mp4',\n '.avi': 'video/x-msvideo',\n\n // 文档\n '.pdf': 'application/pdf',\n\n // 压缩\n '.zip': 'application/zip',\n '.gz': 'application/gzip',\n '.tar': 'application/x-tar',\n '.rar': 'application/vnd.rar',\n '.7z': 'application/x-7z-compressed',\n\n // 其他\n '.wasm': 'application/wasm',\n '.map': 'application/json',\n '.webmanifest': 'application/manifest+json',\n};\n\n/**\n * 尝试提供静态文件\n *\n * 使用流式响应(createReadStream)避免大文件占用内存。\n * 路径遍历检查使用 path.relative 严格判断。\n *\n * @param urlPath 请求路径\n * @param staticDir 静态文件根目录的绝对路径\n * @returns Response 或 null(未找到文件)\n */\nexport async function serveStatic(urlPath: string, staticDir: string): Promise<Response | null> {\n // 安全检查:防止路径遍历\n // 使用 path.relative 判断解析后的路径是否仍在 staticDir 内\n const resolved = path.resolve(staticDir, '.' + urlPath);\n const relative = path.relative(staticDir, resolved);\n\n // relative 如果以 '..' 开头或为绝对路径,说明逃逸了 staticDir\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n return null;\n }\n\n let stat: fs.Stats;\n try {\n stat = await fs.promises.stat(resolved);\n } catch {\n return null;\n }\n\n if (stat.isDirectory()) {\n // 尝试 index.html\n const indexPath = path.join(resolved, 'index.html');\n try {\n const indexStat = await fs.promises.stat(indexPath);\n if (indexStat.isFile()) {\n return serveFile(indexPath, indexStat.size);\n }\n } catch {\n // index.html 不存在\n }\n return null;\n }\n\n if (!stat.isFile()) {\n return null;\n }\n\n return serveFile(resolved, stat.size);\n}\n\n/**\n * 流式响应文件\n *\n * 使用 createReadStream 避免大文件占用内存。\n * 设置 ETag 和 Last-Modified 支持条件请求。\n */\nfunction serveFile(filePath: string, size: number): Response {\n const ext = path.extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n // 使用 mtime 作为 ETag 和 Last-Modified\n const stream = createReadStream(filePath);\n const webStream = Readable.toWeb(stream) as ReadableStream<Uint8Array>;\n\n return new Response(webStream, {\n status: 200,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'public, max-age=3600',\n 'Content-Length': String(size),\n },\n });\n}\n","import { FaapiError } from './FaapiError';\nimport { ValidationError, MethodNotAllowedError } from './httpErrors';\n\n/**\n * 将错误转换为统一的 JSON 响应结构\n *\n * 格式:\n * {\n * \"error\": {\n * \"code\": \"VALIDATION_ERROR\",\n * \"message\": \"Invalid query parameters\",\n * \"issues\": [...] // 仅 ValidationError 包含\n * }\n * }\n */\nexport function formatErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n const body: Record<string, unknown> = {\n code: error.code,\n message: error.message,\n issues: error.issues,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n if (error instanceof MethodNotAllowedError) {\n const body = {\n code: error.code,\n message: error.message,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: {\n 'Content-Type': 'application/json',\n Allow: error.allowedMethods.join(', '),\n },\n });\n }\n\n if (error instanceof FaapiError) {\n const body = {\n code: error.code,\n message: error.message,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // 未知错误:500 INTERNAL_ERROR\n const body = {\n code: 'INTERNAL_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n return new Response(JSON.stringify({ error: body }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n","import type { IncomingMessage } from 'node:http';\nimport type { FaapiContext } from '../runtime/contextTypes';\nimport type { ErrorFormatFn } from '../config/configTypes';\nimport { formatErrorResponse } from '../errors/formatErrorResponse';\n\n/**\n * 将 Node.js IncomingMessage 的 headers 转为 Web Headers\n *\n * 处理数组型 header 值(如 set-cookie)和 undefined 值。\n */\nexport function nodeHttpToWebHeaders(req: IncomingMessage): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\n/**\n * 构建错误响应(兜底链)\n *\n * 1. 配置了 errorFormat → 优先调用;返回 Response 表示已处理\n * 2. errorFormat 返回 null/undefined(未处理)或抛错 → 框架内置 formatErrorResponse 兜底\n * 3. 内置兜底仍抛错 → 最简 500 JSON 响应\n */\nexport function buildErrorResponse(\n err: unknown,\n ctx: FaapiContext,\n errorFormat?: ErrorFormatFn,\n): Response {\n if (errorFormat) {\n try {\n const res = errorFormat(err, ctx);\n if (res) return res;\n } catch {\n // errorFormat 抛错,落入下方 formatErrorResponse 兜底\n }\n }\n try {\n return formatErrorResponse(err);\n } catch {\n // 极端情况:内置兜底也失败,返回最简 500\n return new Response(\n JSON.stringify({ error: { code: 'INTERNAL_ERROR', message: 'Internal Server Error' } }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n}\n","/**\n * WebSocket Handler 类型定义与 socket 封装\n *\n * 用户在 handler.ts 中导出 WS 函数,返回事件回调对象。\n * 框架在协议升级成功后调用对应回调,传递封装后的 WsSocket。\n *\n * @see wsHandler.md 功能说明\n */\n\n/**\n * faapi 封装的 WebSocket socket 抽象\n *\n * 不直接暴露 ws 库的原生 socket,提供更安全、易用的 API。\n * send 对象时自动 JSON.stringify。\n */\nexport interface WsSocket {\n /** 发送数据(string/Buffer 直发,对象自动 JSON.stringify) */\n send(data: string | Buffer | object): void;\n /** 关闭连接 */\n close(code?: number, reason?: string | Buffer): void;\n /** 连接状态:0=connecting, 1=open, 2=closing, 3=closed */\n readonly readyState: number;\n}\n\n/**\n * WebSocket 事件回调集合\n *\n * 用户在 WS handler 中返回此对象,框架在对应事件触发时调用。\n * 所有回调可选,未提供则忽略事件。\n */\nexport interface WsEventHandlers {\n /** 连接建立时触发 */\n onOpen?: (ws: WsSocket) => void;\n /** 收到客户端消息时触发 */\n onMessage?: (ws: WsSocket, message: string | Buffer) => void;\n /** 连接关闭时触发 */\n onClose?: (ws: WsSocket, code: number, reason: string) => void;\n /** 发生错误时触发 */\n onError?: (ws: WsSocket, error: Error) => void;\n}\n\n/**\n * WebSocket 上下文(握手阶段构造)\n *\n * 与 HTTP FaapiContext 类似但精简,提供路由参数、查询参数、请求头、配置。\n * 可通过 declare module '@faapi/faapi' 增强自定义字段。\n */\nexport interface WsContext {\n /** 动态路由参数(如 [id] → params.id) */\n params: Record<string, string>;\n /** URL 查询参数 */\n query: URLSearchParams;\n /** 请求头 */\n headers: Headers;\n /** 业务配置(来自 faapi.config.ts) */\n config: Record<string, unknown>;\n /** 中间件塞入的用户信息(鉴权等) */\n user?: unknown;\n /** 允许通过 declare module 扩展 */\n [key: string]: unknown;\n}\n\n/**\n * WS handler 签名:接收 WsContext,返回事件回调对象(或无返回)\n */\nexport type WsHandler = (ctx: WsContext) => WsEventHandlers | void;\n\n/**\n * 将 ws 库的原生 WebSocket 封装为 faapi 的 WsSocket\n *\n * - send 对象时自动 JSON.stringify\n * - close/re.readyState 透传原生 socket\n */\nexport function wrapWsSocket(rawSocket: {\n send: (data: string | Buffer, cb?: (err?: Error) => void) => void;\n close: (code?: number, reason?: string | Buffer) => void;\n readonly readyState: number;\n}): WsSocket {\n return {\n send(data: string | Buffer | object): void {\n const payload =\n typeof data === 'string' || Buffer.isBuffer(data) ? data : JSON.stringify(data);\n rawSocket.send(payload);\n },\n close(code?: number, reason?: string | Buffer): void {\n rawSocket.close(code, reason);\n },\n get readyState(): number {\n return rawSocket.readyState;\n },\n };\n}\n","/**\n * WebSocket 协议升级处理\n *\n * 监听 HTTP server 的 upgrade 事件,匹配 WS 路由后调用 ws 库完成协议升级,\n * 加载 handler.ts 的 WS 导出,绑定事件回调。\n *\n * 握手阶段复用洋葱中间件链(鉴权/CORS/限流/日志等),与同目录 HTTP 路由共享中间件。\n * 中间件塞入 ctx 的值(如 ctx.user)传入 WS handler。连接建立后切到事件模型,不走中间件。\n *\n * @see wsHandler.md WS handler 约定与握手中间件链设计\n */\nimport type { IncomingMessage } from 'node:http';\nimport type { Server } from 'node:http';\nimport type { Socket } from 'node:net';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport path from 'node:path';\nimport type { WsRouteManifest, WsRouteMatch } from '../router/routeTypes';\nimport { matchWsRoute } from '../router/matchRoute';\nimport { createContext } from '../runtime/createContext';\nimport { compose, mergeMeta } from '../runtime/invokeHandler';\nimport type { FaapiContext, ResponseMeta } from '../runtime/contextTypes';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\nimport { getClientIp } from '../utils/getClientIp';\nimport { nodeHttpToWebHeaders, buildErrorResponse } from './serverUtils';\nimport type { ErrorFormatFn } from '../config/configTypes';\nimport {\n wrapWsSocket,\n type WsContext,\n type WsEventHandlers,\n type WsHandler,\n} from '../runtime/wsHandler';\n\n/**\n * 从 IncomingMessage 提取 URL pathname(不含 query)\n */\nfunction getPathname(req: IncomingMessage): string {\n const url = req.url ?? '/';\n const idx = url.indexOf('?');\n return idx >= 0 ? url.slice(0, idx) : url;\n}\n\n/**\n * 加载 WS handler 并执行,返回事件回调对象(可能为空)\n *\n * 直接动态 import handler.ts 并取 `WS` 导出(不经过 loadRouteModule,\n * 因为 WS 不是 HTTP 方法,loadRouteModule 的 method 维度不适用)。\n * watch 模式下通过时间戳 query string 绕过 ESM 缓存。\n */\nasync function loadWsHandler(filePath: string, ctx: WsContext): Promise<WsEventHandlers | void> {\n const module = await importWithCacheBust(filePath);\n const handler = module['WS'];\n if (typeof handler !== 'function') {\n throw new Error(`WS export not found in ${filePath}`);\n }\n return (handler as WsHandler)(ctx);\n}\n\n/**\n * 绑定 ws 库原生事件到 faapi 的 WsEventHandlers\n *\n * 注意:wss.handleUpgrade 回调触发时 socket 已经处于 OPEN 状态,\n * 'open' 事件不会再触发,需要直接同步调用 onOpen。\n */\nfunction bindEvents(rawSocket: WebSocket, handlers: WsEventHandlers | void): void {\n if (!handlers) return;\n const ws = wrapWsSocket(rawSocket);\n\n if (handlers.onOpen) {\n // handleUpgrade 回调触发时 socket 已是 OPEN,直接同步调用\n if (rawSocket.readyState === WebSocket.OPEN) {\n handlers.onOpen!(ws);\n } else {\n rawSocket.once('open', () => handlers.onOpen!(ws));\n }\n }\n if (handlers.onMessage) {\n rawSocket.on('message', (data: Buffer) => {\n // ws 库 message 事件传 Buffer[],合并为单个 Buffer 后转 string\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data as unknown as Uint8Array);\n handlers.onMessage!(ws, buf.toString('utf8'));\n });\n }\n if (handlers.onClose) {\n rawSocket.on('close', (code: number, reason: Buffer) => {\n handlers.onClose!(ws, code, reason.toString('utf8'));\n });\n }\n if (handlers.onError) {\n rawSocket.on('error', (err: Error) => {\n handlers.onError!(ws, err);\n });\n }\n}\n\n/**\n * 把 Web Response 写回原始 socket(握手被中间件拦截或出错时使用)\n *\n * socket 未升级为 WebSocket 时,按 HTTP 响应格式写回并销毁。\n */\nasync function sendResponseToSocket(socket: Socket, response: Response): Promise<void> {\n const body = await response.text().catch(() => '');\n const statusLine = `HTTP/1.1 ${response.status} ${response.statusText || ''}\\r\\n`;\n const headerLines: string[] = [];\n let hasContentLength = false;\n for (const [key, value] of response.headers) {\n if (key.toLowerCase() === 'content-length') {\n hasContentLength = true;\n }\n headerLines.push(`${key}: ${value}`);\n }\n if (!hasContentLength) {\n headerLines.push(`Content-Length: ${Buffer.byteLength(body)}`);\n }\n socket.write(statusLine + headerLines.join('\\r\\n') + '\\r\\n\\r\\n' + body);\n socket.destroy();\n}\n\nexport interface AttachWsOptions {\n /** HTTP server 实例(已由 createServer 创建) */\n server: Server;\n /** WS 路由清单(watch 模式下可通过更新此数组热更新) */\n wsRoutes: WsRouteManifest;\n /** 项目根目录,用于解析路由文件绝对路径 */\n rootDir: string;\n /** 业务配置,注入到 WsContext.config */\n config?: Record<string, unknown>;\n /** 错误响应格式化函数(来自 faapi.config.ts) */\n errorFormat?: ErrorFormatFn;\n /** 全局中间件(来自 faapi.config.ts,WS 握手最外层) */\n globalMiddlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,WS handler 可通过 ctx 间接访问全局依赖) */\n globalInjectors?: InjectorMap;\n}\n\n/**\n * 在 HTTP server 上挂载 WebSocket 升级处理\n *\n * 创建独立的 WebSocketServer(noServer 模式),监听 server 的 upgrade 事件。\n * 路由匹配成功后,走洋葱中间件链:\n * - 中间件放行(await next):finalHandler 内调用 ws.handleUpgrade 完成协议升级、绑定事件回调\n * - 中间件拦截(返回 Response):把 Response 写回 socket 后销毁,不进行协议升级\n * - 中间件抛错:由 errorFormat/内置兜底生成错误 Response,写回 socket 后销毁\n *\n * 中间件链顺序:全局中间件(外)→ 目录中间件(内)→ finalHandler。\n * watch 模式下 wsRoutes 通过引用更新(见 createServer 的 globalRef 模式)。\n */\nexport function attachWebSocket(options: AttachWsOptions): WebSocketServer {\n const { server, rootDir, config, errorFormat, globalMiddlewares } = options;\n // wsRoutes 通过闭包引用 globalRef,支持 watch 热更新\n const globalRef = globalThis as Record<string, unknown>;\n\n const wss = new WebSocketServer({ noServer: true });\n\n server.on('upgrade', async (req: IncomingMessage, socket: Socket, head: Buffer) => {\n const currentWsRoutes = (globalRef.__FAAPI_WS_ROUTES__ as WsRouteManifest) ?? options.wsRoutes;\n const pathname = getPathname(req);\n const match: WsRouteMatch | null = matchWsRoute(currentWsRoutes, pathname);\n\n if (!match) {\n // 路由不匹配:返回 404 并销毁 socket\n socket.write('HTTP/1.1 404 Not Found\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n\n const { route, params } = match;\n const headers = nodeHttpToWebHeaders(req);\n const host = req.headers.host ?? 'localhost';\n const url = `http://${host}${req.url ?? '/'}`;\n\n // 构造 Web Request 与 FaapiContext(与 HTTP 请求一致,供中间件使用)\n const request = new Request(url, { method: 'GET', headers });\n const ctx = createContext(request, params, config, getClientIp(req));\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n // 标记握手是否已完成协议升级(用于判断 socket 是否可写)\n let upgraded = false;\n\n // finalHandler:加载 WS handler + 协议升级 + 绑定事件\n const finalHandler = async (): Promise<Response> => {\n let handlers: WsEventHandlers | void;\n try {\n const absoluteFilePath = path.resolve(rootDir, route.filePath);\n // WsContext 是 FaapiContext 的结构子集,直接复用 ctx 实例\n // 中间件塞入的字段(如 ctx.user)对 WS handler 可见\n handlers = await loadWsHandler(absoluteFilePath, ctx as unknown as WsContext);\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n console.error(`[faapi] WS handler 加载失败 ${route.filePath}: ${reason}`);\n return new Response('Internal Server Error', { status: 500 });\n }\n\n // 协议升级:等 wss.handleUpgrade 回调完成 bindEvents\n await new Promise<void>((resolve, reject) => {\n wss.handleUpgrade(req, socket, head, (rawSocket: WebSocket) => {\n try {\n bindEvents(rawSocket, handlers);\n wss.emit('connection', rawSocket, req);\n upgraded = true;\n resolve();\n } catch (err) {\n reject(err);\n }\n });\n });\n\n // 占位 Response,表示握手成功(socket 已升级,不会被写出)\n return new Response(null, { status: 200 });\n };\n\n // 执行中间件链:全局中间件(外)+ 目录中间件(内)\n let response: Response;\n try {\n const dirMiddlewares = route.middlewares ?? [];\n const allMiddlewares =\n globalMiddlewares && globalMiddlewares.length > 0\n ? [...globalMiddlewares, ...dirMiddlewares]\n : dirMiddlewares;\n if (allMiddlewares.length > 0) {\n response = await compose(allMiddlewares, ctx, finalHandler);\n } else {\n response = await finalHandler();\n }\n } catch (err) {\n if (upgraded) {\n // 握手已完成(socket 已被 ws 库接管),中间件 after 阶段抛错无法改写响应\n console.error('[faapi] WS 握手后中间件抛错:', err);\n return;\n }\n // 错误兜底链:errorFormat 返回 null/未处理或抛错 → 内置 formatErrorResponse 兜底\n response = buildErrorResponse(err, ctx, errorFormat);\n }\n\n // 握手成功:socket 已升级,中间件 after 阶段已执行完,无需再写\n if (upgraded) {\n return;\n }\n\n // 中间件拦截或错误:把 Response 写回 socket 后销毁\n await sendResponseToSocket(socket, mergeMeta(response, meta));\n });\n\n return wss;\n}\n","import {\n createServer as createHttpServer,\n type Server,\n type IncomingMessage,\n type ServerResponse,\n} from 'node:http';\nimport { Readable } from 'node:stream';\nimport path from 'node:path';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport { matchRoute, matchDynamicPath } from '../router/matchRoute';\nimport { loadRouteModule } from '../loader/loadRouteModule';\nimport { createContext } from '../runtime/createContext';\nimport { resolveInput } from '../runtime/resolveInput';\nimport { invokeHandler, compose, mergeMeta } from '../runtime/invokeHandler';\nimport type { FaapiContext, ResponseMeta } from '../runtime/contextTypes';\nimport { sendNodeResponse } from '../response/sendNodeResponse';\nimport { RouteNotFoundError, MethodNotAllowedError, ValidationError } from '../errors/httpErrors';\nimport { validateInput } from '../validator/validateInput';\nimport { getInputTypeForMethod, hasBody } from '../runtime/inputType';\nimport { getClientIp } from '../utils/getClientIp';\nimport { cors, type CorsOptions } from '../middleware/cors';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport type { ResponseFormatFn, ErrorFormatFn } from '../config/configTypes';\nimport { serveStatic } from './serveStatic';\nimport { schemaRegistry } from '../validator/schemaRegistry';\nimport { extractSchemasForRoutes } from '../cli/generateSchema';\nimport { attachWebSocket } from './handleWsUpgrade';\nimport { nodeHttpToWebHeaders, buildErrorResponse } from './serverUtils';\n\n/**\n * 将 Node.js IncomingMessage 转为 Web Request 对象\n *\n * 协议判断:\n * 1. 优先使用 X-Forwarded-Proto 头(反向代理场景)\n * 2. 回退到 http(HTTPS 由外部代理处理)\n *\n * 请求体大小限制:10MB(防止 DoS)\n */\nconst MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB\n\nfunction toWebRequest(req: IncomingMessage): Request {\n // 协议判断:优先 X-Forwarded-Proto(反向代理),否则 http\n const forwardedProto = req.headers['x-forwarded-proto'];\n const protocol = Array.isArray(forwardedProto)\n ? (forwardedProto[0]?.split(',')[0]?.trim() ?? 'http')\n : (forwardedProto?.split(',')[0]?.trim() ?? 'http');\n const host = req.headers.host ?? 'localhost';\n const url = new URL(req.url ?? '/', `${protocol}://${host}`);\n\n const headers = nodeHttpToWebHeaders(req);\n\n const method = req.method ?? 'GET';\n\n // GET/HEAD 不应该有 body\n if (method === 'GET' || method === 'HEAD') {\n return new Request(url.toString(), { method, headers });\n }\n\n // 将 Node.js IncomingMessage 转为 Web ReadableStream\n // 并限制请求体大小(防止 DoS)\n const stream = Readable.toWeb(req) as ReadableStream<Uint8Array>;\n const limitedStream = limitStreamSize(stream, MAX_BODY_SIZE);\n return new Request(url.toString(), {\n method,\n headers,\n body: limitedStream,\n duplex: 'half',\n } as RequestInit);\n}\n\n/**\n * 限制 ReadableStream 的总字节数,超过限制时抛错\n */\nfunction limitStreamSize(\n stream: ReadableStream<Uint8Array>,\n maxSize: number,\n): ReadableStream<Uint8Array> {\n let totalSize = 0;\n const reader = stream.getReader();\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n reader.releaseLock();\n return;\n }\n totalSize += value.byteLength;\n if (totalSize > maxSize) {\n controller.error(new Error(`请求体超过大小限制 ${maxSize} 字节`));\n reader.releaseLock();\n return;\n }\n controller.enqueue(value);\n },\n cancel(reason) {\n reader.cancel(reason);\n },\n });\n}\n\n/**\n * 检查指定路径是否有其他方法的路由(用于 405 响应)\n */\nfunction findAllowedMethods(routes: RouteManifest, path: string): string[] {\n const methods = new Set<string>();\n for (const route of routes) {\n if (route.urlPath === path) {\n methods.add(route.method);\n continue;\n }\n // 也检查动态路由\n if (route.isDynamic) {\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n methods.add(route.method);\n }\n }\n }\n return Array.from(methods);\n}\n\nexport interface CreateServerOptions {\n routes: RouteManifest;\n rootDir: string;\n cors?: CorsOptions | boolean; // true = dev mode auto-enable, false = disabled\n staticDir?: string;\n /** 统一响应格式化函数 */\n responseFormat?: ResponseFormatFn;\n /** 错误响应格式化函数(优先于内置 formatErrorResponse 处理;返回 null/undefined 表示不处理) */\n errorFormat?: ErrorFormatFn;\n /** 请求错误钩子(在错误响应生成后调用,用于副作用;不修改已发出的响应) */\n onError?: (error: unknown, ctx: FaapiContext) => Promise<void> | void;\n /** 自定义业务配置(来自 faapi.config.ts,注入到 ctx.config) */\n config?: Record<string, unknown>;\n /** WebSocket 路由清单(空数组则不挂载 WS 支持) */\n wsRoutes?: WsRouteManifest;\n /** 全局中间件(来自 faapi.config.ts,对所有路由生效,最外层) */\n middlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,对所有路由 handler 参数注入生效) */\n injectors?: InjectorMap;\n}\n\n/**\n * 创建 faapi HTTP server\n *\n * @param options 路由清单、根目录\n * @returns Node.js Server 实例\n */\nexport function createServer(options: CreateServerOptions): Server {\n const {\n routes,\n rootDir,\n cors: corsOption,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares: globalMiddlewares,\n injectors: globalInjectors,\n } = options;\n\n // 初始化全局路由状态(watch 模式会更新这些值)\n const globalRef = globalThis as Record<string, unknown>;\n globalRef.__FAAPI_ROUTES__ = routes;\n if (wsRoutes) {\n globalRef.__FAAPI_WS_ROUTES__ = wsRoutes;\n }\n\n // 确保 schema 已注册到 registry\n // - 如果 registry 已有数据(startCommand 已加载 manifest 或 dev 已提取),跳过\n // - 如果 registry 为空(e2e 测试或直接调用 createServer),自动提取\n if (schemaRegistry.size === 0 && routes.length > 0) {\n const manifest = extractSchemasForRoutes(routes, rootDir);\n schemaRegistry.loadManifest(manifest);\n }\n\n // Build CORS middleware if enabled\n const corsMiddleware: FaapiMiddleware | null =\n corsOption === false\n ? null\n : corsOption === true || corsOption === undefined\n ? cors() // default: allow all (dev mode)\n : cors(corsOption);\n\n const server = createHttpServer((req: IncomingMessage, res: ServerResponse) => {\n // 每次请求读取最新的路由状态(支持 watch 模式热更新)\n const currentRoutes = (globalRef.__FAAPI_ROUTES__ as RouteManifest) ?? routes;\n\n handleRequest(\n currentRoutes,\n rootDir,\n req,\n res,\n corsMiddleware,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n globalMiddlewares,\n globalInjectors,\n ).catch(() => {\n res.statusCode = 500;\n res.end();\n });\n });\n\n // 挂载 WebSocket 升级处理(仅当提供了 WS 路由)\n if (wsRoutes && wsRoutes.length > 0) {\n attachWebSocket({ server, wsRoutes, rootDir, config, errorFormat, globalMiddlewares });\n }\n\n return server;\n}\n\nasync function handleRequest(\n routes: RouteManifest,\n rootDir: string,\n req: IncomingMessage,\n res: ServerResponse,\n corsMiddleware: FaapiMiddleware | null,\n staticDir: string | undefined,\n responseFormat: ResponseFormatFn | undefined,\n errorFormat: ErrorFormatFn | undefined,\n onError: ((error: unknown, ctx: FaapiContext) => Promise<void> | void) | undefined,\n config: Record<string, unknown> | undefined,\n globalMiddlewares: FaapiMiddleware[] | undefined,\n globalInjectors: InjectorMap | undefined,\n): Promise<void> {\n const request = toWebRequest(req);\n const method = request.method.toUpperCase();\n const urlPath = new URL(request.url).pathname;\n const ctx = createContext(request, {}, config, getClientIp(req));\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n // 路由处理管线:作为 CORS 中间件的 next\n // 包含路由匹配、静态文件、参数校验、handler 调用、响应格式化\n const routePipeline = async (): Promise<Response> => {\n // 尝试匹配路由\n const match = matchRoute(routes, method, urlPath);\n\n if (!match) {\n // 静态文件 fallback\n if (staticDir) {\n const absStaticDir = path.resolve(rootDir, staticDir);\n const staticResponse = await serveStatic(urlPath, absStaticDir);\n if (staticResponse) {\n return mergeMeta(staticResponse, meta);\n }\n }\n\n // 检查是否有其他方法匹配该路径\n const allowedMethods = findAllowedMethods(routes, urlPath);\n if (allowedMethods.length > 0) {\n throw new MethodNotAllowedError(method, urlPath, allowedMethods);\n }\n\n // 路由未匹配,返回 404\n throw new RouteNotFoundError(urlPath);\n }\n\n // 匹配成功,填充路由参数\n ctx.params = match.params;\n const { route } = match;\n\n // 处理 API 路由(handler.ts)\n const absoluteFilePath = path.resolve(rootDir, route.filePath);\n const routeModule = await loadRouteModule(absoluteFilePath, route.method);\n const input = await resolveInput(route.method, request);\n\n // 参数校验(统一从 inputType 模块获取输入类型)\n const inputType = getInputTypeForMethod(route.method);\n const result = await validateInput(absoluteFilePath, route.method, inputType, input);\n if (!result.valid) {\n throw new ValidationError('参数校验失败', result.issues);\n }\n\n const body = hasBody(route.method) ? result.data : undefined;\n // 合并注入器:全局注入器为基线,目录注入器覆盖同名\n const mergedInjectors = globalInjectors\n ? { ...globalInjectors, ...route.injectors }\n : route.injectors;\n let response = await invokeHandler(\n routeModule.handler,\n ctx,\n body,\n route.middlewares,\n mergedInjectors,\n );\n\n // 统一响应格式化:对非 Response 的成功响应应用 responseFormat\n if (responseFormat && response.status >= 200 && response.status < 300) {\n // 只对 JSON 响应(handler 返回的对象)应用格式化,跳过 Response 原样透传的情况\n const contentType = response.headers.get('Content-Type') ?? '';\n if (contentType.includes('application/json')) {\n const data = await response.json();\n const formatted = responseFormat(data, ctx);\n // 重新构建响应(保留原有 meta 信息)\n const { toResponse } = await import('../response/toResponse.js');\n response = await toResponse(formatted, meta);\n }\n }\n\n return response;\n };\n\n try {\n let response: Response;\n // 外层中间件链:CORS + 全局中间件(CORS 最外,全局次外)\n // 顺序:CORS.before → 全局.before → routePipeline(含目录中间件 + handler)→ 全局.after → CORS.after\n const outerMiddlewares: FaapiMiddleware[] = [];\n if (corsMiddleware) outerMiddlewares.push(corsMiddleware);\n if (globalMiddlewares && globalMiddlewares.length > 0) {\n outerMiddlewares.push(...globalMiddlewares);\n }\n\n if (outerMiddlewares.length > 0) {\n response = await compose(outerMiddlewares, ctx, routePipeline);\n } else {\n response = await routePipeline();\n }\n await sendNodeResponse(response, res);\n } catch (err: unknown) {\n // 错误处理兜底链(参考 Fastify 语义):\n // 1. 用户 errorFormat 返回 Response 表示已处理\n // 2. errorFormat 未处理(返回 null/undefined)或抛错 → 框架内置 formatErrorResponse 兜底\n // 3. 内置兜底仍抛错 → 最简 500 JSON 响应\n // 4. 响应发出后 → onError 触发副作用(不修改已发出的响应)\n const errorResponse = buildErrorResponse(err, ctx, errorFormat);\n await sendNodeResponse(mergeMeta(errorResponse, meta), res);\n\n // 响应已发出,触发 onError 副作用(日志/告警),自身抛错被忽略\n if (onError) {\n try {\n await onError(err, ctx);\n } catch {\n // onError 自身抛错不影响已发出的响应\n }\n }\n }\n}\n","import type { Server } from 'node:http';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport type { CorsOptions } from '../middleware/cors';\nimport type { ResponseFormatFn, ErrorFormatFn } from '../config/configTypes';\nimport type { FaapiContext } from '../runtime/contextTypes';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport type { RequestHandler, UpgradeHandler } from '../config/pluginTypes';\nimport { createServer } from './createServer';\n\nexport interface StartOptions {\n port: number;\n routes: RouteManifest;\n rootDir: string;\n cors?: CorsOptions | boolean;\n staticDir?: string;\n /** 统一响应格式化函数 */\n responseFormat?: ResponseFormatFn;\n /** 错误响应格式化函数(优先于内置 formatErrorResponse 处理;返回 null/undefined 表示不处理) */\n errorFormat?: ErrorFormatFn;\n /** 请求错误钩子(在错误响应生成后调用,用于副作用,不修改已发出的响应) */\n onError?: (error: unknown, ctx: FaapiContext) => Promise<void> | void;\n /** 自定义业务配置(来自 faapi.config.ts,注入到 ctx.config) */\n config?: Record<string, unknown>;\n /** WebSocket 路由清单 */\n wsRoutes?: WsRouteManifest;\n /** 全局中间件(来自 faapi.config.ts,对所有路由生效,最外层) */\n middlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,对所有路由 handler 参数注入生效) */\n injectors?: InjectorMap;\n /**\n * server.listen 之前的钩子(用于加载插件、应用 handler 包装等)\n *\n * 钩子在 server 创建后、listen 之前调用,可修改 server 的 request/upgrade listener。\n */\n beforeListen?: (server: Server) => Promise<void> | void;\n}\n\n/**\n * 启动 HTTP server 并打印路由表\n *\n * 流程:createServer → beforeListen(可选,加载插件/应用包装)→ listen → 打印路由表\n */\nexport function startServer(options: StartOptions): Promise<Server> {\n const {\n port,\n routes,\n rootDir,\n cors,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares,\n injectors,\n beforeListen,\n } = options;\n const server = createServer({\n routes,\n rootDir,\n cors,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares,\n injectors,\n });\n\n return (async () => {\n // beforeListen 钩子:加载插件、应用 handler 包装等\n if (beforeListen) {\n await beforeListen(server);\n }\n\n return new Promise<Server>((resolve) => {\n server.listen(port, () => {\n const address = server.address();\n const actualPort = typeof address === 'object' && address !== null ? address.port : port;\n\n console.log('faapi dev server started');\n console.log(`- Local: http://localhost:${actualPort}`);\n console.log('- Loaded routes:');\n\n for (const route of routes) {\n const method = route.method.padEnd(6);\n console.log(` ${method}${route.urlPath} ${route.filePath}`);\n }\n\n if (wsRoutes && wsRoutes.length > 0) {\n console.log('- WebSocket routes:');\n for (const route of wsRoutes) {\n console.log(` WS ${route.urlPath} ${route.filePath}`);\n }\n }\n\n resolve(server);\n });\n });\n })();\n}\n\n/**\n * 应用 handler / upgrade 包装器到 server\n *\n * 在 server.listen 之前调用,替换 server 的 request/upgrade listener。\n * 包装器按数组顺序嵌套:finalHandler = wrap1(wrap2(originalHandler))。\n *\n * @param server 目标 server(未 listen)\n * @param handlerWrappers HTTP handler 包装器数组\n * @param upgradeWrappers WS upgrade handler 包装器数组\n */\nexport function applyPluginWrappers(\n server: Server,\n handlerWrappers: Array<(original: RequestHandler) => RequestHandler>,\n upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler>,\n): void {\n // 应用 HTTP handler 包装\n if (handlerWrappers.length > 0) {\n const listeners = server.listeners('request');\n const original = listeners[0] as RequestHandler | undefined;\n if (original) {\n server.removeAllListeners('request');\n let handler: RequestHandler = original;\n for (const wrap of handlerWrappers) {\n handler = wrap(handler);\n }\n server.on('request', handler);\n }\n }\n\n // 应用 WS upgrade handler 包装\n if (upgradeWrappers.length > 0) {\n const listeners = server.listeners('upgrade');\n const original = listeners[0] as UpgradeHandler | undefined;\n server.removeAllListeners('upgrade');\n let upgrade: UpgradeHandler | undefined = original;\n for (const wrap of upgradeWrappers) {\n upgrade = wrap(upgrade);\n }\n if (upgrade) {\n server.on('upgrade', upgrade);\n }\n }\n}\n","import { stat, lstat, readdir, realpath } from 'node:fs/promises';\nimport { Readable } from 'node:stream';\nimport { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from 'node:path';\nexport const EntryTypes = {\n FILE_TYPE: 'files',\n DIR_TYPE: 'directories',\n FILE_DIR_TYPE: 'files_directories',\n EVERYTHING_TYPE: 'all',\n};\nconst defaultOptions = {\n root: '.',\n fileFilter: (_entryInfo) => true,\n directoryFilter: (_entryInfo) => true,\n type: EntryTypes.FILE_TYPE,\n lstat: false,\n depth: 2147483648,\n alwaysStat: false,\n highWaterMark: 4096,\n};\nObject.freeze(defaultOptions);\nconst RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';\nconst NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);\nconst ALL_TYPES = [\n EntryTypes.DIR_TYPE,\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n EntryTypes.FILE_TYPE,\n];\nconst DIR_TYPES = new Set([\n EntryTypes.DIR_TYPE,\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n]);\nconst FILE_TYPES = new Set([\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n EntryTypes.FILE_TYPE,\n]);\nconst isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);\nconst wantBigintFsStats = process.platform === 'win32';\nconst emptyFn = (_entryInfo) => true;\nconst normalizeFilter = (filter) => {\n if (filter === undefined)\n return emptyFn;\n if (typeof filter === 'function')\n return filter;\n if (typeof filter === 'string') {\n const fl = filter.trim();\n return (entry) => entry.basename === fl;\n }\n if (Array.isArray(filter)) {\n const trItems = filter.map((item) => item.trim());\n return (entry) => trItems.some((f) => entry.basename === f);\n }\n return emptyFn;\n};\n/** Readable readdir stream, emitting new files as they're being listed. */\nexport class ReaddirpStream extends Readable {\n constructor(options = {}) {\n super({\n objectMode: true,\n autoDestroy: true,\n highWaterMark: options.highWaterMark,\n });\n const opts = { ...defaultOptions, ...options };\n const { root, type } = opts;\n this._fileFilter = normalizeFilter(opts.fileFilter);\n this._directoryFilter = normalizeFilter(opts.directoryFilter);\n const statMethod = opts.lstat ? lstat : stat;\n // Use bigint stats if it's windows and stat() supports options (node 10+).\n if (wantBigintFsStats) {\n this._stat = (path) => statMethod(path, { bigint: true });\n }\n else {\n this._stat = statMethod;\n }\n this._maxDepth = opts.depth ?? defaultOptions.depth;\n this._wantsDir = type ? DIR_TYPES.has(type) : false;\n this._wantsFile = type ? FILE_TYPES.has(type) : false;\n this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;\n this._root = presolve(root);\n this._isDirent = !opts.alwaysStat;\n this._statsProp = this._isDirent ? 'dirent' : 'stats';\n this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };\n // Launch stream with one parent, the root dir.\n this.parents = [this._exploreDir(root, 1)];\n this.reading = false;\n this.parent = undefined;\n }\n async _read(batch) {\n if (this.reading)\n return;\n this.reading = true;\n try {\n while (!this.destroyed && batch > 0) {\n const par = this.parent;\n const fil = par && par.files;\n if (fil && fil.length > 0) {\n const { path, depth } = par;\n const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path));\n const awaited = await Promise.all(slice);\n for (const entry of awaited) {\n if (!entry)\n continue;\n if (this.destroyed)\n return;\n const entryType = await this._getEntryType(entry);\n if (entryType === 'directory' && this._directoryFilter(entry)) {\n if (depth <= this._maxDepth) {\n this.parents.push(this._exploreDir(entry.fullPath, depth + 1));\n }\n if (this._wantsDir) {\n this.push(entry);\n batch--;\n }\n }\n else if ((entryType === 'file' || this._includeAsFile(entry)) &&\n this._fileFilter(entry)) {\n if (this._wantsFile) {\n this.push(entry);\n batch--;\n }\n }\n }\n }\n else {\n const parent = this.parents.pop();\n if (!parent) {\n this.push(null);\n break;\n }\n this.parent = await parent;\n if (this.destroyed)\n return;\n }\n }\n }\n catch (error) {\n this.destroy(error);\n }\n finally {\n this.reading = false;\n }\n }\n async _exploreDir(path, depth) {\n let files;\n try {\n files = await readdir(path, this._rdOptions);\n }\n catch (error) {\n this._onError(error);\n }\n return { files, depth, path };\n }\n async _formatEntry(dirent, path) {\n let entry;\n const basename = this._isDirent ? dirent.name : dirent;\n try {\n const fullPath = presolve(pjoin(path, basename));\n entry = { path: prelative(this._root, fullPath), fullPath, basename };\n entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);\n }\n catch (err) {\n this._onError(err);\n return;\n }\n return entry;\n }\n _onError(err) {\n if (isNormalFlowError(err) && !this.destroyed) {\n this.emit('warn', err);\n }\n else {\n this.destroy(err);\n }\n }\n async _getEntryType(entry) {\n // entry may be undefined, because a warning or an error were emitted\n // and the statsProp is undefined\n if (!entry && this._statsProp in entry) {\n return '';\n }\n const stats = entry[this._statsProp];\n if (stats.isFile())\n return 'file';\n if (stats.isDirectory())\n return 'directory';\n if (stats && stats.isSymbolicLink()) {\n const full = entry.fullPath;\n try {\n const entryRealPath = await realpath(full);\n const entryRealPathStats = await lstat(entryRealPath);\n if (entryRealPathStats.isFile()) {\n return 'file';\n }\n if (entryRealPathStats.isDirectory()) {\n const len = entryRealPath.length;\n if (full.startsWith(entryRealPath) && full.substr(len, 1) === psep) {\n const recursiveError = new Error(`Circular symlink detected: \"${full}\" points to \"${entryRealPath}\"`);\n // @ts-ignore\n recursiveError.code = RECURSIVE_ERROR_CODE;\n return this._onError(recursiveError);\n }\n return 'directory';\n }\n }\n catch (error) {\n this._onError(error);\n return '';\n }\n }\n }\n _includeAsFile(entry) {\n const stats = entry && entry[this._statsProp];\n return stats && this._wantsEverything && !stats.isDirectory();\n }\n}\n/**\n * Streaming version: Reads all files and directories in given root recursively.\n * Consumes ~constant small amount of RAM.\n * @param root Root directory\n * @param options Options to specify root (start directory), filters and recursion depth\n */\nexport function readdirp(root, options = {}) {\n // @ts-ignore\n let type = options.entryType || options.type;\n if (type === 'both')\n type = EntryTypes.FILE_DIR_TYPE; // backwards-compatibility\n if (type)\n options.type = type;\n if (!root) {\n throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');\n }\n else if (typeof root !== 'string') {\n throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');\n }\n else if (type && !ALL_TYPES.includes(type)) {\n throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);\n }\n options.root = root;\n return new ReaddirpStream(options);\n}\n/**\n * Promise version: Reads all files and directories in given root recursively.\n * Compared to streaming version, will consume a lot of RAM e.g. when 1 million files are listed.\n * @returns array of paths and their entry infos\n */\nexport function readdirpPromise(root, options = {}) {\n return new Promise((resolve, reject) => {\n const files = [];\n readdirp(root, options)\n .on('data', (entry) => files.push(entry))\n .on('end', () => resolve(files))\n .on('error', (error) => reject(error));\n });\n}\nexport default readdirp;\n","import { watchFile, unwatchFile, watch as fs_watch } from 'fs';\nimport { open, stat, lstat, realpath as fsrealpath } from 'fs/promises';\nimport * as sysPath from 'path';\nimport { type as osType } from 'os';\nexport const STR_DATA = 'data';\nexport const STR_END = 'end';\nexport const STR_CLOSE = 'close';\nexport const EMPTY_FN = () => { };\nexport const IDENTITY_FN = (val) => val;\nconst pl = process.platform;\nexport const isWindows = pl === 'win32';\nexport const isMacos = pl === 'darwin';\nexport const isLinux = pl === 'linux';\nexport const isFreeBSD = pl === 'freebsd';\nexport const isIBMi = osType() === 'OS400';\nexport const EVENTS = {\n ALL: 'all',\n READY: 'ready',\n ADD: 'add',\n CHANGE: 'change',\n ADD_DIR: 'addDir',\n UNLINK: 'unlink',\n UNLINK_DIR: 'unlinkDir',\n RAW: 'raw',\n ERROR: 'error',\n};\nconst EV = EVENTS;\nconst THROTTLE_MODE_WATCH = 'watch';\nconst statMethods = { lstat, stat };\nconst KEY_LISTENERS = 'listeners';\nconst KEY_ERR = 'errHandlers';\nconst KEY_RAW = 'rawEmitters';\nconst HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];\n// prettier-ignore\nconst binaryExtensions = new Set([\n '3dm', '3ds', '3g2', '3gp', '7z', 'a', 'aac', 'adp', 'afdesign', 'afphoto', 'afpub', 'ai',\n 'aif', 'aiff', 'alz', 'ape', 'apk', 'appimage', 'ar', 'arj', 'asf', 'au', 'avi',\n 'bak', 'baml', 'bh', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'bzip2',\n 'cab', 'caf', 'cgm', 'class', 'cmx', 'cpio', 'cr2', 'cur', 'dat', 'dcm', 'deb', 'dex', 'djvu',\n 'dll', 'dmg', 'dng', 'doc', 'docm', 'docx', 'dot', 'dotm', 'dra', 'DS_Store', 'dsk', 'dts',\n 'dtshd', 'dvb', 'dwg', 'dxf',\n 'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe',\n 'f4v', 'fbs', 'fh', 'fla', 'flac', 'flatpak', 'fli', 'flv', 'fpx', 'fst', 'fvt',\n 'g3', 'gh', 'gif', 'graffle', 'gz', 'gzip',\n 'h261', 'h263', 'h264', 'icns', 'ico', 'ief', 'img', 'ipa', 'iso',\n 'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'key', 'ktx',\n 'lha', 'lib', 'lvp', 'lz', 'lzh', 'lzma', 'lzo',\n 'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mht', 'mid', 'midi', 'mj2', 'mka', 'mkv', 'mmr', 'mng',\n 'mobi', 'mov', 'movie', 'mp3',\n 'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu',\n 'nef', 'npx', 'numbers', 'nupkg',\n 'o', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'otf', 'ott',\n 'pages', 'pbm', 'pcx', 'pdb', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'pot', 'potm',\n 'potx', 'ppa', 'ppam',\n 'ppm', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'psd', 'pya', 'pyc', 'pyo', 'pyv',\n 'qt',\n 'rar', 'ras', 'raw', 'resources', 'rgb', 'rip', 'rlc', 'rmf', 'rmvb', 'rpm', 'rtf', 'rz',\n 's3m', 's7z', 'scpt', 'sgi', 'shar', 'snap', 'sil', 'sketch', 'slk', 'smv', 'snk', 'so',\n 'stl', 'suo', 'sub', 'swf',\n 'tar', 'tbz', 'tbz2', 'tga', 'tgz', 'thmx', 'tif', 'tiff', 'tlz', 'ttc', 'ttf', 'txz',\n 'udf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu',\n 'viv', 'vob',\n 'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wim', 'wm', 'wma',\n 'wmv', 'wmx', 'woff', 'woff2', 'wrm', 'wvx',\n 'xbm', 'xif', 'xla', 'xlam', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xm',\n 'xmind', 'xpi', 'xpm', 'xwd', 'xz',\n 'z', 'zip', 'zipx',\n]);\nconst isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());\n// TODO: emit errors properly. Example: EMFILE on Macos.\nconst foreach = (val, fn) => {\n if (val instanceof Set) {\n val.forEach(fn);\n }\n else {\n fn(val);\n }\n};\nconst addAndConvert = (main, prop, item) => {\n let container = main[prop];\n if (!(container instanceof Set)) {\n main[prop] = container = new Set([container]);\n }\n container.add(item);\n};\nconst clearItem = (cont) => (key) => {\n const set = cont[key];\n if (set instanceof Set) {\n set.clear();\n }\n else {\n delete cont[key];\n }\n};\nconst delFromSet = (main, prop, item) => {\n const container = main[prop];\n if (container instanceof Set) {\n container.delete(item);\n }\n else if (container === item) {\n delete main[prop];\n }\n};\nconst isEmptySet = (val) => (val instanceof Set ? val.size === 0 : !val);\nconst FsWatchInstances = new Map();\n/**\n * Instantiates the fs_watch interface\n * @param path to be watched\n * @param options to be passed to fs_watch\n * @param listener main event handler\n * @param errHandler emits info about errors\n * @param emitRaw emits raw event data\n * @returns {NativeFsWatcher}\n */\nfunction createFsWatchInstance(path, options, listener, errHandler, emitRaw) {\n const handleEvent = (rawEvent, evPath) => {\n listener(path);\n emitRaw(rawEvent, evPath, { watchedPath: path });\n // emit based on events occurring for files from a directory's watcher in\n // case the file's watcher misses it (and rely on throttling to de-dupe)\n if (evPath && path !== evPath) {\n fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));\n }\n };\n try {\n return fs_watch(path, {\n persistent: options.persistent,\n }, handleEvent);\n }\n catch (error) {\n errHandler(error);\n return undefined;\n }\n}\n/**\n * Helper for passing fs_watch event data to a collection of listeners\n * @param fullPath absolute path bound to fs_watch instance\n */\nconst fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {\n const cont = FsWatchInstances.get(fullPath);\n if (!cont)\n return;\n foreach(cont[listenerType], (listener) => {\n listener(val1, val2, val3);\n });\n};\n/**\n * Instantiates the fs_watch interface or binds listeners\n * to an existing one covering the same file system entry\n * @param path\n * @param fullPath absolute path\n * @param options to be passed to fs_watch\n * @param handlers container for event listener functions\n */\nconst setFsWatchListener = (path, fullPath, options, handlers) => {\n const { listener, errHandler, rawEmitter } = handlers;\n let cont = FsWatchInstances.get(fullPath);\n let watcher;\n if (!options.persistent) {\n watcher = createFsWatchInstance(path, options, listener, errHandler, rawEmitter);\n if (!watcher)\n return;\n return watcher.close.bind(watcher);\n }\n if (cont) {\n addAndConvert(cont, KEY_LISTENERS, listener);\n addAndConvert(cont, KEY_ERR, errHandler);\n addAndConvert(cont, KEY_RAW, rawEmitter);\n }\n else {\n watcher = createFsWatchInstance(path, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, // no need to use broadcast here\n fsWatchBroadcast.bind(null, fullPath, KEY_RAW));\n if (!watcher)\n return;\n watcher.on(EV.ERROR, async (error) => {\n const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);\n if (cont)\n cont.watcherUnusable = true; // documented since Node 10.4.1\n // Workaround for https://github.com/joyent/node/issues/4337\n if (isWindows && error.code === 'EPERM') {\n try {\n const fd = await open(path, 'r');\n await fd.close();\n broadcastErr(error);\n }\n catch (err) {\n // do nothing\n }\n }\n else {\n broadcastErr(error);\n }\n });\n cont = {\n listeners: listener,\n errHandlers: errHandler,\n rawEmitters: rawEmitter,\n watcher,\n };\n FsWatchInstances.set(fullPath, cont);\n }\n // const index = cont.listeners.indexOf(listener);\n // removes this instance's listeners and closes the underlying fs_watch\n // instance if there are no more listeners left\n return () => {\n delFromSet(cont, KEY_LISTENERS, listener);\n delFromSet(cont, KEY_ERR, errHandler);\n delFromSet(cont, KEY_RAW, rawEmitter);\n if (isEmptySet(cont.listeners)) {\n // Check to protect against issue gh-730.\n // if (cont.watcherUnusable) {\n cont.watcher.close();\n // }\n FsWatchInstances.delete(fullPath);\n HANDLER_KEYS.forEach(clearItem(cont));\n // @ts-ignore\n cont.watcher = undefined;\n Object.freeze(cont);\n }\n };\n};\n// fs_watchFile helpers\n// object to hold per-process fs_watchFile instances\n// (may be shared across chokidar FSWatcher instances)\nconst FsWatchFileInstances = new Map();\n/**\n * Instantiates the fs_watchFile interface or binds listeners\n * to an existing one covering the same file system entry\n * @param path to be watched\n * @param fullPath absolute path\n * @param options options to be passed to fs_watchFile\n * @param handlers container for event listener functions\n * @returns closer\n */\nconst setFsWatchFileListener = (path, fullPath, options, handlers) => {\n const { listener, rawEmitter } = handlers;\n let cont = FsWatchFileInstances.get(fullPath);\n // let listeners = new Set();\n // let rawEmitters = new Set();\n const copts = cont && cont.options;\n if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {\n // \"Upgrade\" the watcher to persistence or a quicker interval.\n // This creates some unlikely edge case issues if the user mixes\n // settings in a very weird way, but solving for those cases\n // doesn't seem worthwhile for the added complexity.\n // listeners = cont.listeners;\n // rawEmitters = cont.rawEmitters;\n unwatchFile(fullPath);\n cont = undefined;\n }\n if (cont) {\n addAndConvert(cont, KEY_LISTENERS, listener);\n addAndConvert(cont, KEY_RAW, rawEmitter);\n }\n else {\n // TODO\n // listeners.add(listener);\n // rawEmitters.add(rawEmitter);\n cont = {\n listeners: listener,\n rawEmitters: rawEmitter,\n options,\n watcher: watchFile(fullPath, options, (curr, prev) => {\n foreach(cont.rawEmitters, (rawEmitter) => {\n rawEmitter(EV.CHANGE, fullPath, { curr, prev });\n });\n const currmtime = curr.mtimeMs;\n if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {\n foreach(cont.listeners, (listener) => listener(path, curr));\n }\n }),\n };\n FsWatchFileInstances.set(fullPath, cont);\n }\n // const index = cont.listeners.indexOf(listener);\n // Removes this instance's listeners and closes the underlying fs_watchFile\n // instance if there are no more listeners left.\n return () => {\n delFromSet(cont, KEY_LISTENERS, listener);\n delFromSet(cont, KEY_RAW, rawEmitter);\n if (isEmptySet(cont.listeners)) {\n FsWatchFileInstances.delete(fullPath);\n unwatchFile(fullPath);\n cont.options = cont.watcher = undefined;\n Object.freeze(cont);\n }\n };\n};\n/**\n * @mixin\n */\nexport class NodeFsHandler {\n constructor(fsW) {\n this.fsw = fsW;\n this._boundHandleError = (error) => fsW._handleError(error);\n }\n /**\n * Watch file for changes with fs_watchFile or fs_watch.\n * @param path to file or dir\n * @param listener on fs change\n * @returns closer for the watcher instance\n */\n _watchWithNodeFs(path, listener) {\n const opts = this.fsw.options;\n const directory = sysPath.dirname(path);\n const basename = sysPath.basename(path);\n const parent = this.fsw._getWatchedDir(directory);\n parent.add(basename);\n const absolutePath = sysPath.resolve(path);\n const options = {\n persistent: opts.persistent,\n };\n if (!listener)\n listener = EMPTY_FN;\n let closer;\n if (opts.usePolling) {\n const enableBin = opts.interval !== opts.binaryInterval;\n options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;\n closer = setFsWatchFileListener(path, absolutePath, options, {\n listener,\n rawEmitter: this.fsw._emitRaw,\n });\n }\n else {\n closer = setFsWatchListener(path, absolutePath, options, {\n listener,\n errHandler: this._boundHandleError,\n rawEmitter: this.fsw._emitRaw,\n });\n }\n return closer;\n }\n /**\n * Watch a file and emit add event if warranted.\n * @returns closer for the watcher instance\n */\n _handleFile(file, stats, initialAdd) {\n if (this.fsw.closed) {\n return;\n }\n const dirname = sysPath.dirname(file);\n const basename = sysPath.basename(file);\n const parent = this.fsw._getWatchedDir(dirname);\n // stats is always present\n let prevStats = stats;\n // if the file is already being watched, do nothing\n if (parent.has(basename))\n return;\n const listener = async (path, newStats) => {\n if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))\n return;\n if (!newStats || newStats.mtimeMs === 0) {\n try {\n const newStats = await stat(file);\n if (this.fsw.closed)\n return;\n // Check that change event was not fired because of changed only accessTime.\n const at = newStats.atimeMs;\n const mt = newStats.mtimeMs;\n if (!at || at <= mt || mt !== prevStats.mtimeMs) {\n this.fsw._emit(EV.CHANGE, file, newStats);\n }\n if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) {\n this.fsw._closeFile(path);\n prevStats = newStats;\n const closer = this._watchWithNodeFs(file, listener);\n if (closer)\n this.fsw._addPathCloser(path, closer);\n }\n else {\n prevStats = newStats;\n }\n }\n catch (error) {\n // Fix issues where mtime is null but file is still present\n this.fsw._remove(dirname, basename);\n }\n // add is about to be emitted if file not already tracked in parent\n }\n else if (parent.has(basename)) {\n // Check that change event was not fired because of changed only accessTime.\n const at = newStats.atimeMs;\n const mt = newStats.mtimeMs;\n if (!at || at <= mt || mt !== prevStats.mtimeMs) {\n this.fsw._emit(EV.CHANGE, file, newStats);\n }\n prevStats = newStats;\n }\n };\n // kick off the watcher\n const closer = this._watchWithNodeFs(file, listener);\n // emit an add event if we're supposed to\n if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {\n if (!this.fsw._throttle(EV.ADD, file, 0))\n return;\n this.fsw._emit(EV.ADD, file, stats);\n }\n return closer;\n }\n /**\n * Handle symlinks encountered while reading a dir.\n * @param entry returned by readdirp\n * @param directory path of dir being read\n * @param path of this item\n * @param item basename of this item\n * @returns true if no more processing is needed for this entry.\n */\n async _handleSymlink(entry, directory, path, item) {\n if (this.fsw.closed) {\n return;\n }\n const full = entry.fullPath;\n const dir = this.fsw._getWatchedDir(directory);\n if (!this.fsw.options.followSymlinks) {\n // watch symlink directly (don't follow) and detect changes\n this.fsw._incrReadyCount();\n let linkPath;\n try {\n linkPath = await fsrealpath(path);\n }\n catch (e) {\n this.fsw._emitReady();\n return true;\n }\n if (this.fsw.closed)\n return;\n if (dir.has(item)) {\n if (this.fsw._symlinkPaths.get(full) !== linkPath) {\n this.fsw._symlinkPaths.set(full, linkPath);\n this.fsw._emit(EV.CHANGE, path, entry.stats);\n }\n }\n else {\n dir.add(item);\n this.fsw._symlinkPaths.set(full, linkPath);\n this.fsw._emit(EV.ADD, path, entry.stats);\n }\n this.fsw._emitReady();\n return true;\n }\n // don't follow the same symlink more than once\n if (this.fsw._symlinkPaths.has(full)) {\n return true;\n }\n this.fsw._symlinkPaths.set(full, true);\n }\n _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {\n // Normalize the directory name on Windows\n directory = sysPath.join(directory, '');\n throttler = this.fsw._throttle('readdir', directory, 1000);\n if (!throttler)\n return;\n const previous = this.fsw._getWatchedDir(wh.path);\n const current = new Set();\n let stream = this.fsw._readdirp(directory, {\n fileFilter: (entry) => wh.filterPath(entry),\n directoryFilter: (entry) => wh.filterDir(entry),\n });\n if (!stream)\n return;\n stream\n .on(STR_DATA, async (entry) => {\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n const item = entry.path;\n let path = sysPath.join(directory, item);\n current.add(item);\n if (entry.stats.isSymbolicLink() &&\n (await this._handleSymlink(entry, directory, path, item))) {\n return;\n }\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n // Files that present in current directory snapshot\n // but absent in previous are added to watch list and\n // emit `add` event.\n if (item === target || (!target && !previous.has(item))) {\n this.fsw._incrReadyCount();\n // ensure relativeness of path is preserved in case of watcher reuse\n path = sysPath.join(dir, sysPath.relative(dir, path));\n this._addToNodeFs(path, initialAdd, wh, depth + 1);\n }\n })\n .on(EV.ERROR, this._boundHandleError);\n return new Promise((resolve, reject) => {\n if (!stream)\n return reject();\n stream.once(STR_END, () => {\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n const wasThrottled = throttler ? throttler.clear() : false;\n resolve(undefined);\n // Files that absent in current directory snapshot\n // but present in previous emit `remove` event\n // and are removed from @watched[directory].\n previous\n .getChildren()\n .filter((item) => {\n return item !== directory && !current.has(item);\n })\n .forEach((item) => {\n this.fsw._remove(directory, item);\n });\n stream = undefined;\n // one more time for any missed in case changes came in extremely quickly\n if (wasThrottled)\n this._handleRead(directory, false, wh, target, dir, depth, throttler);\n });\n });\n }\n /**\n * Read directory to add / remove files from `@watched` list and re-read it on change.\n * @param dir fs path\n * @param stats\n * @param initialAdd\n * @param depth relative to user-supplied path\n * @param target child path targeted for watch\n * @param wh Common watch helpers for this path\n * @param realpath\n * @returns closer for the watcher instance.\n */\n async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {\n const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));\n const tracked = parentDir.has(sysPath.basename(dir));\n if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {\n this.fsw._emit(EV.ADD_DIR, dir, stats);\n }\n // ensure dir is tracked (harmless if redundant)\n parentDir.add(sysPath.basename(dir));\n this.fsw._getWatchedDir(dir);\n let throttler;\n let closer;\n const oDepth = this.fsw.options.depth;\n if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {\n if (!target) {\n await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);\n if (this.fsw.closed)\n return;\n }\n closer = this._watchWithNodeFs(dir, (dirPath, stats) => {\n // if current directory is removed, do nothing\n if (stats && stats.mtimeMs === 0)\n return;\n this._handleRead(dirPath, false, wh, target, dir, depth, throttler);\n });\n }\n return closer;\n }\n /**\n * Handle added file, directory, or glob pattern.\n * Delegates call to _handleFile / _handleDir after checks.\n * @param path to file or ir\n * @param initialAdd was the file added at watch instantiation?\n * @param priorWh depth relative to user-supplied path\n * @param depth Child path actually targeted for watch\n * @param target Child path actually targeted for watch\n */\n async _addToNodeFs(path, initialAdd, priorWh, depth, target) {\n const ready = this.fsw._emitReady;\n if (this.fsw._isIgnored(path) || this.fsw.closed) {\n ready();\n return false;\n }\n const wh = this.fsw._getWatchHelpers(path);\n if (priorWh) {\n wh.filterPath = (entry) => priorWh.filterPath(entry);\n wh.filterDir = (entry) => priorWh.filterDir(entry);\n }\n // evaluate what is at the path we're being asked to watch\n try {\n const stats = await statMethods[wh.statMethod](wh.watchPath);\n if (this.fsw.closed)\n return;\n if (this.fsw._isIgnored(wh.watchPath, stats)) {\n ready();\n return false;\n }\n const follow = this.fsw.options.followSymlinks;\n let closer;\n if (stats.isDirectory()) {\n const absPath = sysPath.resolve(path);\n const targetPath = follow ? await fsrealpath(path) : path;\n if (this.fsw.closed)\n return;\n closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);\n if (this.fsw.closed)\n return;\n // preserve this symlink's target path\n if (absPath !== targetPath && targetPath !== undefined) {\n this.fsw._symlinkPaths.set(absPath, targetPath);\n }\n }\n else if (stats.isSymbolicLink()) {\n const targetPath = follow ? await fsrealpath(path) : path;\n if (this.fsw.closed)\n return;\n const parent = sysPath.dirname(wh.watchPath);\n this.fsw._getWatchedDir(parent).add(wh.watchPath);\n this.fsw._emit(EV.ADD, wh.watchPath, stats);\n closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);\n if (this.fsw.closed)\n return;\n // preserve this symlink's target path\n if (targetPath !== undefined) {\n this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);\n }\n }\n else {\n closer = this._handleFile(wh.watchPath, stats, initialAdd);\n }\n ready();\n if (closer)\n this.fsw._addPathCloser(path, closer);\n return false;\n }\n catch (error) {\n if (this.fsw._handleError(error)) {\n ready();\n return path;\n }\n }\n }\n}\n","/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */\nimport { stat as statcb } from 'fs';\nimport { stat, readdir } from 'fs/promises';\nimport { EventEmitter } from 'events';\nimport * as sysPath from 'path';\nimport { readdirp } from 'readdirp';\nimport { NodeFsHandler, EVENTS as EV, isWindows, isIBMi, EMPTY_FN, STR_CLOSE, STR_END, } from './handler.js';\nconst SLASH = '/';\nconst SLASH_SLASH = '//';\nconst ONE_DOT = '.';\nconst TWO_DOTS = '..';\nconst STRING_TYPE = 'string';\nconst BACK_SLASH_RE = /\\\\/g;\nconst DOUBLE_SLASH_RE = /\\/\\//;\nconst DOT_RE = /\\..*\\.(sw[px])$|~$|\\.subl.*\\.tmp/;\nconst REPLACER_RE = /^\\.[/\\\\]/;\nfunction arrify(item) {\n return Array.isArray(item) ? item : [item];\n}\nconst isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);\nfunction createPattern(matcher) {\n if (typeof matcher === 'function')\n return matcher;\n if (typeof matcher === 'string')\n return (string) => matcher === string;\n if (matcher instanceof RegExp)\n return (string) => matcher.test(string);\n if (typeof matcher === 'object' && matcher !== null) {\n return (string) => {\n if (matcher.path === string)\n return true;\n if (matcher.recursive) {\n const relative = sysPath.relative(matcher.path, string);\n if (!relative) {\n return false;\n }\n return !relative.startsWith('..') && !sysPath.isAbsolute(relative);\n }\n return false;\n };\n }\n return () => false;\n}\nfunction normalizePath(path) {\n if (typeof path !== 'string')\n throw new Error('string expected');\n path = sysPath.normalize(path);\n path = path.replace(/\\\\/g, '/');\n let prepend = false;\n if (path.startsWith('//'))\n prepend = true;\n const DOUBLE_SLASH_RE = /\\/\\//;\n while (path.match(DOUBLE_SLASH_RE))\n path = path.replace(DOUBLE_SLASH_RE, '/');\n if (prepend)\n path = '/' + path;\n return path;\n}\nfunction matchPatterns(patterns, testString, stats) {\n const path = normalizePath(testString);\n for (let index = 0; index < patterns.length; index++) {\n const pattern = patterns[index];\n if (pattern(path, stats)) {\n return true;\n }\n }\n return false;\n}\nfunction anymatch(matchers, testString) {\n if (matchers == null) {\n throw new TypeError('anymatch: specify first argument');\n }\n // Early cache for matchers.\n const matchersArray = arrify(matchers);\n const patterns = matchersArray.map((matcher) => createPattern(matcher));\n if (testString == null) {\n return (testString, stats) => {\n return matchPatterns(patterns, testString, stats);\n };\n }\n return matchPatterns(patterns, testString);\n}\nconst unifyPaths = (paths_) => {\n const paths = arrify(paths_).flat();\n if (!paths.every((p) => typeof p === STRING_TYPE)) {\n throw new TypeError(`Non-string provided as watch path: ${paths}`);\n }\n return paths.map(normalizePathToUnix);\n};\n// If SLASH_SLASH occurs at the beginning of path, it is not replaced\n// because \"//StoragePC/DrivePool/Movies\" is a valid network path\nconst toUnix = (string) => {\n let str = string.replace(BACK_SLASH_RE, SLASH);\n let prepend = false;\n if (str.startsWith(SLASH_SLASH)) {\n prepend = true;\n }\n while (str.match(DOUBLE_SLASH_RE)) {\n str = str.replace(DOUBLE_SLASH_RE, SLASH);\n }\n if (prepend) {\n str = SLASH + str;\n }\n return str;\n};\n// Our version of upath.normalize\n// TODO: this is not equal to path-normalize module - investigate why\nconst normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));\n// TODO: refactor\nconst normalizeIgnored = (cwd = '') => (path) => {\n if (typeof path === 'string') {\n return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));\n }\n else {\n return path;\n }\n};\nconst getAbsolutePath = (path, cwd) => {\n if (sysPath.isAbsolute(path)) {\n return path;\n }\n return sysPath.join(cwd, path);\n};\nconst EMPTY_SET = Object.freeze(new Set());\n/**\n * Directory entry.\n */\nclass DirEntry {\n constructor(dir, removeWatcher) {\n this.path = dir;\n this._removeWatcher = removeWatcher;\n this.items = new Set();\n }\n add(item) {\n const { items } = this;\n if (!items)\n return;\n if (item !== ONE_DOT && item !== TWO_DOTS)\n items.add(item);\n }\n async remove(item) {\n const { items } = this;\n if (!items)\n return;\n items.delete(item);\n if (items.size > 0)\n return;\n const dir = this.path;\n try {\n await readdir(dir);\n }\n catch (err) {\n if (this._removeWatcher) {\n this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));\n }\n }\n }\n has(item) {\n const { items } = this;\n if (!items)\n return;\n return items.has(item);\n }\n getChildren() {\n const { items } = this;\n if (!items)\n return [];\n return [...items.values()];\n }\n dispose() {\n this.items.clear();\n this.path = '';\n this._removeWatcher = EMPTY_FN;\n this.items = EMPTY_SET;\n Object.freeze(this);\n }\n}\nconst STAT_METHOD_F = 'stat';\nconst STAT_METHOD_L = 'lstat';\nexport class WatchHelper {\n constructor(path, follow, fsw) {\n this.fsw = fsw;\n const watchPath = path;\n this.path = path = path.replace(REPLACER_RE, '');\n this.watchPath = watchPath;\n this.fullWatchPath = sysPath.resolve(watchPath);\n this.dirParts = [];\n this.dirParts.forEach((parts) => {\n if (parts.length > 1)\n parts.pop();\n });\n this.followSymlinks = follow;\n this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;\n }\n entryPath(entry) {\n return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));\n }\n filterPath(entry) {\n const { stats } = entry;\n if (stats && stats.isSymbolicLink())\n return this.filterDir(entry);\n const resolvedPath = this.entryPath(entry);\n // TODO: what if stats is undefined? remove !\n return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);\n }\n filterDir(entry) {\n return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);\n }\n}\n/**\n * Watches files & directories for changes. Emitted events:\n * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`\n *\n * new FSWatcher()\n * .add(directories)\n * .on('add', path => log('File', path, 'was added'))\n */\nexport class FSWatcher extends EventEmitter {\n // Not indenting methods for history sake; for now.\n constructor(_opts = {}) {\n super();\n this.closed = false;\n this._closers = new Map();\n this._ignoredPaths = new Set();\n this._throttled = new Map();\n this._streams = new Set();\n this._symlinkPaths = new Map();\n this._watched = new Map();\n this._pendingWrites = new Map();\n this._pendingUnlinks = new Map();\n this._readyCount = 0;\n this._readyEmitted = false;\n const awf = _opts.awaitWriteFinish;\n const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };\n const opts = {\n // Defaults\n persistent: true,\n ignoreInitial: false,\n ignorePermissionErrors: false,\n interval: 100,\n binaryInterval: 300,\n followSymlinks: true,\n usePolling: false,\n // useAsync: false,\n atomic: true, // NOTE: overwritten later (depends on usePolling)\n ..._opts,\n // Change format\n ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),\n awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,\n };\n // Always default to polling on IBM i because fs.watch() is not available on IBM i.\n if (isIBMi)\n opts.usePolling = true;\n // Editor atomic write normalization enabled by default with fs.watch\n if (opts.atomic === undefined)\n opts.atomic = !opts.usePolling;\n // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;\n // Global override. Useful for developers, who need to force polling for all\n // instances of chokidar, regardless of usage / dependency depth\n const envPoll = process.env.CHOKIDAR_USEPOLLING;\n if (envPoll !== undefined) {\n const envLower = envPoll.toLowerCase();\n if (envLower === 'false' || envLower === '0')\n opts.usePolling = false;\n else if (envLower === 'true' || envLower === '1')\n opts.usePolling = true;\n else\n opts.usePolling = !!envLower;\n }\n const envInterval = process.env.CHOKIDAR_INTERVAL;\n if (envInterval)\n opts.interval = Number.parseInt(envInterval, 10);\n // This is done to emit ready only once, but each 'add' will increase that?\n let readyCalls = 0;\n this._emitReady = () => {\n readyCalls++;\n if (readyCalls >= this._readyCount) {\n this._emitReady = EMPTY_FN;\n this._readyEmitted = true;\n // use process.nextTick to allow time for listener to be bound\n process.nextTick(() => this.emit(EV.READY));\n }\n };\n this._emitRaw = (...args) => this.emit(EV.RAW, ...args);\n this._boundRemove = this._remove.bind(this);\n this.options = opts;\n this._nodeFsHandler = new NodeFsHandler(this);\n // You’re frozen when your heart’s not open.\n Object.freeze(opts);\n }\n _addIgnoredPath(matcher) {\n if (isMatcherObject(matcher)) {\n // return early if we already have a deeply equal matcher object\n for (const ignored of this._ignoredPaths) {\n if (isMatcherObject(ignored) &&\n ignored.path === matcher.path &&\n ignored.recursive === matcher.recursive) {\n return;\n }\n }\n }\n this._ignoredPaths.add(matcher);\n }\n _removeIgnoredPath(matcher) {\n this._ignoredPaths.delete(matcher);\n // now find any matcher objects with the matcher as path\n if (typeof matcher === 'string') {\n for (const ignored of this._ignoredPaths) {\n // TODO (43081j): make this more efficient.\n // probably just make a `this._ignoredDirectories` or some\n // such thing.\n if (isMatcherObject(ignored) && ignored.path === matcher) {\n this._ignoredPaths.delete(ignored);\n }\n }\n }\n }\n // Public methods\n /**\n * Adds paths to be watched on an existing FSWatcher instance.\n * @param paths_ file or file list. Other arguments are unused\n */\n add(paths_, _origAdd, _internal) {\n const { cwd } = this.options;\n this.closed = false;\n this._closePromise = undefined;\n let paths = unifyPaths(paths_);\n if (cwd) {\n paths = paths.map((path) => {\n const absPath = getAbsolutePath(path, cwd);\n // Check `path` instead of `absPath` because the cwd portion can't be a glob\n return absPath;\n });\n }\n paths.forEach((path) => {\n this._removeIgnoredPath(path);\n });\n this._userIgnored = undefined;\n if (!this._readyCount)\n this._readyCount = 0;\n this._readyCount += paths.length;\n Promise.all(paths.map(async (path) => {\n const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);\n if (res)\n this._emitReady();\n return res;\n })).then((results) => {\n if (this.closed)\n return;\n results.forEach((item) => {\n if (item)\n this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));\n });\n });\n return this;\n }\n /**\n * Close watchers or start ignoring events from specified paths.\n */\n unwatch(paths_) {\n if (this.closed)\n return this;\n const paths = unifyPaths(paths_);\n const { cwd } = this.options;\n paths.forEach((path) => {\n // convert to absolute path unless relative path already matches\n if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {\n if (cwd)\n path = sysPath.join(cwd, path);\n path = sysPath.resolve(path);\n }\n this._closePath(path);\n this._addIgnoredPath(path);\n if (this._watched.has(path)) {\n this._addIgnoredPath({\n path,\n recursive: true,\n });\n }\n // reset the cached userIgnored anymatch fn\n // to make ignoredPaths changes effective\n this._userIgnored = undefined;\n });\n return this;\n }\n /**\n * Close watchers and remove all listeners from watched paths.\n */\n close() {\n if (this._closePromise) {\n return this._closePromise;\n }\n this.closed = true;\n // Memory management.\n this.removeAllListeners();\n const closers = [];\n this._closers.forEach((closerList) => closerList.forEach((closer) => {\n const promise = closer();\n if (promise instanceof Promise)\n closers.push(promise);\n }));\n this._streams.forEach((stream) => stream.destroy());\n this._userIgnored = undefined;\n this._readyCount = 0;\n this._readyEmitted = false;\n this._watched.forEach((dirent) => dirent.dispose());\n this._closers.clear();\n this._watched.clear();\n this._streams.clear();\n this._symlinkPaths.clear();\n this._throttled.clear();\n this._closePromise = closers.length\n ? Promise.all(closers).then(() => undefined)\n : Promise.resolve();\n return this._closePromise;\n }\n /**\n * Expose list of watched paths\n * @returns for chaining\n */\n getWatched() {\n const watchList = {};\n this._watched.forEach((entry, dir) => {\n const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;\n const index = key || ONE_DOT;\n watchList[index] = entry.getChildren().sort();\n });\n return watchList;\n }\n emitWithAll(event, args) {\n this.emit(event, ...args);\n if (event !== EV.ERROR)\n this.emit(EV.ALL, event, ...args);\n }\n // Common helpers\n // --------------\n /**\n * Normalize and emit events.\n * Calling _emit DOES NOT MEAN emit() would be called!\n * @param event Type of event\n * @param path File or directory path\n * @param stats arguments to be passed with event\n * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag\n */\n async _emit(event, path, stats) {\n if (this.closed)\n return;\n const opts = this.options;\n if (isWindows)\n path = sysPath.normalize(path);\n if (opts.cwd)\n path = sysPath.relative(opts.cwd, path);\n const args = [path];\n if (stats != null)\n args.push(stats);\n const awf = opts.awaitWriteFinish;\n let pw;\n if (awf && (pw = this._pendingWrites.get(path))) {\n pw.lastChange = new Date();\n return this;\n }\n if (opts.atomic) {\n if (event === EV.UNLINK) {\n this._pendingUnlinks.set(path, [event, ...args]);\n setTimeout(() => {\n this._pendingUnlinks.forEach((entry, path) => {\n this.emit(...entry);\n this.emit(EV.ALL, ...entry);\n this._pendingUnlinks.delete(path);\n });\n }, typeof opts.atomic === 'number' ? opts.atomic : 100);\n return this;\n }\n if (event === EV.ADD && this._pendingUnlinks.has(path)) {\n event = EV.CHANGE;\n this._pendingUnlinks.delete(path);\n }\n }\n if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {\n const awfEmit = (err, stats) => {\n if (err) {\n event = EV.ERROR;\n args[0] = err;\n this.emitWithAll(event, args);\n }\n else if (stats) {\n // if stats doesn't exist the file must have been deleted\n if (args.length > 1) {\n args[1] = stats;\n }\n else {\n args.push(stats);\n }\n this.emitWithAll(event, args);\n }\n };\n this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);\n return this;\n }\n if (event === EV.CHANGE) {\n const isThrottled = !this._throttle(EV.CHANGE, path, 50);\n if (isThrottled)\n return this;\n }\n if (opts.alwaysStat &&\n stats === undefined &&\n (event === EV.ADD || event === EV.ADD_DIR || event === EV.CHANGE)) {\n const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;\n let stats;\n try {\n stats = await stat(fullPath);\n }\n catch (err) {\n // do nothing\n }\n // Suppress event when fs_stat fails, to avoid sending undefined 'stat'\n if (!stats || this.closed)\n return;\n args.push(stats);\n }\n this.emitWithAll(event, args);\n return this;\n }\n /**\n * Common handler for errors\n * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag\n */\n _handleError(error) {\n const code = error && error.code;\n if (error &&\n code !== 'ENOENT' &&\n code !== 'ENOTDIR' &&\n (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {\n this.emit(EV.ERROR, error);\n }\n return error || this.closed;\n }\n /**\n * Helper utility for throttling\n * @param actionType type being throttled\n * @param path being acted upon\n * @param timeout duration of time to suppress duplicate actions\n * @returns tracking object or false if action should be suppressed\n */\n _throttle(actionType, path, timeout) {\n if (!this._throttled.has(actionType)) {\n this._throttled.set(actionType, new Map());\n }\n const action = this._throttled.get(actionType);\n if (!action)\n throw new Error('invalid throttle');\n const actionPath = action.get(path);\n if (actionPath) {\n actionPath.count++;\n return false;\n }\n // eslint-disable-next-line prefer-const\n let timeoutObject;\n const clear = () => {\n const item = action.get(path);\n const count = item ? item.count : 0;\n action.delete(path);\n clearTimeout(timeoutObject);\n if (item)\n clearTimeout(item.timeoutObject);\n return count;\n };\n timeoutObject = setTimeout(clear, timeout);\n const thr = { timeoutObject, clear, count: 0 };\n action.set(path, thr);\n return thr;\n }\n _incrReadyCount() {\n return this._readyCount++;\n }\n /**\n * Awaits write operation to finish.\n * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.\n * @param path being acted upon\n * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished\n * @param event\n * @param awfEmit Callback to be called when ready for event to be emitted.\n */\n _awaitWriteFinish(path, threshold, event, awfEmit) {\n const awf = this.options.awaitWriteFinish;\n if (typeof awf !== 'object')\n return;\n const pollInterval = awf.pollInterval;\n let timeoutHandler;\n let fullPath = path;\n if (this.options.cwd && !sysPath.isAbsolute(path)) {\n fullPath = sysPath.join(this.options.cwd, path);\n }\n const now = new Date();\n const writes = this._pendingWrites;\n function awaitWriteFinishFn(prevStat) {\n statcb(fullPath, (err, curStat) => {\n if (err || !writes.has(path)) {\n if (err && err.code !== 'ENOENT')\n awfEmit(err);\n return;\n }\n const now = Number(new Date());\n if (prevStat && curStat.size !== prevStat.size) {\n writes.get(path).lastChange = now;\n }\n const pw = writes.get(path);\n const df = now - pw.lastChange;\n if (df >= threshold) {\n writes.delete(path);\n awfEmit(undefined, curStat);\n }\n else {\n timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);\n }\n });\n }\n if (!writes.has(path)) {\n writes.set(path, {\n lastChange: now,\n cancelWait: () => {\n writes.delete(path);\n clearTimeout(timeoutHandler);\n return event;\n },\n });\n timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);\n }\n }\n /**\n * Determines whether user has asked to ignore this path.\n */\n _isIgnored(path, stats) {\n if (this.options.atomic && DOT_RE.test(path))\n return true;\n if (!this._userIgnored) {\n const { cwd } = this.options;\n const ign = this.options.ignored;\n const ignored = (ign || []).map(normalizeIgnored(cwd));\n const ignoredPaths = [...this._ignoredPaths];\n const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];\n this._userIgnored = anymatch(list, undefined);\n }\n return this._userIgnored(path, stats);\n }\n _isntIgnored(path, stat) {\n return !this._isIgnored(path, stat);\n }\n /**\n * Provides a set of common helpers and properties relating to symlink handling.\n * @param path file or directory pattern being watched\n */\n _getWatchHelpers(path) {\n return new WatchHelper(path, this.options.followSymlinks, this);\n }\n // Directory helpers\n // -----------------\n /**\n * Provides directory tracking objects\n * @param directory path of the directory\n */\n _getWatchedDir(directory) {\n const dir = sysPath.resolve(directory);\n if (!this._watched.has(dir))\n this._watched.set(dir, new DirEntry(dir, this._boundRemove));\n return this._watched.get(dir);\n }\n // File helpers\n // ------------\n /**\n * Check for read permissions: https://stackoverflow.com/a/11781404/1358405\n */\n _hasReadPermissions(stats) {\n if (this.options.ignorePermissionErrors)\n return true;\n return Boolean(Number(stats.mode) & 0o400);\n }\n /**\n * Handles emitting unlink events for\n * files and directories, and via recursion, for\n * files and directories within directories that are unlinked\n * @param directory within which the following item is located\n * @param item base path of item/directory\n */\n _remove(directory, item, isDirectory) {\n // if what is being deleted is a directory, get that directory's paths\n // for recursive deleting and cleaning of watched object\n // if it is not a directory, nestedDirectoryChildren will be empty array\n const path = sysPath.join(directory, item);\n const fullPath = sysPath.resolve(path);\n isDirectory =\n isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);\n // prevent duplicate handling in case of arriving here nearly simultaneously\n // via multiple paths (such as _handleFile and _handleDir)\n if (!this._throttle('remove', path, 100))\n return;\n // if the only watched file is removed, watch for its return\n if (!isDirectory && this._watched.size === 1) {\n this.add(directory, item, true);\n }\n // This will create a new entry in the watched object in either case\n // so we got to do the directory check beforehand\n const wp = this._getWatchedDir(path);\n const nestedDirectoryChildren = wp.getChildren();\n // Recursively remove children directories / files.\n nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));\n // Check if item was on the watched list and remove it\n const parent = this._getWatchedDir(directory);\n const wasTracked = parent.has(item);\n parent.remove(item);\n // Fixes issue #1042 -> Relative paths were detected and added as symlinks\n // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),\n // but never removed from the map in case the path was deleted.\n // This leads to an incorrect state if the path was recreated:\n // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553\n if (this._symlinkPaths.has(fullPath)) {\n this._symlinkPaths.delete(fullPath);\n }\n // If we wait for this file to be fully written, cancel the wait.\n let relPath = path;\n if (this.options.cwd)\n relPath = sysPath.relative(this.options.cwd, path);\n if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {\n const event = this._pendingWrites.get(relPath).cancelWait();\n if (event === EV.ADD)\n return;\n }\n // The Entry will either be a directory that just got removed\n // or a bogus entry to a file, in either case we have to remove it\n this._watched.delete(path);\n this._watched.delete(fullPath);\n const eventName = isDirectory ? EV.UNLINK_DIR : EV.UNLINK;\n if (wasTracked && !this._isIgnored(path))\n this._emit(eventName, path);\n // Avoid conflicts if we later create another file with the same name\n this._closePath(path);\n }\n /**\n * Closes all watchers for a path\n */\n _closePath(path) {\n this._closeFile(path);\n const dir = sysPath.dirname(path);\n this._getWatchedDir(dir).remove(sysPath.basename(path));\n }\n /**\n * Closes only file-specific watchers\n */\n _closeFile(path) {\n const closers = this._closers.get(path);\n if (!closers)\n return;\n closers.forEach((closer) => closer());\n this._closers.delete(path);\n }\n _addPathCloser(path, closer) {\n if (!closer)\n return;\n let list = this._closers.get(path);\n if (!list) {\n list = [];\n this._closers.set(path, list);\n }\n list.push(closer);\n }\n _readdirp(root, opts) {\n if (this.closed)\n return;\n const options = { type: EV.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };\n let stream = readdirp(root, options);\n this._streams.add(stream);\n stream.once(STR_CLOSE, () => {\n stream = undefined;\n });\n stream.once(STR_END, () => {\n if (stream) {\n this._streams.delete(stream);\n stream = undefined;\n }\n });\n return stream;\n }\n}\n/**\n * Instantiates watcher with paths to be tracked.\n * @param paths file / directory paths\n * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others\n * @returns an instance of FSWatcher for chaining.\n * @example\n * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });\n * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })\n */\nexport function watch(paths, options = {}) {\n const watcher = new FSWatcher(options);\n watcher.add(paths);\n return watcher;\n}\nexport default { watch, FSWatcher };\n","import chokidar from 'chokidar';\nimport type { Server } from 'node:http';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { invalidateMiddlewareCache } from '../middleware/loadMiddlewares';\nimport { invalidateProgramCache } from '../ast/createProgram';\nimport { schemaRegistry } from '../validator/schemaRegistry';\nimport { extractSchemasForRoutes } from './generateSchema';\n\nexport interface WatchOptions {\n rootDir: string;\n patterns: string[];\n appDir: string;\n server: Server;\n port: number;\n cors?: boolean;\n staticDir?: string;\n types?: string;\n}\n\n/**\n * 启动 watch 模式\n *\n * 监听文件变化(handler.ts / middlewares.ts):\n * - 清理所有缓存(中间件 + Program)\n * - 全量重新扫描路由 + 提取 schema\n * - 通过全局状态让 server 使用最新路由(HTTP + WS)\n *\n * 全量重建而非增量更新,理由:\n * - 简单可靠,无状态一致性问题\n * - 跨文件类型引用自然解决(全量提取时所有类型都在)\n * - dev 模式文件量有限,全量提取在百毫秒级,debounce 后用户无感\n *\n * ESM 模块缓存通过时间戳 query string 绕过。\n */\nexport function startWatcher(options: WatchOptions): void {\n const { rootDir, patterns, appDir } = options;\n\n // 重建定时器(debounce)\n let rebuildTimer: ReturnType<typeof setTimeout> | null = null;\n\n // 全量重建路由和 schema\n async function rebuildRoutes(): Promise<void> {\n try {\n // 更新模块加载时间戳,ESM import 时拼接该时间戳绕过缓存\n const timestamp = Date.now();\n (globalThis as Record<string, unknown>).__FAAPI_LOAD_TS__ = timestamp;\n\n // 清理所有缓存(中间件 + Program)\n invalidateMiddlewareCache();\n invalidateProgramCache();\n\n // 重新扫描路由(HTTP + WS)\n const { routes, wsRoutes } = await scanRoutes(rootDir, patterns, appDir);\n const sorted = sortRoutes(routes);\n\n // 全量提取 schema 并加载到注册表\n const manifest = extractSchemasForRoutes(sorted, rootDir);\n schemaRegistry.loadManifest(manifest);\n\n // 更新服务器的路由引用(HTTP + WS)\n updateServerRoutes(sorted, wsRoutes);\n\n const wsCount = wsRoutes.length;\n console.log(\n `- Routes rebuilt: ${sorted.length} route(s), ${wsCount} WS route(s), ${manifest.size} file(s)`,\n );\n } catch (err) {\n console.error('- Error rebuilding routes:', err instanceof Error ? err.message : String(err));\n }\n }\n\n // debounce 重建:编辑器保存时可能触发多次写操作\n function scheduleRebuild(): void {\n if (rebuildTimer) clearTimeout(rebuildTimer);\n rebuildTimer = setTimeout(() => {\n rebuildTimer = null;\n void rebuildRoutes();\n }, 100);\n }\n\n // 监听文件变化\n const watchPatterns = [...patterns, `${appDir}/**/middlewares.ts`];\n\n const watcher = chokidar.watch(watchPatterns, {\n cwd: rootDir,\n ignoreInitial: true,\n ignored: ['**/node_modules/**', '**/.faapi/**', '**/dist/**'],\n });\n\n watcher.on('add', () => scheduleRebuild());\n watcher.on('change', () => scheduleRebuild());\n watcher.on('unlink', () => scheduleRebuild());\n\n console.log('- Watch mode enabled');\n}\n\n/**\n * 更新服务器的路由引用(HTTP + WS)\n * 通过修改全局状态实现热更新\n */\nfunction updateServerRoutes(routes: RouteManifest, wsRoutes: WsRouteManifest): void {\n (globalThis as Record<string, unknown>).__FAAPI_ROUTES__ = routes;\n (globalThis as Record<string, unknown>).__FAAPI_WS_ROUTES__ = wsRoutes;\n}\n","import path from 'node:path';\nimport fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { FaapiConfig } from './configTypes';\n\n/**\n * 配置文件查找顺序\n *\n * 1. faapi.config.ts / faapi.config.js(基础配置)\n * 2. faapi.config.{env}.ts / faapi.config.{env}.js(环境覆盖)\n *\n * 环境覆盖深度合并到基础配置上(见 deepMerge)\n */\nconst BASE_CONFIG_FILES = ['faapi.config.ts', 'faapi.config.js'];\n\n/**\n * 获取当前运行环境(用于加载 faapi.config.{env}.ts)\n *\n * 优先级:FAAPI_ENV → NODE_ENV → 'development'\n *\n * FAAPI_ENV 优先:让 faapi 的环境切换不污染全局 NODE_ENV(其他库也读 NODE_ENV)。\n * FAAPI_ENV 未设时回退 NODE_ENV,符合 Node 生态默认直觉。\n */\nfunction getEnv(): string {\n return process.env.FAAPI_ENV || process.env.NODE_ENV || 'development';\n}\n\n/**\n * 深度合并两个配置对象(后者覆盖前者)\n *\n * 特殊对象(Date / RegExp / Map / Set)直接替换,不递归合并。\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n base: T,\n override: Record<string, unknown>,\n): T {\n const result = { ...base };\n for (const key of Object.keys(override)) {\n const baseVal = (base as Record<string, unknown>)[key];\n const overVal = override[key];\n\n // 特殊对象类型直接替换(不递归合并)\n if (\n baseVal instanceof Date ||\n overVal instanceof Date ||\n baseVal instanceof RegExp ||\n overVal instanceof RegExp ||\n baseVal instanceof Map ||\n overVal instanceof Map ||\n baseVal instanceof Set ||\n overVal instanceof Set\n ) {\n (result as Record<string, unknown>)[key] = overVal;\n continue;\n }\n\n // 普通对象递归合并\n if (\n baseVal !== null &&\n overVal !== null &&\n typeof baseVal === 'object' &&\n typeof overVal === 'object' &&\n !Array.isArray(baseVal) &&\n !Array.isArray(overVal) &&\n !(baseVal instanceof Function) &&\n !(overVal instanceof Function)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n baseVal as Record<string, unknown>,\n overVal as Record<string, unknown>,\n );\n } else {\n (result as Record<string, unknown>)[key] = overVal;\n }\n }\n return result;\n}\n\n/**\n * 加载单个配置文件\n */\nasync function loadConfigFile(filePath: string): Promise<Partial<FaapiConfig> | null> {\n if (!fs.existsSync(filePath)) {\n return null;\n }\n\n try {\n const url = pathToFileURL(filePath).href;\n const module = (await import(url)) as { default?: Partial<FaapiConfig> };\n return module.default ?? {};\n } catch (err) {\n throw new Error(\n `Failed to load config file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n}\n\n/**\n * 加载 faapi 配置文件\n *\n * 查找顺序:\n * 1. 指定的 configPath\n * 2. faapi.config.ts / faapi.config.js(基础配置)\n * 3. faapi.config.{env}.ts / faapi.config.{env}.js(环境覆盖,深度合并)\n *\n * 环境由 FAAPI_ENV 或 NODE_ENV 决定,默认 'development'\n *\n * @param rootDir 项目根目录\n * @param configPath 指定的配置文件路径(可选)\n * @returns 合并后的配置,如果无配置文件则返回 null\n */\nexport async function loadConfig(\n rootDir: string,\n configPath?: string,\n): Promise<Partial<FaapiConfig> | null> {\n // 指定了配置文件路径时,直接加载该文件(文件不存在则抛错)\n if (configPath) {\n const resolvedPath = path.resolve(rootDir, configPath);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`Config file not found: ${configPath}`);\n }\n return loadConfigFile(resolvedPath);\n }\n\n // 查找基础配置文件\n let baseConfig: Partial<FaapiConfig> | null = null;\n for (const fileName of BASE_CONFIG_FILES) {\n const filePath = path.join(rootDir, fileName);\n baseConfig = await loadConfigFile(filePath);\n if (baseConfig) break;\n }\n\n if (!baseConfig) {\n return null;\n }\n\n // 查找环境配置文件并合并\n const env = getEnv();\n const envFiles = [`faapi.config.${env}.ts`, `faapi.config.${env}.js`];\n\n for (const envFile of envFiles) {\n const envConfig = await loadConfigFile(path.join(rootDir, envFile));\n if (envConfig) {\n baseConfig = deepMerge(baseConfig, envConfig);\n break;\n }\n }\n\n return baseConfig;\n}\n","import type { FaapiPlugin, PluginDeclaration } from '../config/pluginTypes';\nimport type { RequestHandler, UpgradeHandler } from '../config/pluginTypes';\n\n/** loadPlugins 的输入上下文(不含 wrap 能力,由 loadPlugins 内部注入) */\ntype LoadPluginsContext = Omit<\n import('../config/pluginTypes').PluginContext,\n 'wrapHandler' | 'wrapUpgradeHandler'\n>;\n\n/** loadPlugins 返回的包装器收集结果 */\nexport interface PluginLoadResult {\n /** 插件注册的 HTTP handler 包装器(按注册顺序) */\n handlerWrappers: Array<(original: RequestHandler) => RequestHandler>;\n /** 插件注册的 WS upgrade handler 包装器(按注册顺序) */\n upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler>;\n}\n\n/**\n * 加载并执行插件列表\n *\n * 遍历 config.plugins,动态 import 插件包,调用 setup(ctx)。\n * 插件在 server 创建后、listen 之前按声明顺序执行。\n *\n * 插件可通过 ctx.wrapHandler / ctx.wrapUpgradeHandler 注册包装函数,\n * 本函数收集后返回,由调用方在 listen 之前应用。\n *\n * @param declarations 插件声明列表\n * @param ctx 插件上下文(不含 wrap 能力,由本函数注入)\n * @returns 包装器收集结果\n */\nexport async function loadPlugins(\n declarations: PluginDeclaration[] | undefined,\n ctx: LoadPluginsContext,\n): Promise<PluginLoadResult> {\n const handlerWrappers: Array<(original: RequestHandler) => RequestHandler> = [];\n const upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler> = [];\n\n if (!declarations || declarations.length === 0) {\n return { handlerWrappers, upgradeWrappers };\n }\n\n // 注入 wrap 能力到 ctx\n const fullCtx = {\n ...ctx,\n wrapHandler: (fn: (original: RequestHandler) => RequestHandler) => {\n handlerWrappers.push(fn);\n },\n wrapUpgradeHandler: (fn: (original: UpgradeHandler | undefined) => UpgradeHandler) => {\n upgradeWrappers.push(fn);\n },\n };\n\n const loaded = new Set<string>();\n\n for (const decl of declarations) {\n const { specifier, options, enable } = resolveDeclaration(decl);\n\n // enable 检查\n if (enable === false) continue;\n\n // 去重\n if (loaded.has(specifier)) {\n console.warn(`! Plugin already loaded: ${specifier}, skipping`);\n continue;\n }\n loaded.add(specifier);\n\n try {\n const mod = await import(specifier);\n const plugin: FaapiPlugin = mod.default ?? mod;\n\n if (typeof plugin.setup !== 'function') {\n console.warn(`! Plugin ${specifier} has no setup function, skipping`);\n continue;\n }\n\n await plugin.setup({ ...fullCtx, options });\n console.log(`- Plugin loaded: ${plugin.name ?? specifier}`);\n } catch (err) {\n console.warn(\n `! Failed to load plugin ${specifier}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return { handlerWrappers, upgradeWrappers };\n}\n\n/**\n * 解析插件声明为统一格式\n */\nfunction resolveDeclaration(decl: PluginDeclaration): {\n specifier: string;\n options?: unknown;\n enable?: boolean;\n} {\n if (typeof decl === 'string') {\n return { specifier: decl };\n }\n\n if (Array.isArray(decl)) {\n const [specifier, options] = decl;\n return { specifier, options };\n }\n\n if ('package' in decl) {\n return { specifier: decl.package, options: decl.options, enable: decl.enable };\n }\n\n if ('path' in decl) {\n return { specifier: decl.path, options: decl.options, enable: decl.enable };\n }\n\n // 不应该到这里\n throw new Error(`Invalid plugin declaration: ${JSON.stringify(decl)}`);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { parseArgs } from './parseArgs';\nimport { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { detectRouteConflicts } from '../router/detectRouteConflicts';\nimport { startServer, applyPluginWrappers } from '../server/startServer';\nimport { generateTypes } from './generateTypes';\nimport { startWatcher } from './watcher';\nimport { loadConfig } from '../config/loadConfig';\nimport { schemaRegistry } from '../validator/schemaRegistry';\nimport { extractSchemasForRoutes, readManifestFile } from './generateSchema';\nimport { hydrateRoutes } from './generateRoutes';\nimport { loadPlugins } from './loadPlugins';\nimport type { SchemaManifest } from '../validator/schemaRegistry';\n\n/**\n * CLI 启动命令的完整流程\n *\n * dev 模式(默认,`faapi` 或 `faapi dev`):\n * 1. 解析参数\n * 2. 加载配置文件\n * 3. 扫描路由(.ts)\n * 4. 排序路由\n * 5. 检测路由冲突\n * 6. 全量提取 schema → schemaRegistry.loadManifest\n * 7. 生成类型文件(可选)\n * 8. 启动 server\n * 9. 执行 onReady 生命周期钩子\n * 10. 启动 watch 模式(文件变化全量重建 schema)\n *\n * start 模式(`faapi start`,生产模式):\n * 1. 解析参数(patterns/appDir 自动指向 dist)\n * 2. 加载配置文件\n * 3. 扫描路由(.js)\n * 4. 排序路由\n * 5. 检测路由冲突\n * 6. 加载 dist/faapi-schema.js → schemaRegistry.loadManifest\n * 7. 启动 server\n * 8. 执行 onReady 生命周期钩子\n *\n * dev 和 start 共用 createServer / handleRequest / validateInput,\n * 差异仅在 schema 来源、文件类型、是否启动 watch。\n *\n * @param argv 原始 CLI 参数(含命令词 dev/start,由 parseArgs 解析)\n */\nexport async function startCommand(argv: string[]): Promise<void> {\n const args = parseArgs(argv);\n const rootDir = process.cwd();\n\n // mode === 'start' → 生产模式,加载 dist 产物\n const isProd = args.mode === 'start';\n\n // 生产模式要求 dist/faapi-routes.js 和 dist/faapi-schema.js 存在(由 faapi build 生成)\n if (isProd) {\n const routesPath = path.resolve(rootDir, 'dist', 'faapi-routes.js');\n const schemaPath = path.resolve(rootDir, 'dist', 'faapi-schema.js');\n if (!fs.existsSync(routesPath) || !fs.existsSync(schemaPath)) {\n console.error(\n '[faapi] dist/faapi-routes.js 或 dist/faapi-schema.js 不存在,请先执行 `faapi build` 构建生产产物。',\n );\n process.exit(1);\n }\n }\n\n if (isProd) {\n // 同步 NODE_ENV 给生态(如 Next.js 运行时 20+ 处直接读 process.env.NODE_ENV 做分支)\n // 仅在未显式设置时回退,避免覆盖用户意图\n if (!process.env.NODE_ENV) process.env.NODE_ENV = 'production';\n console.log('- Production mode');\n } else {\n // 标记 dev 模式\n process.env.__FAAPI_DEV__ = '1';\n if (!process.env.NODE_ENV) process.env.NODE_ENV = 'development';\n console.log('- Development mode');\n }\n\n // 加载配置文件\n const config = await loadConfig(rootDir, args.config);\n if (config) {\n console.log('- Config loaded');\n }\n\n // 路由获取:start 读清单+水合,dev 扫描文件系统\n let routes: import('../router/routeTypes').RouteManifest;\n let wsRoutes: import('../router/routeTypes').WsRouteManifest;\n if (isProd) {\n // start 模式:从 dist/faapi-routes.js 读取序列化清单,水合(加载中间件)\n const routesPath = path.resolve(rootDir, 'dist', 'faapi-routes.js');\n const serialized = (await import(pathToFileURL(routesPath).href)) as import('./generateRoutes').SerializedRouteManifest;\n const hydrated = await hydrateRoutes(serialized);\n routes = hydrated.routes;\n wsRoutes = hydrated.wsRoutes;\n console.log(`- Routes loaded: ${routes.length} routes, ${wsRoutes.length} WS routes`);\n } else {\n // dev 模式:扫描文件系统\n const { patterns, appDir } = { patterns: args.patterns, appDir: args.appDir };\n const scanned = await scanRoutes(rootDir, patterns, appDir);\n routes = scanned.routes;\n wsRoutes = scanned.wsRoutes;\n console.log(`- Routes scanned: ${routes.length} routes, ${wsRoutes.length} WS routes`);\n }\n const sorted = sortRoutes(routes);\n\n // 检测路由冲突(相同 method + urlPath 的多个文件)\n const conflicts = detectRouteConflicts(sorted);\n if (conflicts.length > 0) {\n for (const conflict of conflicts) {\n console.warn(`! 路由冲突: ${conflict.method} ${conflict.urlPath}`);\n for (const file of conflict.files) {\n console.warn(` - ${file}`);\n }\n }\n }\n\n // 加载 schema\n if (isProd) {\n // prod 模式:从 faapi-schema.js import 加载\n const schemaPath = path.resolve(rootDir, 'dist', 'faapi-schema.js');\n const manifest = await readManifestFile(schemaPath);\n // build 时 schema key 是绝对路径 + .ts(如 /abs/api/health/handler.ts),\n // 运行时 route.filePath 是相对路径 + .js + dist 前缀(如 dist/api/health/handler.js)。\n // 重写 key 使两者匹配,validateInput 才能查到。\n const remapped = remapManifestKeys(manifest, rootDir);\n schemaRegistry.loadManifest(remapped);\n console.log(`- Schema loaded: ${schemaPath}`);\n } else {\n // dev 模式:全量提取 schema 并生成校验函数(watcher 全量重建)\n const manifest = extractSchemasForRoutes(sorted, rootDir);\n schemaRegistry.loadManifest(manifest);\n console.log(`- Schema extracted: ${manifest.size} file(s)`);\n }\n\n // 生成类型文件(仅 dev 启动时)\n if (!isProd && args.types) {\n const typesPath = path.resolve(rootDir, args.types);\n await generateTypes(sorted, rootDir, typesPath);\n console.log(`- Types generated: ${typesPath}`);\n }\n\n // 自定义业务配置(排除 FaapiConfig 内置 key)\n const pluginConfig = config\n ? Object.fromEntries(Object.entries(config).filter(([k]) => !isFaapiConfigKey(k)))\n : {};\n\n const server = await startServer({\n port: args.port,\n routes: sorted,\n rootDir,\n cors: config?.cors ?? args.cors,\n staticDir: config?.staticDir ?? args.staticDir,\n responseFormat: config?.responseFormat,\n errorFormat: config?.errorFormat,\n onError: config?.lifecycle?.onError,\n config: config ?? undefined,\n wsRoutes,\n middlewares: config?.middlewares,\n injectors: config?.injectors,\n // beforeListen:加载插件并应用 handler 包装(在 server.listen 之前)\n beforeListen: async (server) => {\n const { handlerWrappers, upgradeWrappers } = await loadPlugins(config?.plugins, {\n rootDir,\n routes: sorted,\n server,\n config: pluginConfig,\n });\n applyPluginWrappers(server, handlerWrappers, upgradeWrappers);\n },\n });\n\n // 执行 onReady 生命周期钩子\n if (config?.lifecycle?.onReady) {\n await config.lifecycle.onReady({\n rootDir,\n routes: sorted,\n server,\n });\n console.log('- onReady hook executed');\n }\n\n // 注册 onClose 生命周期钩子\n if (config?.lifecycle?.onClose) {\n const onClose = config.lifecycle.onClose;\n const gracefulShutdown = async (signal: string) => {\n console.log(`\\n- Received ${signal}, running onClose hook...`);\n await onClose({ rootDir, routes: sorted, server });\n process.exit(0);\n };\n process.on('SIGTERM', () => void gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => void gracefulShutdown('SIGINT'));\n }\n\n // 启动 watch 模式(仅 dev)\n if (!isProd) {\n startWatcher({\n rootDir,\n patterns: args.patterns,\n appDir: args.appDir,\n server,\n port: args.port,\n cors: args.cors,\n staticDir: args.staticDir,\n types: args.types,\n });\n }\n}\n\n/** FaapiConfig 的内置 key 集合(排除自定义业务配置) */\nconst FAAPI_CONFIG_KEYS = new Set([\n 'port',\n 'staticDir',\n 'cors',\n 'responseFormat',\n 'errorFormat',\n 'lifecycle',\n 'middlewares',\n 'injectors',\n 'extendContext',\n 'plugins',\n]);\n\nfunction isFaapiConfigKey(key: string): boolean {\n return FAAPI_CONFIG_KEYS.has(key);\n}\n\n/**\n * 重写 manifest 的 filePath key,使 prd 运行时能匹配 validateInput 传入的路径\n *\n * build 时 key 形式:/abs/root/api/health/handler.ts(绝对路径 + .ts)\n * 运行时 validateInput 传入:/abs/root/dist/api/health/handler.js(绝对路径 + .js + dist 前缀)\n *\n * 转换:/abs/root/api/health/handler.ts → /abs/root/dist/api/health/handler.js\n */\nfunction remapManifestKeys(manifest: SchemaManifest, rootDir: string): SchemaManifest {\n const remapped: SchemaManifest = new Map();\n const rootPrefix = rootDir + path.sep;\n for (const [filePath, fileSchemas] of manifest) {\n // 绝对路径 → 相对路径(api/health/handler.ts)\n let rel = filePath;\n if (filePath.startsWith(rootPrefix)) {\n rel = filePath.slice(rootPrefix.length);\n } else if (filePath.startsWith(rootDir)) {\n rel = filePath.slice(rootDir.length).replace(/^[/\\\\]/, '');\n }\n // .ts → .js,加 dist/ 前缀,再转回绝对路径(与 createServer 里的 absoluteFilePath 一致)\n const prodRel = `dist/${rel.replace(/\\.ts$/, '.js')}`;\n const prodAbs = path.resolve(rootDir, prodRel);\n remapped.set(prodAbs, fileSchemas);\n }\n return remapped;\n}\n","#!/usr/bin/env node\n\n/**\n * 检测 tsx 是否已通过 `node --import tsx` 预加载\n * 已预加载时跳过 register:register('tsx/esm') 与 --import tsx 同存会触发 Node 24 ERR_REQUIRE_CYCLE_MODULE\n */\nfunction isTsxPreloaded(): boolean {\n return (\n process.execArgv.some((arg) => arg.includes('tsx')) ||\n (process.env.NODE_OPTIONS ?? '').includes('tsx')\n );\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n\n // 顶层命令分发:build 独立分支,不进 startCommand\n // dev/start 都走 startCommand,由 mode 区分\n const firstArg = argv.find((a) => !a.startsWith('-'));\n if (firstArg === 'build') {\n const { parseBuildArgs, buildCommand } = await import('./buildCommand.js');\n const options = parseBuildArgs(argv.filter((a) => a !== 'build'));\n await buildCommand(options);\n return;\n }\n\n // dev 模式(非 start)需要 tsx 来加载用户 .ts 路由文件\n // start 模式加载的是 dist 下的 .js,无需 tsx\n const isStartMode = firstArg === 'start';\n if (!isStartMode && !isTsxPreloaded()) {\n // tsx/esm/api 的 register() 内部自动构造 MessageChannel 传给 module.register,\n // 满足 tsx 4.22+ initialize 钩子要求\n try {\n const { register } = await import('tsx/esm/api');\n register();\n } catch (err) {\n console.error('[faapi] tsx 加载失败,请确认已安装 tsx:', err);\n process.exit(1);\n }\n }\n\n // tsx 注册(如需)完成后,再加载 startCommand(它可能 import 用户 .ts 路由)\n const { startCommand } = await import('./startCommand.js');\n await startCommand(argv);\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","ts","ts","fs","path","ts","path","ts","ts","path","fs","path","fs","path","path","fs","fg","cors","path","params","url","path","text","headers","body","resolve","path","fs","path","Readable","relative","stat","body","path","resolve","Readable","path","toResponse","cors","resolve","Readable","path","basename","stat","lstat","path","main","rawEmitter","listener","basename","dirname","newStats","closer","resolve","realpath","stats","stat","readdir","EventEmitter","sysPath","relative","normalizePath","path","DOUBLE_SLASH_RE","testString","init_esm","stats","now","init_esm","path","fs","pathToFileURL","fs","path","pathToFileURL","server","parseBuildArgs","buildCommand","startCommand"]}
|
|
1
|
+
{"version":3,"sources":["../../src/router/constants.ts","../../src/utils/normalizePath.ts","../../src/router/parseRouteFile.ts","../../src/utils/importWithCacheBust.ts","../../src/middleware/loadMiddlewares.ts","../../src/router/scanRoutes.ts","../../src/router/sortRoutes.ts","../../src/router/detectRouteConflicts.ts","../../src/injection/resolveInjection.ts","../../src/injection/analyzeInjection.ts","../../src/runtime/inputType.ts","../../src/cli/generateTypes.ts","../../src/ast/resolveTypeNode.ts","../../src/ast/generateValidatorCode.ts","../../src/validator/schemaRegistry.ts","../../src/ast/createProgram.ts","../../src/ast/extractHandlerTypes.ts","../../src/validator/schemaName.ts","../../src/cli/collectRouteSchemaSources.ts","../../src/cli/generateSchema.ts","../../src/cli/generateRoutes.ts","../../src/utils/readTsconfig.ts","../../src/utils/resolveAlias.ts","../../src/cli/compileRoutes.ts","../../src/cli/buildCommand.ts","../../../../node_modules/.pnpm/cac@6.7.14/node_modules/cac/dist/index.mjs","../../src/cli/normalizePatterns.ts","../../src/cli/parseArgs.ts","../../src/router/matchRoute.ts","../../src/loader/resolveExports.ts","../../src/loader/validateRouteModule.ts","../../src/loader/loadRouteModule.ts","../../src/runtime/sse.ts","../../src/runtime/createContext.ts","../../src/utils/queryToObject.ts","../../src/utils/parseJsonBody.ts","../../src/utils/parseMultipart.ts","../../src/errors/FaapiError.ts","../../src/errors/httpErrors.ts","../../src/runtime/resolveInput.ts","../../src/utils/isPlainObject.ts","../../src/response/toResponse.ts","../../src/injection/injectParams.ts","../../src/runtime/invokeHandler.ts","../../src/response/sendNodeResponse.ts","../../src/validator/coerceInput.ts","../../src/validator/validateInput.ts","../../src/utils/getClientIp.ts","../../src/middleware/cors.ts","../../src/server/serveStatic.ts","../../src/errors/formatErrorResponse.ts","../../src/server/serverUtils.ts","../../src/runtime/wsHandler.ts","../../src/server/handleWsUpgrade.ts","../../src/server/createServer.ts","../../src/server/startServer.ts","../../../../node_modules/.pnpm/readdirp@4.1.2/node_modules/readdirp/esm/index.js","../../../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/handler.js","../../../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js","../../src/cli/watcher.ts","../../src/config/loadConfig.ts","../../src/cli/loadPlugins.ts","../../src/cli/startCommand.ts","../../src/cli/index.ts"],"sourcesContent":["export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const;\n\nexport type HttpMethod = (typeof HTTP_METHODS)[number];\n\nconst HTTP_METHOD_SET: ReadonlySet<string> = new Set(HTTP_METHODS);\n\nexport function isHttpMethod(value: string): value is HttpMethod {\n return HTTP_METHOD_SET.has(value);\n}\n","/**\n * 标准化路径:\n * - 将反斜杠替换为正斜杠\n * - 去除重复的斜杠\n * - 去除尾部斜杠\n * - 确保以 / 开头(如果非空)\n */\nexport function normalizePath(path: string): string {\n if (!path) return '';\n\n // 将反斜杠替换为正斜杠\n let result = path.replace(/\\\\/g, '/');\n\n // 去除重复的斜杠\n result = result.replace(/\\/+/g, '/');\n\n // 去除尾部斜杠\n result = result.replace(/\\/+$/, '');\n\n // 确保以 / 开头(如果非空)\n if (result && !result.startsWith('/')) {\n result = '/' + result;\n }\n\n return result;\n}\n","import { normalizePath } from '../utils/normalizePath';\n\n/**\n * 将 [name] 格式的目录名转换为 :name 格式\n * '[id]' -> ':id'\n * '[...slug]' -> ':...slug'\n * 'login' -> 'login'\n */\nexport function dynamicSegmentToParam(segment: string): string {\n const match = segment.match(/^\\[(.+)\\]$/);\n if (match) {\n return ':' + match[1];\n }\n return segment;\n}\n\n/**\n * 从 URL 路径中提取动态参数名\n * '/user/:id' -> ['id']\n * '/auth/login' -> []\n * '/user/:id/posts/:postId' -> ['id', 'postId']\n * '/shop/:...slug' -> ['slug']\n */\nexport function extractParamNames(urlPath: string): string[] {\n const params: string[] = [];\n const segments = urlPath.split('/');\n for (const segment of segments) {\n if (segment.startsWith(':...')) {\n // catch-all 参数::...slug -> slug\n params.push(segment.slice(4));\n } else if (segment.startsWith(':')) {\n params.push(segment.slice(1));\n }\n }\n return params;\n}\n\n/**\n * 判断路径段是否为 catch-all 路由\n * '[...slug]' -> true\n * '[id]' -> false\n */\nexport function isCatchAllSegment(segment: string): boolean {\n return /^\\[\\.\\.\\..+\\]$/.test(segment);\n}\n\n/**\n * 判断路径段是否为路由分组\n * '(marketing)' -> true\n * 'login' -> false\n */\nexport function isRouteGroup(segment: string): boolean {\n return /^\\(.+\\)$/.test(segment);\n}\n\n/**\n * 将路由文件路径转换为 URL 路径\n * 输入: 相对于项目根目录的文件路径,如 'api/auth/login/handler.ts'\n * 输出: URL 路径,如 '/api/auth/login'\n *\n * 规则:\n * - 去掉 appDir 前缀(默认 '.',即项目根目录,不剥离)\n * - 去掉文件名(handler.ts 等)\n * - 将 [id] 转换为 :id\n * - 忽略路由分组 (groupName) — 不影响 URL\n * - 标准化路径\n *\n * 说明:CLI 默认扫描 src/api/(appDir='src'),底层 API 默认 '.'。\n * 无论 appDir 是 'src' 还是 '.',api/ 前缀都保留在 URL 中,因此 URL 始终带 /api 前缀。\n */\nexport function filePathToUrlPath(filePath: string, appDir: string = '.'): string {\n // 去掉 appDir 前缀(appDir='.' 时不剥离)\n const withoutPrefix = filePath.startsWith(appDir + '/')\n ? filePath.slice(appDir.length + 1)\n : filePath;\n\n // 去掉文件名(最后一个路径段)\n const lastSlashIndex = withoutPrefix.lastIndexOf('/');\n const dirPath = lastSlashIndex === -1 ? '' : withoutPrefix.slice(0, lastSlashIndex);\n\n if (!dirPath) {\n return '';\n }\n\n // 将每个路径段中的 [name] 转换为 :name,忽略路由分组 (name)\n const segments = dirPath\n .split('/')\n .filter((s) => !isRouteGroup(s)) // 过滤掉路由分组\n .map(dynamicSegmentToParam);\n\n // 拼接并标准化路径\n return normalizePath(segments.join('/'));\n}\n","import { pathToFileURL } from 'node:url';\n\n/**\n * 获取当前模块加载时间戳(watch 模式下用于绕过 ESM 缓存)\n *\n * 由 startCommand 在 watch 模式下设置到 globalThis.__FAAPI_LOAD_TS__。\n */\nexport function getLoadTimestamp(): number | undefined {\n return (globalThis as Record<string, unknown>).__FAAPI_LOAD_TS__ as number | undefined;\n}\n\n/**\n * 动态 import 文件,watch 模式下拼接时间戳绕过 ESM 缓存\n *\n * @param filePath 文件绝对路径\n * @returns 模块导出对象\n */\nexport async function importWithCacheBust(filePath: string): Promise<Record<string, unknown>> {\n let url = pathToFileURL(filePath).href;\n const ts = getLoadTimestamp();\n if (ts !== undefined) {\n url += `?t=${ts}`;\n }\n return (await import(url)) as Record<string, unknown>;\n}\n","import type { FaapiMiddleware } from './middlewareTypes';\nimport type { InjectorMap } from './injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\n/**\n * 中间件 + 注入器加载结果\n */\nexport interface LoadedMiddlewareBundle {\n middlewares: FaapiMiddleware[];\n injectors: InjectorMap;\n}\n\n/**\n * 中间件缓存,key 为 middlewares.ts 的绝对路径\n */\nconst middlewareCache = new Map<string, LoadedMiddlewareBundle>();\n\n/**\n * 失效所有中间件缓存(watch 模式下文件变化时调用)\n */\nexport function invalidateMiddlewareCache(): void {\n middlewareCache.clear();\n}\n\n/**\n * 从缓存中读取中间件 bundle(未命中返回 undefined)\n */\nexport function getCachedMiddlewares(absPath: string): LoadedMiddlewareBundle | undefined {\n return middlewareCache.get(absPath);\n}\n\n/**\n * 写入中间件缓存\n */\nexport function setCachedMiddlewares(absPath: string, bundle: LoadedMiddlewareBundle): void {\n middlewareCache.set(absPath, bundle);\n}\n\n/**\n * 从绝对路径加载 middlewares.ts 并校验\n *\n * 文件可导出:\n * - `default`:中间件数组(洋葱模型,每项为 async 函数)\n * - `injectors`:注入器映射表(按参数名匹配 handler 参数)\n *\n * 两者都是可选的,但至少要有一个。\n */\nexport async function loadMiddlewaresFile(filePath: string): Promise<LoadedMiddlewareBundle> {\n try {\n const module = await importWithCacheBust(filePath);\n\n // 加载中间件数组\n const middlewares = (module.default ?? module.middlewares ?? []) as unknown[];\n if (!Array.isArray(middlewares)) {\n console.warn(`[faapi] middlewares.ts 应导出数组,已忽略: ${filePath}`);\n return { middlewares: [], injectors: {} };\n }\n\n const validMiddlewares = middlewares.filter((m: unknown) => {\n if (typeof m !== 'function') {\n console.warn(`[faapi] 无效的中间件项(应为函数),已忽略: ${typeof m}`);\n return false;\n }\n return true;\n }) as FaapiMiddleware[];\n\n // 加载注入器映射表(可选命名导出)\n const injectors = (module.injectors ?? {}) as InjectorMap;\n if (typeof injectors !== 'object' || injectors === null) {\n console.warn(`[faapi] injectors 应导出对象,已忽略: ${filePath}`);\n return { middlewares: validMiddlewares, injectors: {} };\n }\n\n // 校验注入器:每个值必须是函数\n const validInjectors: InjectorMap = {};\n for (const [name, injector] of Object.entries(injectors)) {\n if (typeof injector !== 'function') {\n console.warn(`[faapi] 注入器 ${name} 应为函数,已忽略`);\n continue;\n }\n validInjectors[name] = injector;\n }\n\n return { middlewares: validMiddlewares, injectors: validInjectors };\n } catch {\n return { middlewares: [], injectors: {} };\n }\n}\n","import fg from 'fast-glob';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport type { RouteManifest, WsRouteManifest } from './routeTypes';\nimport { isHttpMethod, type HttpMethod } from './constants';\nimport { filePathToUrlPath, extractParamNames, isCatchAllSegment } from './parseRouteFile';\nimport {\n loadMiddlewaresFile,\n getCachedMiddlewares,\n setCachedMiddlewares,\n type LoadedMiddlewareBundle,\n} from '../middleware/loadMiddlewares';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\n/**\n * 把源码绝对路径转为产物绝对路径(用于 import 产物 .js)\n *\n * dev/build 模式下 scanRoutes 不再 import 源码 .ts(无需 tsx),\n * 而是先编译到 prodDir(.faapi/dev 或 dist),再 import 产物 .js。\n *\n * @param sourceAbsPath 源码绝对路径(如 /root/src/api/hello/handler.ts)\n * @param rootDir 项目根目录\n * @param prodDir 产物目录(dist 或 .faapi/dev)\n */\nfunction toProdAbsPath(sourceAbsPath: string, rootDir: string, prodDir: string): string {\n const rel = path.relative(rootDir, sourceAbsPath);\n const prodRel = `${prodDir}/${rel.replace(/\\.ts$/, '.js')}`;\n return path.resolve(rootDir, prodRel);\n}\n\n/**\n * 从路由文件所在目录向上逐级查找 middlewares.ts(源码),\n * 按从根到路由目录的顺序合并中间件和注入器(父级在前,子级在后)。\n *\n * 若传入 prodDir,加载产物 middlewares.js(已编译);否则加载源码 middlewares.ts。\n *\n * 子级中间件包裹父级(洋葱模型下后注册的先执行 after);\n * 子级注入器覆盖父级同名注入器。\n */\nasync function findMergedMiddlewares(\n routeFilePath: string,\n rootDir: string,\n prodDir?: string,\n): Promise<{ middlewares: FaapiMiddleware[]; injectors: InjectorMap } | undefined> {\n const routeDir = path.dirname(routeFilePath);\n const resolvedRoot = path.resolve(rootDir);\n\n // 收集从根到路由目录的所有 middlewares 路径\n // prodDir 传入时查找产物 middlewares.js;否则查找源码 middlewares.ts(兼容旧路径)\n const mwPaths: string[] = [];\n let currentDir = path.resolve(rootDir, routeDir);\n while (true) {\n if (prodDir) {\n // 新模式:查找产物 middlewares.js\n const mwPath = path.join(currentDir, 'middlewares.js');\n const absMwPath = path.resolve(rootDir, mwPath);\n // 产物路径:把源码路径转为产物路径\n const prodAbsMwPath = toProdAbsPath(absMwPath, rootDir, prodDir);\n if (fs.existsSync(prodAbsMwPath)) {\n mwPaths.push(prodAbsMwPath);\n }\n } else {\n // 旧模式:查找源码 middlewares.ts/.js\n for (const ext of ['.ts', '.js']) {\n const mwPath = path.join(currentDir, `middlewares${ext}`);\n const absMwPath = path.resolve(rootDir, mwPath);\n if (fs.existsSync(absMwPath)) {\n mwPaths.push(absMwPath);\n break;\n }\n }\n }\n if (currentDir === resolvedRoot) break;\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n\n if (mwPaths.length === 0) return undefined;\n\n // 从根到路由目录逐级加载(mwPaths 是从路由目录向上收集的,需反转)\n mwPaths.reverse();\n\n const mergedMiddlewares: FaapiMiddleware[] = [];\n const mergedInjectors: InjectorMap = {};\n\n for (const absMwPath of mwPaths) {\n let bundle: LoadedMiddlewareBundle | undefined = getCachedMiddlewares(absMwPath);\n if (bundle === undefined) {\n bundle = await loadMiddlewaresFile(absMwPath);\n setCachedMiddlewares(absMwPath, bundle);\n }\n // 子级中间件追加在父级之后(洋葱模型:后注册的中间件在内层)\n mergedMiddlewares.push(...bundle.middlewares);\n // 子级注入器覆盖父级同名注入器\n for (const [name, injector] of Object.entries(bundle.injectors)) {\n mergedInjectors[name] = injector;\n }\n }\n\n if (mergedMiddlewares.length === 0 && Object.keys(mergedInjectors).length === 0) {\n return undefined;\n }\n\n return { middlewares: mergedMiddlewares, injectors: mergedInjectors };\n}\n\n/**\n * 从 handler 模块中提取导出的 HTTP 方法名\n *\n * @param absPath handler 文件路径(产物 .js 或源码 .ts,取决于调用方)\n */\nexport async function extractMethodsFromHandler(absPath: string): Promise<HttpMethod[]> {\n try {\n const module = await importWithCacheBust(absPath);\n const methods: HttpMethod[] = [];\n for (const key of Object.keys(module)) {\n if (isHttpMethod(key) && typeof module[key] === 'function') {\n methods.push(key);\n }\n }\n return methods;\n } catch (err) {\n // 模块加载失败时输出警告,避免静默吞没错误\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[faapi] 加载路由文件失败 ${absPath}: ${reason}`);\n return [];\n }\n}\n\n/**\n * 检测 handler 模块是否导出 WS 函数\n *\n * WS 导出与 HTTP 方法导出(GET/POST 等)同级,导出名必须为 `WS`。\n *\n * @param absPath handler 文件路径(产物 .js 或源码 .ts,取决于调用方)\n */\nexport async function hasWsExport(absPath: string): Promise<boolean> {\n try {\n const module = await importWithCacheBust(absPath);\n return typeof module['WS'] === 'function';\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[faapi] 加载路由文件失败(WS 检测)${absPath}: ${reason}`);\n return false;\n }\n}\n\n/**\n * 扫描 api 目录,同时生成 HTTP 路由清单和 WebSocket 路由清单\n *\n * 路由文件格式:handler.ts,导出 HTTP 方法名作为 handler,也可导出 `WS` 函数声明 WebSocket 路由\n * ```ts\n * // api/user/handler.ts\n * export function GET() { return { list: [] } }\n * export function POST(body: any) { return { created: true } }\n *\n * // WebSocket 路由:导出 WS 函数\n * export function WS(ctx: WsContext) {\n * return { onMessage(ws, msg) { ws.send(`echo: ${msg}`) } };\n * }\n * ```\n * 一个 handler.ts 可同时导出 HTTP 方法(GET/POST...)和 WS 函数,\n * 分别生成 HTTP RouteRecord 和 WsRouteRecord。\n *\n * @param rootDir 项目根目录\n * @param patterns glob patterns(源码 .ts 路径,如 src/api 下所有 .ts)\n * @param appDir app 目录前缀,默认 '.'(项目根目录);CLI 层默认 'src'\n * @param prodDir 产物目录(dist 或 .faapi/dev)。传入时 import 产物 .js(不依赖 tsx);\n * 不传时 import 源码 .ts(旧模式,需要 tsx)。\n */\nexport async function scanRoutes(\n rootDir: string,\n patterns: string[],\n appDir?: string,\n prodDir?: string,\n): Promise<{ routes: RouteManifest; wsRoutes: WsRouteManifest }> {\n const dir = appDir ?? '.';\n\n const files = await fg(patterns, {\n cwd: rootDir,\n onlyFiles: true,\n absolute: false,\n });\n\n const routes: RouteManifest = [];\n const wsRoutes: WsRouteManifest = [];\n\n for (const file of files) {\n const normalizedFile = file.replace(/\\\\/g, '/');\n const fileName = normalizedFile.split('/').pop()!;\n\n // 处理 handler.{ts,js} — API 路由 + WebSocket 路由\n // dev/build 模式扫源码 .ts(prodDir 传入),start 模式扫产物 .js(由 hydrateRoutes 处理)\n if (fileName === 'handler.ts' || fileName === 'handler.js') {\n const absPath = path.resolve(rootDir, normalizedFile);\n // prodDir 传入时 import 产物 .js;否则 import 源码 .ts\n const importPath = prodDir ? toProdAbsPath(absPath, rootDir, prodDir) : absPath;\n const urlPath = filePathToUrlPath(normalizedFile, dir);\n const paramNames = extractParamNames(urlPath);\n const isDynamic = paramNames.length > 0;\n const isCatchAll = normalizedFile.split('/').some(isCatchAllSegment);\n const middlewareBundle = await findMergedMiddlewares(normalizedFile, rootDir, prodDir);\n\n // HTTP 方法导出\n const methods = await extractMethodsFromHandler(importPath);\n for (const method of methods) {\n routes.push({\n method,\n urlPath,\n filePath: normalizedFile,\n paramNames,\n isDynamic,\n isCatchAll: isCatchAll || undefined,\n middlewares: middlewareBundle?.middlewares,\n injectors: middlewareBundle?.injectors,\n });\n }\n\n // WS 导出\n const hasWs = await hasWsExport(importPath);\n if (hasWs) {\n wsRoutes.push({\n urlPath,\n filePath: normalizedFile,\n paramNames,\n isDynamic,\n isCatchAll: isCatchAll || undefined,\n middlewares: middlewareBundle?.middlewares,\n injectors: middlewareBundle?.injectors,\n });\n }\n continue;\n }\n }\n\n return { routes, wsRoutes };\n}\n","import type { RouteManifest } from './routeTypes';\n\n/**\n * 路由排序规则:\n * 1. 静态路由优先于动态路由\n * 2. 动态路由优先于 catch-all 路由\n * 3. 路径段数少的优先\n * 4. 字母序排列\n */\nexport function sortRoutes(routes: RouteManifest): RouteManifest {\n return [...routes].sort((a, b) => {\n // 1. 静态路由优先于动态路由\n if (a.isDynamic !== b.isDynamic) {\n return a.isDynamic ? 1 : -1;\n }\n\n // 2. catch-all 路由优先级最低(排在所有动态路由之后)\n if (a.isCatchAll !== b.isCatchAll) {\n return a.isCatchAll ? 1 : -1;\n }\n\n // 3. 路径段数少的优先\n const aSegments = a.urlPath.split('/').filter(Boolean).length;\n const bSegments = b.urlPath.split('/').filter(Boolean).length;\n if (aSegments !== bSegments) {\n return aSegments - bSegments;\n }\n\n // 4. 字母序排列\n return a.urlPath.localeCompare(b.urlPath);\n });\n}\n","import type { RouteManifest } from './routeTypes';\n\nexport interface RouteConflict {\n method: string;\n urlPath: string;\n files: string[];\n}\n\n/**\n * 检测路由冲突(相同 method + urlPath 的多个文件)\n */\nexport function detectRouteConflicts(routes: RouteManifest): RouteConflict[] {\n const map = new Map<string, RouteConflict>();\n\n for (const route of routes) {\n const key = `${route.method} ${route.urlPath}`;\n const existing = map.get(key);\n if (existing) {\n existing.files.push(route.filePath);\n } else {\n map.set(key, {\n method: route.method,\n urlPath: route.urlPath,\n files: [route.filePath],\n });\n }\n }\n\n // 只返回有冲突的(文件数 > 1)\n const conflicts: RouteConflict[] = [];\n for (const conflict of map.values()) {\n if (conflict.files.length > 1) {\n conflicts.push(conflict);\n }\n }\n\n return conflicts;\n}\n","import ts from 'typescript';\n\n/**\n * 参数注入类型\n */\nexport type InjectionType =\n | 'query'\n | 'body'\n | 'headers'\n | 'params'\n | 'context'\n | 'cookies'\n | 'ip'\n | 'files'\n | 'fields'\n | 'unknown';\n\n/**\n * 注入项信息\n */\nexport interface InjectionItem {\n name: string; // 参数名\n type: InjectionType; // 注入类型\n hasType: boolean; // 是否有类型标注(运行时类型已擦除,始终为 false)\n}\n\n/**\n * 参数名到注入类型的映射(单一来源,构建期和运行时共用)\n */\nexport const PARAM_TYPE_MAP: Record<string, InjectionType> = {\n query: 'query',\n body: 'body',\n headers: 'headers',\n params: 'params',\n context: 'context',\n ctx: 'context', // 别名\n cookies: 'cookies',\n ip: 'ip',\n files: 'files',\n fields: 'fields',\n};\n\n/**\n * 分析函数参数,决定需要注入什么内容\n *\n * 使用 TypeScript AST 解析 fn.toString() 的结果,\n * 正确处理解构参数、默认值、rest 参数等情况。\n *\n * 注意:运行时类型信息已被擦除,hasType 始终为 false。\n */\nexport function resolveInjection(fn: (...args: unknown[]) => unknown): InjectionItem[] {\n const fnStr = fn.toString();\n const params = extractParamsWithAst(fnStr);\n\n return params.map((param) => {\n const type = PARAM_TYPE_MAP[param.name] || 'unknown';\n return {\n name: param.name,\n type,\n hasType: false, // 运行时类型已擦除\n };\n });\n}\n\n/**\n * 使用 TypeScript AST 从函数字符串中提取参数名\n *\n * 相比正则解析,AST 能正确处理:\n * - 解构参数 `function GET({ page, size })` → page, size\n * - 默认值 `function GET(query = {})` → query\n * - rest 参数 `function GET(...args)` → args\n * - 含逗号的泛型(类型擦除后不存在该问题)\n */\nfunction extractParamsWithAst(fnStr: string): Array<{ name: string }> {\n // 包装成模块,让 TS 能解析\n const sourceFile = ts.createSourceFile(\n '__faapi_injection__.ts',\n fnStr,\n ts.ScriptTarget.Latest,\n true,\n );\n\n const paramNames: string[] = [];\n\n function visit(node: ts.Node): void {\n // 函数声明:function GET(query) {}\n if (ts.isFunctionDeclaration(node) && node.parameters.length > 0) {\n for (const param of node.parameters) {\n extractParamName(param, paramNames);\n }\n return;\n }\n\n // 箭头函数 / 函数表达式:(query) => {} 或 function(query) {}\n if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && node.parameters.length > 0) {\n for (const param of node.parameters) {\n extractParamName(param, paramNames);\n }\n return;\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n\n return paramNames.map((name) => ({ name }));\n}\n\n/**\n * 从单个参数节点提取参数名\n *\n * 支持的参数形式:\n * - 标识符:query → query\n * - 解构对象:{ page, size } → page, size(每个属性都作为一个注入项)\n * - 解构数组:[a, b] → a, b\n * - rest 参数:...args → args\n * - 默认值:query = {} → query\n */\nfunction extractParamName(param: ts.ParameterDeclaration, names: string[]): void {\n const name = param.name;\n\n // 标识符:query\n if (ts.isIdentifier(name)) {\n names.push(name.text);\n return;\n }\n\n // 解构对象:{ page, size }\n if (ts.isObjectBindingPattern(name)) {\n for (const element of name.elements) {\n if (ts.isBindingElement(element)) {\n const elemName = element.name;\n if (ts.isIdentifier(elemName)) {\n names.push(elemName.text);\n }\n }\n }\n return;\n }\n\n // 解构数组:[a, b]\n if (ts.isArrayBindingPattern(name)) {\n for (const element of name.elements) {\n if (element && ts.isBindingElement(element)) {\n const elemName = element.name;\n if (ts.isIdentifier(elemName)) {\n names.push(elemName.text);\n }\n }\n }\n return;\n }\n}\n","import ts from 'typescript';\nimport type { InjectionType } from './resolveInjection';\nimport { PARAM_TYPE_MAP } from './resolveInjection';\n\n/**\n * 参数元数据\n */\nexport interface ParamMeta {\n name: string; // 参数名\n type: InjectionType; // 注入类型\n typeName?: string; // 引用类型名(如 'Query')\n schema?: PropertyInfo[]; // 类型结构(内联类型时)\n}\n\n/**\n * 属性信息\n */\nexport interface PropertyInfo {\n name: string;\n type: string;\n optional: boolean;\n}\n\n/**\n * 注入元数据\n */\nexport interface InjectionMeta {\n params: ParamMeta[];\n}\n\n/**\n * AST 分析 handler 函数,提取参数注入元数据\n */\nexport function analyzeInjection(code: string, functionName: string): InjectionMeta {\n const sourceFile = ts.createSourceFile('temp.ts', code, ts.ScriptTarget.Latest, true);\n\n const params: ParamMeta[] = [];\n\n // 遍历 AST 查找目标函数\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isFunctionDeclaration(node) && node.name?.text === functionName) {\n // 分析参数\n for (const param of node.parameters) {\n const paramMeta = analyzeParam(param, sourceFile);\n params.push(paramMeta);\n }\n }\n });\n\n return { params };\n}\n\n/**\n * 分析单个参数\n */\nfunction analyzeParam(param: ts.ParameterDeclaration, sourceFile: ts.SourceFile): ParamMeta {\n const name = param.name.getText(sourceFile);\n const type = PARAM_TYPE_MAP[name] || 'unknown';\n\n const result: ParamMeta = { name, type };\n\n // 分析类型\n if (param.type) {\n if (ts.isTypeReferenceNode(param.type)) {\n // 引用类型:Query, Body 等\n result.typeName = param.type.typeName.getText(sourceFile);\n } else if (ts.isTypeLiteralNode(param.type)) {\n // 内联类型:{ page: number }\n result.schema = extractSchema(param.type, sourceFile);\n }\n }\n\n return result;\n}\n\n/**\n * 从类型字面量提取 schema\n */\nfunction extractSchema(typeNode: ts.TypeLiteralNode, sourceFile: ts.SourceFile): PropertyInfo[] {\n const schema: PropertyInfo[] = [];\n\n for (const member of typeNode.members) {\n if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {\n const propName = member.name.text;\n const optional = !!member.questionToken;\n const propType = member.type?.getText(sourceFile) || 'unknown';\n\n schema.push({\n name: propName,\n type: propType,\n optional,\n });\n }\n }\n\n return schema;\n}\n","/**\n * 根据 HTTP 方法判断主输入类型\n *\n * - GET / DELETE / HEAD:query(URL 查询参数)\n * - POST / PUT / PATCH:body(请求体)\n *\n * 注意:所有方法都可能同时有 query 和 body,\n * 这里返回的是\"主输入\"(用于校验和注入)。\n * DELETE 请求也支持 body(见 resolveInput.ts)。\n */\nexport function getInputTypeForMethod(method: string): 'query' | 'body' {\n const upper = method.toUpperCase();\n if (upper === 'GET' || upper === 'DELETE' || upper === 'HEAD') {\n return 'query';\n }\n return 'body';\n}\n\n/**\n * 判断方法是否有请求体\n *\n * POST / PUT / PATCH / DELETE 可能有 body\n * GET / HEAD 不应该有 body\n */\nexport function hasBody(method: string): boolean {\n const upper = method.toUpperCase();\n return upper === 'POST' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE';\n}\n","import type { RouteManifest } from '../router/routeTypes';\nimport { analyzeInjection } from '../injection/analyzeInjection';\nimport { getInputTypeForMethod } from '../runtime/inputType';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\ninterface RouteTypeInfo {\n method: string;\n urlPath: string;\n inputType: string; // TypeScript type string for input\n outputType: string; // TypeScript type string for output (unknown if can't infer)\n filePath: string;\n}\n\n/**\n * 从路由清单生成类型定义文件\n */\nexport async function generateTypes(\n routes: RouteManifest,\n rootDir: string,\n outputPath: string,\n): Promise<void> {\n const routeTypes: RouteTypeInfo[] = [];\n\n for (const route of routes) {\n const absolutePath = path.resolve(rootDir, route.filePath);\n let code: string;\n try {\n code = await fs.readFile(absolutePath, 'utf-8');\n } catch {\n continue;\n }\n\n const meta = analyzeInjection(code, route.method);\n const inputType = buildInputType(meta, route.method);\n\n routeTypes.push({\n method: route.method,\n urlPath: route.urlPath,\n inputType,\n outputType: 'unknown',\n filePath: route.filePath,\n });\n }\n\n const content = buildTypeFile(routeTypes);\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, content, 'utf-8');\n}\n\nfunction buildInputType(\n meta: { params: Array<{ name: string; type: string; typeName?: string }> },\n method: string,\n): string {\n if (meta.params.length === 0) return 'void';\n\n const source = getInputTypeForMethod(method);\n const relevantParams = meta.params.filter((p) => p.type === source);\n\n if (relevantParams.length === 0) return 'void';\n\n // If there's a type name, reference it\n if (relevantParams.length === 1 && relevantParams[0].typeName) {\n return relevantParams[0].typeName;\n }\n\n return 'Record<string, unknown>';\n}\n\nfunction buildTypeFile(routes: RouteTypeInfo[]): string {\n const lines: string[] = [\n '// Auto-generated by faapi — do not edit',\n '// eslint-disable-next-line @typescript-eslint/no-namespace',\n 'export namespace FaapiRoutes {',\n '',\n ];\n\n for (const route of routes) {\n const key = routeKey(route.method, route.urlPath);\n lines.push(` interface ${key} {`);\n lines.push(` method: '${route.method}';`);\n lines.push(` path: '${route.urlPath}';`);\n lines.push(` input: ${route.inputType};`);\n lines.push(` output: ${route.outputType};`);\n lines.push(' }');\n lines.push('');\n }\n\n // Build route map type\n lines.push(' interface Routes {');\n for (const route of routes) {\n const key = routeKey(route.method, route.urlPath);\n lines.push(` '${route.method} ${route.urlPath}': ${key};`);\n }\n lines.push(' }');\n lines.push('}');\n lines.push('');\n\n // Generate typed client interface\n lines.push('export interface FaapiClient {');\n for (const route of routes) {\n lines.push(\n ` ${methodName(route.method)}('${route.urlPath}'${route.inputType === 'void' ? '' : ', input'}): Promise<${route.outputType}>;`,\n );\n }\n lines.push('}');\n\n return lines.join('\\n');\n}\n\nexport function routeKey(method: string, urlPath: string): string {\n const sanitized = urlPath\n .replace(/^\\//, '')\n .replace(/\\/:/g, '_')\n .replace(/\\//g, '_')\n .replace(/-/g, '_');\n return `${method}_${sanitized || 'root'}`;\n}\n\nexport function methodName(method: string): string {\n return method.toLowerCase();\n}\n","import ts from 'typescript';\n\n/**\n * Schema 提取错误\n *\n * 遇到无法解析或不支持运行时校验的类型时抛出,\n * 避免静默降级为 any 导致用户不知情。\n */\nexport class SchemaExtractionError extends Error {\n constructor(\n public readonly typeText: string,\n public readonly reason: string,\n options?: ErrorOptions,\n ) {\n super(`无法解析类型 \"${typeText}\": ${reason}`, options);\n this.name = 'SchemaExtractionError';\n }\n}\n\n/**\n * 运行时类型描述\n *\n * 用于校验器在运行时判断值的结构是否符合声明类型。\n * 相比单纯的字符串,能描述数组元素类型、嵌套对象、联合类型等。\n */\nexport type RuntimeType =\n | { kind: 'string' }\n | { kind: 'number' }\n | { kind: 'boolean' }\n | { kind: 'bigint' }\n | { kind: 'null' }\n | { kind: 'undefined' }\n | { kind: 'any' } // 不校验\n | { kind: 'unknown' } // 不校验\n | { kind: 'literal'; value: string | number | boolean } // 字面量\n | { kind: 'array'; element: RuntimeType }\n | { kind: 'tuple'; elements: TupleElement[] }\n | { kind: 'object'; properties: PropertyType[] }\n | { kind: 'union'; members: RuntimeType[] }\n | { kind: 'date' }\n | { kind: 'record'; key: RuntimeType; value: RuntimeType }\n | { kind: 'ref'; name: string }; // 命名类型引用(支持循环引用)\n\n/**\n * 元组元素类型\n *\n * - optional: 该位置元素可省略(如 `[string, number?]`)\n * - rest: 该位置是剩余元素(如 `[string, ...number[]]`),必须是数组类型,展开后逐个校验\n */\nexport interface TupleElement {\n type: RuntimeType;\n optional: boolean;\n rest: boolean;\n}\n\nexport interface PropertyType {\n name: string;\n type: RuntimeType;\n optional: boolean;\n}\n\n/**\n * 将 TypeScript 类型节点解析为运行时类型描述\n *\n * 支持的类型:\n * - 基础类型:string / number / boolean / null / undefined / any / unknown / void\n * - bigint:不支持(HTTP/JSON 不能传输),AST 提取阶段抛 SchemaExtractionError\n * - 字面量类型:'foo' / 42 / true\n * - 数组类型:T[] / Array<T>\n * - 元组类型:[string, number] / [string, number?] / [string, ...number[]](按位置校验)\n * - 对象类型:{ name: string; age?: number }\n * - 联合类型:string | null\n * - 交叉类型:A & B(按对象合并处理)\n * - 引用类型:Date / 其他 interface(递归解析)\n * - 工具类型:Record<K, V> / Partial<T>(best effort)\n * - Pick<T, K> / Omit<T, K>:K 支持字面量联合、类型别名、keyof T\n *\n * @param typeNode TypeScript 类型节点\n * @param checker 类型 checker(用于解析引用类型)\n * @param visited 防止递归循环\n */\nexport function resolveTypeNode(\n typeNode: ts.TypeNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const kind = typeNode.kind;\n\n // 基础类型\n switch (kind) {\n case ts.SyntaxKind.StringKeyword:\n return { kind: 'string' };\n case ts.SyntaxKind.NumberKeyword:\n return { kind: 'number' };\n case ts.SyntaxKind.BooleanKeyword:\n return { kind: 'boolean' };\n case ts.SyntaxKind.BigIntKeyword:\n // HTTP/JSON 不能传输 BigInt,在 AST 提取阶段就报错,避免运行时校验必然失败\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'bigint 无法通过 HTTP/JSON 传输,请改用 string 或 number',\n );\n case ts.SyntaxKind.SymbolKeyword:\n // HTTP/JSON 不能传输 Symbol\n throw new SchemaExtractionError(typeNode.getText(), 'symbol 无法通过 HTTP/JSON 传输');\n case ts.SyntaxKind.NullKeyword:\n return { kind: 'null' };\n case ts.SyntaxKind.UndefinedKeyword:\n return { kind: 'undefined' };\n case ts.SyntaxKind.UnknownKeyword:\n // unknown 是唯一允许的\"不校验\"显式声明\n return { kind: 'any' };\n case ts.SyntaxKind.AnyKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'any 不支持,请使用 unknown 表示不校验');\n case ts.SyntaxKind.VoidKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'void 不支持运行时校验');\n case ts.SyntaxKind.NeverKeyword:\n throw new SchemaExtractionError(typeNode.getText(), 'never 不支持运行时校验');\n case ts.SyntaxKind.ObjectKeyword:\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'object 不支持,请使用具体对象类型或 unknown',\n );\n }\n\n // 字面量类型\n if (ts.isLiteralTypeNode(typeNode)) {\n const literal = typeNode.literal;\n if (ts.isStringLiteral(literal)) {\n return { kind: 'literal', value: literal.text };\n }\n if (ts.isNumericLiteral(literal)) {\n return { kind: 'literal', value: Number(literal.text) };\n }\n if (literal.kind === ts.SyntaxKind.TrueKeyword) {\n return { kind: 'literal', value: true };\n }\n if (literal.kind === ts.SyntaxKind.FalseKeyword) {\n return { kind: 'literal', value: false };\n }\n if (literal.kind === ts.SyntaxKind.NullKeyword) {\n return { kind: 'null' };\n }\n throw new SchemaExtractionError(typeNode.getText(), '不支持的字面量类型');\n }\n\n // 数组类型:T[]\n if (ts.isArrayTypeNode(typeNode)) {\n return {\n kind: 'array',\n element: resolveTypeNode(typeNode.elementType, checker, visited),\n };\n }\n\n // 元组类型:[string, number] / [string, number?] / [string, ...number[]]\n if (ts.isTupleTypeNode(typeNode)) {\n const elements: TupleElement[] = typeNode.elements.map((e) => {\n // 剩余元素:...T\n if (ts.isRestTypeNode(e)) {\n const inner = resolveTypeNode(e.type, checker, visited);\n // ...T[] → 元素类型是 T 的数组元素\n if (inner.kind === 'array') {\n return { type: inner.element, optional: false, rest: true };\n }\n // ...T 但 T 不是数组(罕见,TS 通常要求 rest 是数组)\n return { type: inner, optional: false, rest: true };\n }\n // 命名元组成员:[name: string, age?: number]\n if (ts.isNamedTupleMember(e)) {\n return {\n type: resolveTypeNode(e.type, checker, visited),\n optional: !!e.questionToken,\n rest: false,\n };\n }\n // 可选元素:number?(无名称,有 ?)\n if (ts.isOptionalTypeNode(e)) {\n return {\n type: resolveTypeNode(e.type, checker, visited),\n optional: true,\n rest: false,\n };\n }\n // 普通元素\n return {\n type: resolveTypeNode(e, checker, visited),\n optional: false,\n rest: false,\n };\n });\n return { kind: 'tuple', elements };\n }\n\n // 联合类型:A | B\n if (ts.isUnionTypeNode(typeNode)) {\n const members = typeNode.types.map((t) => resolveTypeNode(t, checker, visited));\n return { kind: 'union', members };\n }\n\n // 交叉类型:A & B → 合并对象属性\n if (ts.isIntersectionTypeNode(typeNode)) {\n const properties: PropertyType[] = [];\n for (const t of typeNode.types) {\n const resolved = resolveTypeNode(t, checker, visited);\n if (resolved.kind === 'object') {\n properties.push(...resolved.properties);\n }\n }\n return { kind: 'object', properties };\n }\n\n // 内联对象类型:{ name: string; age?: number }\n if (ts.isTypeLiteralNode(typeNode)) {\n return resolveTypeLiteral(typeNode, checker, visited);\n }\n\n // keyof T — 用 checker 解析为字面量联合\n if (ts.isTypeOperatorNode(typeNode) && typeNode.operator === ts.SyntaxKind.KeyOfKeyword) {\n return resolveKeyOf(typeNode, checker);\n }\n\n // 引用类型:Date / 自定义 interface / Array<T> / Record<K,V> / Partial<T> 等\n if (ts.isTypeReferenceNode(typeNode)) {\n return resolveTypeReference(typeNode, checker, visited);\n }\n\n // 其他无法识别的语法节点\n throw new SchemaExtractionError(typeNode.getText(), '不支持的类型语法');\n}\n\n/**\n * 解析内联对象类型字面量\n */\nfunction resolveTypeLiteral(\n typeNode: ts.TypeLiteralNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const properties: PropertyType[] = [];\n\n for (const member of typeNode.members) {\n // 属性签名:name: string\n if (ts.isPropertySignature(member) && member.name) {\n const name = member.name.getText();\n const optional = !!member.questionToken;\n const type = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n properties.push({ name, type, optional });\n }\n // 索引签名:[key: string]: T → 转为 record\n if (ts.isIndexSignatureDeclaration(member)) {\n const keyType = member.parameters[0]?.type\n ? resolveTypeNode(member.parameters[0].type, checker, visited)\n : { kind: 'any' as const };\n const valueType = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n return { kind: 'record', key: keyType, value: valueType };\n }\n }\n\n return { kind: 'object', properties };\n}\n\n/**\n * 从 RuntimeType 提取字面量字符串集合\n * 用于 Pick<T, K> / Omit<T, K> 的 K 参数解析\n *\n * @returns 字面量值数组;无法解析时返回 null\n */\nfunction extractLiteralKeys(type: RuntimeType): string[] | null {\n if (type.kind === 'literal' && typeof type.value === 'string') {\n return [type.value];\n }\n if (type.kind === 'union') {\n const keys: string[] = [];\n for (const member of type.members) {\n if (member.kind === 'literal' && typeof member.value === 'string') {\n keys.push(member.value);\n } else {\n return null;\n }\n }\n return keys;\n }\n return null;\n}\n\n/**\n * 用 checker 解析 K 的最终类型,提取字面量字符串集合\n *\n * 用于 Pick<T, K> / Omit<T, K> 的 K 参数解析,覆盖 AST 无法直接拿到的场景:\n * - K 为类型别名(type Keys = 'id' | 'name')\n * - K 为 keyof T\n *\n * @returns 字面量值数组;无法解析时返回 null\n */\nfunction extractKeysFromChecker(typeNode: ts.TypeNode, checker?: ts.TypeChecker): string[] | null {\n if (!checker) return null;\n const type = checker.getTypeFromTypeNode(typeNode);\n\n if (type.isUnion()) {\n const keys: string[] = [];\n for (const member of type.types) {\n if (member.isStringLiteral()) {\n keys.push(member.value);\n } else if (member.isNumberLiteral()) {\n keys.push(String(member.value));\n } else {\n return null;\n }\n }\n return keys;\n }\n\n if (type.isStringLiteral()) {\n return [type.value];\n }\n if (type.isNumberLiteral()) {\n return [String(type.value)];\n }\n\n return null;\n}\n\n/**\n * 解析 keyof T — 用 checker 计算最终类型,返回字面量联合\n *\n * 例如 keyof { id: number; name: string } → 'id' | 'name'\n */\nfunction resolveKeyOf(typeNode: ts.TypeOperatorNode, checker?: ts.TypeChecker): RuntimeType {\n if (!checker) {\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 需要 checker 才能解析');\n }\n const type = checker.getTypeFromTypeNode(typeNode);\n\n if (type.isUnion()) {\n const members: RuntimeType[] = [];\n for (const member of type.types) {\n if (member.isStringLiteral()) {\n members.push({ kind: 'literal', value: member.value });\n } else if (member.isNumberLiteral()) {\n members.push({ kind: 'literal', value: member.value });\n } else {\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 的结果包含非字面量类型');\n }\n }\n return { kind: 'union', members };\n }\n\n if (type.isStringLiteral()) {\n return { kind: 'literal', value: type.value };\n }\n if (type.isNumberLiteral()) {\n return { kind: 'literal', value: type.value };\n }\n\n throw new SchemaExtractionError(typeNode.getText(), 'keyof T 的结果无法解析为字面量联合');\n}\n\n/**\n * 解析类型引用(Date / 自定义 interface / Array<T> / Record<K,V> 等)\n */\nfunction resolveTypeReference(\n typeNode: ts.TypeReferenceNode,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const typeName = typeNode.typeName.getText();\n\n // Date 类型\n if (typeName === 'Date') {\n return { kind: 'date' };\n }\n\n // Array<T>\n if (typeName === 'Array' && typeNode.typeArguments?.length === 1) {\n return {\n kind: 'array',\n element: resolveTypeNode(typeNode.typeArguments[0], checker, visited),\n };\n }\n\n // Record<K, V>\n if (typeName === 'Record' && typeNode.typeArguments?.length === 2) {\n return {\n kind: 'record',\n key: resolveTypeNode(typeNode.typeArguments[0], checker, visited),\n value: resolveTypeNode(typeNode.typeArguments[1], checker, visited),\n };\n }\n\n // Partial<T> / Required<T> / Readonly<T> — best effort,解析内部类型\n if (\n (typeName === 'Partial' || typeName === 'Required' || typeName === 'Readonly') &&\n typeNode.typeArguments?.length === 1\n ) {\n const inner = resolveTypeNode(typeNode.typeArguments[0], checker, visited);\n if (inner.kind === 'object' && typeName === 'Partial') {\n // Partial 所有字段变可选\n return {\n kind: 'object',\n properties: inner.properties.map((p) => ({ ...p, optional: true })),\n };\n }\n return inner;\n }\n\n // Pick<T, K> / Omit<T, K> — 解析 T 的字段,按 K 筛选/排除\n if ((typeName === 'Pick' || typeName === 'Omit') && typeNode.typeArguments?.length === 2) {\n const innerType = resolveTypeNode(typeNode.typeArguments[0], checker, visited);\n if (innerType.kind !== 'object') {\n throw new SchemaExtractionError(\n typeNode.getText(),\n `${typeName} 的 T 必须是对象类型,实际为 ${innerType.kind}`,\n );\n }\n\n // K 解析顺序:AST 字面量联合 → checker 解析(覆盖类型别名 / keyof T)\n const keyTypeNode = typeNode.typeArguments[1];\n let keys = extractLiteralKeys(resolveTypeNode(keyTypeNode, checker, visited));\n if (keys === null) {\n keys = extractKeysFromChecker(keyTypeNode, checker);\n }\n if (keys === null) {\n throw new SchemaExtractionError(typeNode.getText(), `${typeName} 的 K 无法解析为字面量集合`);\n }\n\n const keySet = new Set(keys);\n const properties =\n typeName === 'Pick'\n ? innerType.properties.filter((p) => keySet.has(p.name))\n : innerType.properties.filter((p) => !keySet.has(p.name));\n\n return { kind: 'object', properties };\n }\n\n // Map<K, V> / Set<T> — 运行时无法校验\n if (\n typeName === 'Map' ||\n typeName === 'Set' ||\n typeName === 'WeakMap' ||\n typeName === 'WeakSet'\n ) {\n throw new SchemaExtractionError(\n typeNode.getText(),\n `${typeName} 运行时无法校验,请改用对象或数组`,\n );\n }\n\n // Promise<T> — 运行时无法校验异步值\n if (typeName === 'Promise') {\n throw new SchemaExtractionError(\n typeNode.getText(),\n 'Promise 运行时无法校验,请勿在 query/body 类型中使用',\n );\n }\n\n // Function — HTTP/JSON 不能传输函数\n if (typeName === 'Function') {\n throw new SchemaExtractionError(typeNode.getText(), 'Function 无法通过 HTTP/JSON 传输');\n }\n\n // 防止递归循环:遇到已访问的类型返回 ref,支持循环引用\n if (visited.has(typeName)) {\n return { kind: 'ref', name: typeName };\n }\n visited.add(typeName);\n\n // 使用 checker 解析引用类型(interface / type 别名)\n if (checker) {\n const symbol =\n typeNode.typeName.kind === ts.SyntaxKind.Identifier\n ? checker.getSymbolAtLocation(typeNode.typeName)\n : undefined;\n\n if (symbol) {\n const declaration = symbol.declarations?.[0];\n if (declaration) {\n // interface 声明\n if (ts.isInterfaceDeclaration(declaration)) {\n return resolveInterfaceDeclaration(declaration, checker, visited);\n }\n // type 别名声明\n if (ts.isTypeAliasDeclaration(declaration)) {\n return resolveTypeNode(declaration.type, checker, visited);\n }\n // enum 声明 → 字面量联合\n if (ts.isEnumDeclaration(declaration)) {\n return resolveEnumDeclaration(declaration);\n }\n }\n }\n }\n\n throw new SchemaExtractionError(typeNode.getText(), `无法解析的引用类型 \"${typeName}\"`);\n}\n\n/**\n * 解析 enum 声明为字面量联合类型\n *\n * - 字符串枚举:`enum Role { Admin = 'admin' }` → `'admin' | ...`\n * - 数值枚举:`enum Code { OK = 200 }` → `200 | ...`\n * - 隐式数值枚举:`enum Dir { Up, Down }` → `0 | 1 | ...`\n *\n * HTTP 视角:枚举值在 JSON 中是普通 string/number,按字面量联合校验即可。\n */\nfunction resolveEnumDeclaration(node: ts.EnumDeclaration): RuntimeType {\n const members: RuntimeType[] = [];\n let nextNumericValue = 0;\n\n for (const member of node.members) {\n if (member.initializer) {\n if (ts.isStringLiteral(member.initializer)) {\n members.push({ kind: 'literal', value: member.initializer.text });\n } else if (ts.isNumericLiteral(member.initializer)) {\n const num = Number(member.initializer.text);\n members.push({ kind: 'literal', value: num });\n nextNumericValue = num + 1;\n } else {\n throw new SchemaExtractionError(\n node.name.text,\n `enum 成员 \"${member.name.getText()}\" 的初始化值类型不支持,仅支持 string/number 字面量`,\n );\n }\n } else {\n // 隐式数值枚举:无初始化值,使用递增整数\n members.push({ kind: 'literal', value: nextNumericValue });\n nextNumericValue++;\n }\n }\n\n return { kind: 'union', members };\n}\n\n/**\n * 解析 interface 声明(含继承)\n */\nexport function resolveInterfaceDeclaration(\n node: ts.InterfaceDeclaration,\n checker?: ts.TypeChecker,\n visited: Set<string> = new Set(),\n): RuntimeType {\n const properties: PropertyType[] = [];\n const propMap = new Map<string, PropertyType>();\n\n // 处理继承的父接口\n for (const heritageClause of node.heritageClauses ?? []) {\n if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const expr of heritageClause.types) {\n const parentType = resolveTypeNode(expr, checker, visited);\n if (parentType.kind === 'object') {\n for (const prop of parentType.properties) {\n propMap.set(prop.name, prop);\n }\n }\n }\n }\n }\n\n // 处理自身成员(覆盖继承的同名字段)\n for (const member of node.members) {\n if (ts.isPropertySignature(member) && member.name) {\n const name = member.name.getText();\n const optional = !!member.questionToken;\n const type = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n propMap.set(name, { name, type, optional });\n }\n // 索引签名 → record\n if (ts.isIndexSignatureDeclaration(member)) {\n const keyType = member.parameters[0]?.type\n ? resolveTypeNode(member.parameters[0].type, checker, visited)\n : { kind: 'any' as const };\n const valueType = member.type\n ? resolveTypeNode(member.type, checker, visited)\n : { kind: 'any' as const };\n return { kind: 'record', key: keyType, value: valueType };\n }\n }\n\n for (const prop of propMap.values()) {\n properties.push(prop);\n }\n\n return { kind: 'object', properties };\n}\n","import type { HandlerTypeInfo } from './extractHandlerTypes';\nimport type { RuntimeType, PropertyType } from './resolveTypeNode';\nimport { SchemaExtractionError } from './resolveTypeNode';\nimport type { ValidationIssue } from '../errors/httpErrors';\n\n/**\n * 将 RuntimeType 转为人类可读的类型描述字符串(用于 ValidationIssue.expected)\n *\n * 例如 'admin' | 'user' → \"'admin' | 'user'\"\n * string | null → \"string | null\"\n * Array<{ id: number }> → \"object[]\"\n */\nfunction runtimeTypeToExpected(type: RuntimeType): string {\n switch (type.kind) {\n case 'string':\n case 'number':\n case 'boolean':\n case 'null':\n case 'undefined':\n case 'bigint':\n case 'date':\n case 'any':\n case 'unknown':\n return type.kind;\n case 'literal':\n // 字符串字面量用单引号(符合 TS 习惯),数值/布尔直接输出\n return typeof type.value === 'string' ? `'${type.value}'` : String(type.value);\n case 'array':\n return `${runtimeTypeToExpected(type.element)}[]`;\n case 'tuple':\n return `[${type.elements\n .map((e) => (e.rest ? '...' : '') + runtimeTypeToExpected(e.type) + (e.optional ? '?' : ''))\n .join(', ')}]`;\n case 'object':\n return 'object';\n case 'union':\n return type.members.map(runtimeTypeToExpected).join(' | ');\n case 'record':\n return `Record<${runtimeTypeToExpected(type.key)}, ${runtimeTypeToExpected(type.value)}>`;\n case 'ref':\n return type.name;\n }\n}\n\n/**\n * 校验结果类型\n */\nexport interface ValidationResult {\n valid: boolean;\n issues: ValidationIssue[];\n data: Record<string, unknown>;\n}\n\n/**\n * schema 模块条目\n */\nexport interface SchemaModuleEntry {\n filePath: string;\n schemaName: string;\n typeInfo: HandlerTypeInfo | null;\n}\n\n/**\n * schema 模块导出格式\n */\nexport interface SchemaModuleExport {\n /** 校验函数表:'filePath#schemaName' -> ValidatorFn | null */\n validators: Record<string, ValidatorFn | null>;\n /** properties 表:'filePath#schemaName' -> PropertyType[](用于 coerce) */\n properties: Record<string, PropertyType[]>;\n}\n\n/**\n * 校验函数类型\n */\nexport type ValidatorFn = (input: unknown) => ValidationResult;\n\n/**\n * 类型解析器:根据类型名获取 RuntimeType\n *\n * 用于解析循环引用中的 ref。调用方负责提供(通常从 AST 提取)。\n */\nexport type TypeResolver = (name: string) => RuntimeType | undefined;\n\n/**\n * 生成单个类型的校验函数源码\n *\n * 返回的源码包含:\n * - 内部命名类型的 validate_X 函数声明(带循环引用保护)\n * - 名为 `validate` 的入口函数\n *\n * 循环引用保护:每个 validate_X 函数用 WeakSet 追踪已访问对象,\n * 遇到已访问的对象直接跳过,防止无限递归。\n *\n * @param typeInfo 类型信息\n * @param resolveType 类型解析器(可选,用于解析循环引用中的 ref)\n *\n * 用法:`new Function('input', source + '; return validate(input);')`\n */\nexport function generateValidatorSource(\n typeInfo: HandlerTypeInfo,\n resolveType?: TypeResolver,\n): string {\n const ctx = new CodeGenContext(resolveType);\n // 收集所有命名类型(用于生成 validate_X 函数)\n collectNamedTypes(typeInfo.runtimeType, typeInfo.name, ctx);\n // 生成入口函数(每次调用重置所有 validate_X 的 __visited,防止跨调用残留)\n const resetVisited = Array.from(ctx.namedTypes.keys())\n .map((name) => `validate_${name}.__visited = new WeakSet();`)\n .join('\\n ');\n const entryBody = generateObjectValidation(typeInfo.runtimeType, 'input', 'issues', ctx, \"''\");\n const entryFn = `function validate(input) {\n const issues = [];\n ${resetVisited}\n ${entryBody}\n return { valid: issues.length === 0, issues, data: (typeof input === 'object' && input !== null && !Array.isArray(input)) ? input : {} };\n}`;\n\n // 生成所有命名类型函数(带循环引用保护)\n const namedFns = Array.from(ctx.namedTypes.entries()).map(([name, type]) => {\n const body = generateObjectValidation(type, 'value', 'issues', ctx, 'path');\n return `function validate_${name}(value, path, issues) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n issues.push({ path, code: 'TYPE_MISMATCH', expected: 'object', received: typeof value, message: '期望对象' });\n return;\n }\n if (!validate_${name}.__visited) validate_${name}.__visited = new WeakSet();\n if (validate_${name}.__visited.has(value)) return;\n validate_${name}.__visited.add(value);\n ${body}\n}`;\n });\n\n return [...namedFns, entryFn].join('\\n\\n');\n}\n\n/**\n * 生成完整 JS 模块源码\n *\n * 包含所有命名类型函数 + validators 导出对象\n *\n * @param entries schema 条目\n * @param resolveType 类型解析器(可选,用于解析循环引用中的 ref)\n */\nexport function generateSchemaModule(\n entries: SchemaModuleEntry[],\n resolveType?: TypeResolver,\n): string {\n const ctx = new CodeGenContext(resolveType);\n const validatorEntries: string[] = [];\n const propertyEntries: string[] = [];\n\n // 先收集所有命名类型\n for (const entry of entries) {\n if (entry.typeInfo === null) continue;\n collectNamedTypes(entry.typeInfo.runtimeType, entry.typeInfo.name, ctx);\n }\n\n // 为每个 entry 生成重置 __visited 的代码\n const resetVisitedCode = Array.from(ctx.namedTypes.keys())\n .map((name) => `validate_${name}.__visited = new WeakSet();`)\n .join('\\n ');\n\n for (const entry of entries) {\n const key = `${entry.filePath}#${entry.schemaName}`;\n if (entry.typeInfo === null) {\n validatorEntries.push(` ${JSON.stringify(key)}: null,`);\n continue;\n }\n const body = generateObjectValidation(entry.typeInfo.runtimeType, 'input', 'issues', ctx, \"''\");\n validatorEntries.push(` ${JSON.stringify(key)}: (input) => {\n const issues = [];\n ${resetVisitedCode}\n ${body}\n return { valid: issues.length === 0, issues, data: (typeof input === 'object' && input !== null && !Array.isArray(input)) ? input : {} };\n },`);\n // 导出 properties(用于 coerce)\n propertyEntries.push(` ${JSON.stringify(key)}: ${JSON.stringify(entry.typeInfo.properties)},`);\n }\n\n // 生成所有命名类型函数(去重,带循环引用保护)\n const namedFns = Array.from(ctx.namedTypes.entries()).map(([name, type]) => {\n const body = generateObjectValidation(type, 'value', 'issues', ctx, 'path');\n return `function validate_${name}(value, path, issues) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n issues.push({ path, code: 'TYPE_MISMATCH', expected: 'object', received: typeof value, message: '期望对象' });\n return;\n }\n if (!validate_${name}.__visited) validate_${name}.__visited = new WeakSet();\n if (validate_${name}.__visited.has(value)) return;\n validate_${name}.__visited.add(value);\n ${body}\n}`;\n });\n\n return `${namedFns.join('\\n\\n')}\n\nconst validators = {\n${validatorEntries.join('\\n')}\n};\n\nconst properties = {\n${propertyEntries.join('\\n')}\n};\n\nexport { validators, properties };\n`;\n}\n\n/**\n * 代码生成上下文\n */\nclass CodeGenContext {\n // collected 在 collectNamedTypes 等外部函数中访问,故不设为 private\n /** 命名类型集合:类型名 -> RuntimeType */\n namedTypes = new Map<string, RuntimeType>();\n /** 已收集的类型(防重复) */\n collected = new Set<string>();\n /** 类型解析器(用于解析 ref) */\n private resolveType?: TypeResolver;\n /** 变量名计数器(防止嵌套数组变量名遮蔽) */\n private varId = 0;\n\n constructor(resolveType?: TypeResolver) {\n this.resolveType = resolveType;\n }\n\n /** 生成唯一变量 ID */\n nextVarId(): number {\n return ++this.varId;\n }\n\n /**\n * 解析 ref:通过 resolveType 回调获取类型定义\n */\n resolveRef(name: string): RuntimeType | undefined {\n return this.resolveType?.(name);\n }\n}\n\n/**\n * 收集所有命名 object 类型\n *\n * 遇到 object 类型时注册为命名类型,递归收集属性中的命名类型。\n * 遇到 ref 时通过 resolveType 回调获取类型定义并收集。\n *\n * 同时检测必填直接循环引用(会导致无限递归,无法自然终止):\n * - `next: LinkedList`(必填 ref)→ 抛错\n * - `next?: LinkedList`(可选 ref)→ 合法(undefined 可终止)\n * - `children: LinkedList[]`(数组 ref)→ 合法(空数组可终止)\n * - `next: LinkedList | null`(联合中的 ref)→ 合法(null 可终止)\n */\nfunction collectNamedTypes(type: RuntimeType, name: string, ctx: CodeGenContext): void {\n if (ctx.collected.has(name)) return;\n ctx.collected.add(name);\n\n if (type.kind === 'object') {\n ctx.namedTypes.set(name, type);\n for (const prop of type.properties) {\n detectRequiredRef(prop, name);\n collectNamedTypesFromType(prop.type, ctx);\n }\n }\n}\n\n/**\n * 检测必填直接循环引用并抛错\n *\n * 只检测 `!optional && type.kind === 'ref'`。\n * 数组元素、联合成员中的 ref 不检测(它们有自然终止条件)。\n */\nfunction detectRequiredRef(prop: PropertyType, ownerName: string): void {\n if (!prop.optional && prop.type.kind === 'ref') {\n throw new SchemaExtractionError(\n ownerName,\n `属性 \"${prop.name}\" 是必填的循环引用(类型 ${prop.type.name}),会导致无限递归。请改为可选(${prop.name}?: ${prop.type.name})或数组(${prop.name}: ${prop.type.name}[])。`,\n );\n }\n}\n\n/**\n * 从任意类型中收集命名类型\n */\nfunction collectNamedTypesFromType(type: RuntimeType, ctx: CodeGenContext): void {\n switch (type.kind) {\n case 'array':\n collectNamedTypesFromType(type.element, ctx);\n break;\n case 'tuple':\n for (const elem of type.elements) {\n collectNamedTypesFromType(elem.type, ctx);\n }\n break;\n case 'union':\n for (const member of type.members) {\n collectNamedTypesFromType(member, ctx);\n }\n break;\n case 'object':\n // 匿名 object,不需要生成 validate_X,但仍需检测必填 ref\n for (const prop of type.properties) {\n detectRequiredRef(prop, '<匿名对象>');\n collectNamedTypesFromType(prop.type, ctx);\n }\n break;\n case 'record':\n collectNamedTypesFromType(type.value, ctx);\n break;\n case 'ref': {\n // 命名类型引用:通过 resolveType 获取定义并收集\n if (!ctx.collected.has(type.name)) {\n const resolved = ctx.resolveRef(type.name);\n if (resolved) {\n collectNamedTypes(resolved, type.name, ctx);\n }\n }\n break;\n }\n }\n}\n\n/**\n * 生成对象类型的校验代码\n *\n * @param pathExpr 当前路径表达式(入口为 \"''\",命名类型函数体为 \"path\")\n */\nfunction generateObjectValidation(\n type: RuntimeType,\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr: string,\n): string {\n if (type.kind !== 'object') {\n return generateValueValidation(type, varName, issuesVar, ctx, pathExpr);\n }\n\n const lines: string[] = [];\n for (const prop of type.properties) {\n // 入口路径为空字符串时,子属性路径直接用字面量;否则用 pathExpr 拼接\n const propPath = pathExpr === \"''\" ? `'${prop.name}'` : `${pathExpr} + '.${prop.name}'`;\n const propAccess = `${varName}['${prop.name}']`;\n const hasCheck = `'${prop.name}' in ${varName}`;\n\n if (!prop.optional) {\n lines.push(\n `if (!${hasCheck}) ${issuesVar}.push({ path: ${propPath}, code: 'MISSING_FIELD', expected: '${prop.name}', received: 'undefined', message: '缺少必填字段 \"${prop.name}\"' });`,\n );\n lines.push(`else {`);\n } else {\n lines.push(`if (${hasCheck} && ${propAccess} !== undefined) {`);\n }\n\n lines.push(` ${generateValueValidation(prop.type, propAccess, issuesVar, ctx, propPath)}`);\n\n lines.push(`}`);\n }\n return lines.join('\\n');\n}\n\n/**\n * 生成值类型的校验代码\n */\nfunction generateValueValidation(\n type: RuntimeType,\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr?: string,\n): string {\n const path = pathExpr ?? \"''\";\n\n switch (type.kind) {\n case 'any':\n case 'unknown':\n return ''; // 不校验\n\n case 'string':\n return `if (typeof ${varName} !== 'string') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'string', received: typeof ${varName}, message: '期望 string,实际 ' + typeof ${varName} });`;\n\n case 'number':\n return `if (typeof ${varName} !== 'number' || Number.isNaN(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'number', received: typeof ${varName}, message: '期望 number,实际 ' + typeof ${varName} });`;\n\n case 'boolean':\n return `if (typeof ${varName} !== 'boolean') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'boolean', received: typeof ${varName}, message: '期望 boolean,实际 ' + typeof ${varName} });`;\n\n case 'bigint':\n // HTTP 不能传输 BigInt,声明 bigint 的字段必然校验失败\n return `if (typeof ${varName} !== 'bigint') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'bigint', received: typeof ${varName}, message: '期望 bigint,实际 ' + typeof ${varName} });`;\n\n case 'null':\n return `if (${varName} !== null) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'null', received: typeof ${varName}, message: '期望 null,实际 ' + typeof ${varName} });`;\n\n case 'undefined':\n return `if (${varName} !== undefined) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'undefined', received: typeof ${varName}, message: '期望 undefined' });`;\n\n case 'literal':\n return `if (${varName} !== ${JSON.stringify(type.value)}) ${issuesVar}.push({ path: ${path}, code: 'INVALID_VALUE', expected: ${JSON.stringify(JSON.stringify(type.value))}, received: JSON.stringify(${varName}), message: '期望字面量 ${JSON.stringify(type.value)},实际 ' + JSON.stringify(${varName}) });`;\n\n case 'date':\n // HTTP 传输的是 ISO 字符串,允许 Date 实例或合法 ISO 8601 字符串\n // 类型不符 -> TYPE_MISMATCH; 类型对但格式非法 -> INVALID_FORMAT\n return `if (${varName} instanceof Date) { /* Date 实例,通过 */ }\nelse if (typeof ${varName} !== 'string') ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'Date | ISO 8601 string', received: typeof ${varName}, message: '期望 Date 或 ISO 8601 字符串,实际 ' + typeof ${varName} });\nelse if (!/^\\\\d{4}-\\\\d{2}-\\\\d{2}(T\\\\d{2}:\\\\d{2}:\\\\d{2}(\\\\.\\\\d{1,3})?(Z|[+-]\\\\d{2}:?\\\\d{2})?)?$/.test(${varName}) || isNaN(new Date(${varName}).getTime())) ${issuesVar}.push({ path: ${path}, code: 'INVALID_FORMAT', expected: 'ISO 8601', received: String(${varName}), message: '不是合法的 ISO 8601 日期字符串: ' + ${varName} });`;\n\n case 'array': {\n const id = ctx.nextVarId();\n const itemVar = `item${id}`;\n const indexVar = `i${id}`;\n const elemPath = `${path} + '[' + ${indexVar} + ']'`;\n const elemValidation = generateValueValidation(\n type.element,\n itemVar,\n issuesVar,\n ctx,\n elemPath,\n );\n return `if (!Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'array', received: typeof ${varName}, message: '期望数组,实际 ' + typeof ${varName} });\nelse for (let ${indexVar} = 0; ${indexVar} < ${varName}.length; ${indexVar}++) { const ${itemVar} = ${varName}[${indexVar}]; ${elemValidation} }`;\n }\n\n case 'tuple': {\n // 元组:按位置校验,支持可选元素和剩余元素\n // - 必填元素:缺失报 MISSING_FIELD\n // - 可选元素:缺失不报错\n // - 剩余元素:之后的元素都按 rest 类型校验\n const minRequired = type.elements.filter((e) => !e.optional && !e.rest).length;\n const fixedCount = type.elements.filter((e) => !e.rest).length;\n const restElement = type.elements.find((e) => e.rest);\n const id = ctx.nextVarId();\n const itemVar = `t${id}`;\n const indexVar = `ti${id}`;\n\n // 数组类型检查 + 长度检查\n const lines: string[] = [];\n lines.push(\n `if (!Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'tuple', received: typeof ${varName}, message: '期望元组(数组),实际 ' + typeof ${varName} });`,\n );\n lines.push(`else {`);\n // 最小长度检查(必填元素数量)\n lines.push(\n `if (${varName}.length < ${minRequired}) ${issuesVar}.push({ path: ${path}, code: 'MISSING_FIELD', expected: 'tuple length >= ${minRequired}', received: 'length ' + ${varName}.length, message: '元组长度不足,期望至少 ${minRequired},实际 ' + ${varName}.length });`,\n );\n // 最大长度检查(无 rest 时不能超过固定元素数量)\n if (!restElement) {\n lines.push(\n `if (${varName}.length > ${fixedCount}) ${issuesVar}.push({ path: ${path}, code: 'INVALID_VALUE', expected: 'tuple length = ${fixedCount}', received: 'length ' + ${varName}.length, message: '元组长度超出,期望 ${fixedCount},实际 ' + ${varName}.length });`,\n );\n }\n\n // 按位置校验固定元素\n for (let i = 0; i < type.elements.length; i++) {\n const elem = type.elements[i];\n if (elem.rest) continue; // rest 元素单独处理\n const elemPath = `${path} + '[' + ${i} + ']'`;\n const elemAccess = `${varName}[${i}]`;\n if (elem.optional) {\n lines.push(`if (${i} < ${varName}.length && ${elemAccess} !== undefined) {`);\n } else {\n lines.push(`if (${i} < ${varName}.length) {`);\n }\n lines.push(` ${generateValueValidation(elem.type, elemAccess, issuesVar, ctx, elemPath)}`);\n lines.push(`}`);\n }\n\n // 剩余元素校验\n if (restElement) {\n const restPath = `${path} + '[' + ${indexVar} + ']'`;\n const restValidation = generateValueValidation(\n restElement.type,\n itemVar,\n issuesVar,\n ctx,\n restPath,\n );\n lines.push(\n `for (let ${indexVar} = ${fixedCount}; ${indexVar} < ${varName}.length; ${indexVar}++) { const ${itemVar} = ${varName}[${indexVar}]; ${restValidation} }`,\n );\n }\n\n lines.push(`}`);\n return lines.join('\\n');\n }\n\n case 'union': {\n // 联合类型:生成临时 issues 数组,任一成员匹配即可\n const tempVar = `tempIssues_${Math.random().toString(36).slice(2, 8)}`;\n const memberChecks = type.members.map((member) => {\n const check = generateValueValidation(member, varName, tempVar, ctx, path);\n return `(() => { const ${tempVar} = []; ${check}; return ${tempVar}.length === 0; })()`;\n });\n const expected = runtimeTypeToExpected(type);\n return `if (!(${memberChecks.join(' || ')})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: ${JSON.stringify(expected)}, received: typeof ${varName}, message: '值 ' + JSON.stringify(${varName}) + ' 不匹配联合类型 ${expected.replace(/'/g, \"\\\\'\")}' });`;\n }\n\n case 'record': {\n const valuePath = `${path} + '.' + key`;\n const valueValidation = generateValueValidation(type.value, 'val', issuesVar, ctx, valuePath);\n return `if (typeof ${varName} !== 'object' || ${varName} === null || Array.isArray(${varName})) ${issuesVar}.push({ path: ${path}, code: 'TYPE_MISMATCH', expected: 'object', received: typeof ${varName}, message: '期望对象,实际 ' + typeof ${varName} });\nelse for (const [key, val] of Object.entries(${varName})) { ${valueValidation} }`;\n }\n\n case 'object': {\n // 匿名 object:内联校验\n return generateInlineObjectValidation(type, varName, issuesVar, ctx, path);\n }\n\n case 'ref': {\n // 命名类型引用:调用 validate_X 函数(支持循环引用递归)\n return `validate_${type.name}(${varName}, ${path}, ${issuesVar});`;\n }\n }\n}\n\n/**\n * 生成内联对象校验代码(匿名 object)\n */\nfunction generateInlineObjectValidation(\n type: RuntimeType & { kind: 'object' },\n varName: string,\n issuesVar: string,\n ctx: CodeGenContext,\n pathExpr: string,\n): string {\n const lines: string[] = [];\n lines.push(\n `if (typeof ${varName} !== 'object' || ${varName} === null || Array.isArray(${varName})) ${issuesVar}.push({ path: ${pathExpr}, code: 'TYPE_MISMATCH', expected: 'object', received: typeof ${varName}, message: '期望对象,实际 ' + typeof ${varName} });`,\n );\n lines.push('else {');\n for (const prop of type.properties) {\n const propPath = `${pathExpr} + '.${prop.name}'`;\n const propAccess = `${varName}['${prop.name}']`;\n const hasCheck = `'${prop.name}' in ${varName}`;\n\n if (!prop.optional) {\n lines.push(\n ` if (!${hasCheck}) ${issuesVar}.push({ path: ${propPath}, code: 'MISSING_FIELD', expected: '${prop.name}', received: 'undefined', message: '缺少必填字段 \"${prop.name}\"' });`,\n );\n lines.push(` else {`);\n } else {\n lines.push(` if (${hasCheck} && ${propAccess} !== undefined) {`);\n }\n lines.push(` ${generateValueValidation(prop.type, propAccess, issuesVar, ctx, propPath)}`);\n lines.push(` }`);\n }\n lines.push('}');\n return lines.join('\\n');\n}\n","import type { ValidatorFn } from '../ast/generateValidatorCode';\nimport type { PropertyType } from '../ast/resolveTypeNode';\n\n/**\n * 单个 schema 条目\n * - SchemaEntry:有类型声明,包含 properties(用于 coerce)和 validator(用于校验)\n * - null:handler 无类型声明(如 GET() 无参数),跳过校验\n */\nexport type SchemaEntry = { properties: PropertyType[]; validator: ValidatorFn } | null;\n\n/**\n * 单个文件的所有 schema:schemaName -> SchemaEntry\n * schemaName 由 method + inputType 生成,如 'GETQuery'、'POSTBody'\n */\nexport type FileSchemas = Map<string, SchemaEntry>;\n\n/**\n * 完整 manifest:filePath -> FileSchemas\n */\nexport type SchemaManifest = Map<string, FileSchemas>;\n\n/**\n * Schema 注册表(单例)\n *\n * 统一管理 handler 的校验函数,作为 validateInput 的唯一数据来源。\n * - prd 模式:从 dist/faapi-schema.js import 加载\n * - dev 模式:启动时全量提取并生成函数,watch 时全量重建\n *\n * 三种状态区分:\n * - get() 返回 SchemaEntry:有类型声明,校验\n * - get() 返回 null:无类型声明,跳过校验\n * - get() 返回 undefined:manifest 不完整,抛错\n */\nclass SchemaRegistry {\n private manifest: SchemaManifest = new Map();\n\n /**\n * 批量加载 manifest\n * 覆盖已有数据\n */\n loadManifest(manifest: SchemaManifest): void {\n this.manifest.clear();\n for (const [filePath, fileSchemas] of manifest) {\n const copy: FileSchemas = new Map();\n fileSchemas.forEach((value, key) => copy.set(key, value));\n this.manifest.set(filePath, copy);\n }\n }\n\n /**\n * 查询单条 schema\n * @returns SchemaEntry | null | undefined\n * - SchemaEntry:有类型声明\n * - null:无类型声明(跳过校验)\n * - undefined:manifest 不完整(抛错)\n */\n get(filePath: string, schemaName: string): SchemaEntry | undefined {\n const fileSchemas = this.manifest.get(filePath);\n if (!fileSchemas) return undefined;\n return fileSchemas.get(schemaName);\n }\n\n /**\n * 设置单个文件的所有 schema\n * 覆盖该文件的已有数据\n */\n set(filePath: string, schemas: FileSchemas): void {\n const copy: FileSchemas = new Map();\n schemas.forEach((value, key) => copy.set(key, value));\n this.manifest.set(filePath, copy);\n }\n\n /**\n * 删除单个文件(文件被删除时)\n */\n delete(filePath: string): void {\n this.manifest.delete(filePath);\n }\n\n /**\n * 判断文件是否已注册\n */\n hasFile(filePath: string): boolean {\n return this.manifest.has(filePath);\n }\n\n /**\n * 清空(测试用 / watch 全量重建前)\n */\n clear(): void {\n this.manifest.clear();\n }\n\n /**\n * 已注册的文件数量\n */\n get size(): number {\n return this.manifest.size;\n }\n}\n\n/**\n * 全局单例\n */\nexport const schemaRegistry = new SchemaRegistry();\n","import ts from 'typescript';\n\n/**\n * Program 缓存,key 为文件路径\n *\n * watch 模式下通过 invalidateProgramCache() 全量清理。\n * 同一文件多次创建 Program 时复用缓存,避免重复解析。\n */\nconst programCache = new Map<string, ts.Program>();\n\n/**\n * 清理所有 Program 缓存(watch 模式下文件变化时调用)\n *\n * 全量清理而非增量清理,理由:\n * - 简单可靠,无状态一致性问题\n * - 跨文件类型引用需要所有文件的 Program 同步更新\n * - dev 模式文件量有限,全量重建在百毫秒级\n */\nexport function invalidateProgramCache(): void {\n programCache.clear();\n}\n\n/**\n * 为指定文件创建 TypeScript Program(带缓存)\n *\n * @param filePath 要分析的 .ts 文件绝对路径\n */\nexport function createProgram(filePath: string): ts.Program {\n const cached = programCache.get(filePath);\n if (cached) {\n return cached;\n }\n\n const program = ts.createProgram([filePath], {\n strict: true,\n target: ts.ScriptTarget.ES2022,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n skipLibCheck: true,\n noEmit: true,\n });\n\n programCache.set(filePath, program);\n return program;\n}\n","import ts from 'typescript';\nimport {\n resolveTypeNode,\n resolveInterfaceDeclaration,\n type PropertyType,\n type RuntimeType,\n SchemaExtractionError,\n} from './resolveTypeNode';\n\nexport interface HandlerTypeInfo {\n name: string; // 类型名,如 'GETQuery'\n properties: PropertyType[];\n /** 完整的运行时类型描述(用于嵌套校验) */\n runtimeType: RuntimeType;\n}\n\n/**\n * 从源文件中提取指定名称的类型信息\n *\n * 支持的类型声明:\n * - interface 声明(含继承)\n * - type 别名(type Query = { ... })\n *\n * 遇到不支持的类型时抛 `SchemaExtractionError`,错误信息包含文件路径和类型名。\n *\n * @param program TypeScript Program\n * @param filePath 源文件路径\n * @param typeName 类型名,如 'GETQuery'\n */\nexport function extractTypeInfo(\n program: ts.Program,\n filePath: string,\n typeName: string,\n): HandlerTypeInfo | null {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) return null;\n\n const checker = program.getTypeChecker();\n\n // 1. 查找 interface 声明\n let result: HandlerTypeInfo | null = null;\n\n ts.forEachChild(sourceFile, (node) => {\n if (result) return;\n\n if (ts.isInterfaceDeclaration(node) && node.name.text === typeName) {\n const visited = new Set<string>();\n visited.add(typeName); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, typeName, () =>\n resolveInterfaceDeclaration(node, checker, visited),\n );\n result = {\n name: typeName,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n };\n return;\n }\n\n // 2. 查找 type 别名\n if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {\n const visited = new Set<string>();\n visited.add(typeName); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, typeName, () =>\n resolveTypeNode(node.type, checker, visited),\n );\n result = {\n name: typeName,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n };\n return;\n }\n });\n\n return result;\n}\n\n/**\n * 从源文件中提取所有 interface 和 type 别名的类型信息\n *\n * 用于:\n * - 生成 schema 模块时遍历所有命名类型\n * - 作为 typeResolver 提供给 generateValidatorCode,解析循环引用中的 ref\n *\n * @returns Map<类型名, HandlerTypeInfo>\n */\nexport function extractAllTypes(\n program: ts.Program,\n filePath: string,\n): Map<string, HandlerTypeInfo> {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) return new Map();\n\n const checker = program.getTypeChecker();\n const result = new Map<string, HandlerTypeInfo>();\n\n ts.forEachChild(sourceFile, (node) => {\n if (ts.isInterfaceDeclaration(node)) {\n const visited = new Set<string>();\n visited.add(node.name.text); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, node.name.text, () =>\n resolveInterfaceDeclaration(node, checker, visited),\n );\n result.set(node.name.text, {\n name: node.name.text,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n });\n return;\n }\n\n if (ts.isTypeAliasDeclaration(node)) {\n const visited = new Set<string>();\n visited.add(node.name.text); // 标记当前类型,使自引用直接返回 ref\n const runtimeType = withFileContext(filePath, node.name.text, () =>\n resolveTypeNode(node.type, checker, visited),\n );\n result.set(node.name.text, {\n name: node.name.text,\n properties: runtimeType.kind === 'object' ? runtimeType.properties : [],\n runtimeType,\n });\n return;\n }\n });\n\n return result;\n}\n\n/**\n * 包装类型解析,捕获 SchemaExtractionError 并补充文件路径和类型名上下文\n *\n * 只包装一次(最外层),避免嵌套调用时重复包装。\n */\nfunction withFileContext<T>(filePath: string, typeName: string, fn: () => T): T {\n try {\n return fn();\n } catch (err) {\n if (err instanceof SchemaExtractionError) {\n // 补充文件路径和类型名,只包装一次\n const fileName = filePath.split('/').pop() ?? filePath;\n const enriched = new SchemaExtractionError(\n err.typeText,\n `${err.reason}(文件: ${fileName}, 类型: ${typeName})`,\n { cause: err },\n );\n throw enriched;\n }\n throw err;\n }\n}\n","/**\n * 根据 HTTP 方法和输入类型生成 schema 类型名\n * GET + query -> GETQuery\n * POST + body -> POSTBody\n * GET + params -> GETParams\n */\nexport function getSchemaName(method: string, inputType: 'query' | 'body' | 'params'): string {\n return `${method.toUpperCase()}${inputType.charAt(0).toUpperCase() + inputType.slice(1)}`;\n}\n","import { createProgram } from '../ast/createProgram';\nimport { extractTypeInfo, extractAllTypes, type HandlerTypeInfo } from '../ast/extractHandlerTypes';\nimport { getInputTypeForMethod } from '../runtime/inputType';\nimport { getSchemaName } from '../validator/schemaName';\nimport { analyzeInjection } from '../injection/analyzeInjection';\nimport type { RouteManifest } from '../router/routeTypes';\nimport path from 'node:path';\n\n/**\n * 单个路由的 schema 提取结果\n */\nexport interface RouteSchemaSource {\n filePath: string;\n schemaName: string;\n typeInfo: HandlerTypeInfo | null;\n}\n\n/**\n * 从路由清单收集 schema 提取所需的原始数据\n *\n * dev 和 prd 共享的核心提取流程:\n * 1. 按文件分组遍历路由\n * 2. 对每个文件 createProgram + extractAllTypes 收集所有类型\n * 3. 用 analyzeInjection + extractTypeInfo 提取每个路由的 schema 类型\n * 4. 同时返回按文件分组的 allTypesMap 和合并后的全局 allTypes\n *\n * 调用方基于返回的 sources 和 allTypes 各自做最终转换:\n * - dev:编译 validator 函数 → SchemaManifest(用 mergedAllTypes)\n * - prd:生成 JS 模块代码 → SchemaModuleEntry[](用 allTypesByFile)\n */\nexport function collectRouteSchemaSources(\n routes: RouteManifest,\n rootDir?: string,\n): {\n sources: RouteSchemaSource[];\n /** 按文件分组的类型映射(prd writeSchemaModule 用) */\n allTypesByFile: Map<string, Map<string, HandlerTypeInfo>>;\n /** 合并后的全局类型映射(dev typeInfoToSchemaEntry 用) */\n mergedAllTypes: Map<string, HandlerTypeInfo>;\n} {\n // 按文件分组收集方法(去重)\n const methodsByFile = new Map<string, Set<string>>();\n for (const route of routes) {\n const filePath = rootDir ? path.resolve(rootDir, route.filePath) : route.filePath;\n let methods = methodsByFile.get(filePath);\n if (!methods) {\n methods = new Set();\n methodsByFile.set(filePath, methods);\n }\n methods.add(route.method);\n }\n\n // 先收集所有文件的类型\n const programByFile = new Map<string, ReturnType<typeof createProgram>>();\n const allTypesByFile = new Map<string, Map<string, HandlerTypeInfo>>();\n const mergedAllTypes = new Map<string, HandlerTypeInfo>();\n for (const filePath of methodsByFile.keys()) {\n const program = createProgram(filePath);\n programByFile.set(filePath, program);\n const allTypes = extractAllTypes(program, filePath);\n allTypesByFile.set(filePath, allTypes);\n for (const [name, info] of allTypes) {\n mergedAllTypes.set(name, info);\n }\n }\n\n // 每个文件提取 schema\n const sources: RouteSchemaSource[] = [];\n for (const [filePath, methods] of methodsByFile) {\n const program = programByFile.get(filePath)!;\n const sourceFile = program.getSourceFile(filePath);\n const code = sourceFile?.text ?? '';\n for (const method of methods) {\n const inputType = getInputTypeForMethod(method);\n const schemaName = getSchemaName(method, inputType);\n const meta = analyzeInjection(code, method);\n const param = meta.params.find((p) => p.type === inputType);\n const typeInfo = param?.typeName ? extractTypeInfo(program, filePath, param.typeName) : null;\n sources.push({ filePath, schemaName, typeInfo });\n }\n }\n\n return { sources, allTypesByFile, mergedAllTypes };\n}\n","import {\n generateValidatorSource,\n generateSchemaModule,\n type SchemaModuleEntry,\n} from '../ast/generateValidatorCode';\nimport type { HandlerTypeInfo } from '../ast/extractHandlerTypes';\nimport type { RouteManifest } from '../router/routeTypes';\nimport type { SchemaManifest, SchemaEntry } from '../validator/schemaRegistry';\nimport { schemaRegistry } from '../validator/schemaRegistry';\nimport { collectRouteSchemaSources } from './collectRouteSchemaSources';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\n/**\n * 从路由清单提取完整 manifest,并生成校验函数\n *\n * 同一文件的多个方法合并到同一 FileSchemas。\n *\n * 与 prd 的 writeSchemaModule 一致:先收集所有文件的类型并合并为全局 allTypes,\n * 再传给每个文件的 schema 生成,确保跨文件类型引用可解析(与 prd 行为一致)。\n *\n * @param routes 路由清单(filePath 为相对路径)\n * @param rootDir 项目根目录,传入时将 filePath 转为绝对路径(与 validateInput 调用一致)\n */\nexport function extractSchemasForRoutes(routes: RouteManifest, rootDir?: string): SchemaManifest {\n const { sources, mergedAllTypes } = collectRouteSchemaSources(routes, rootDir);\n\n // 按文件分组,合并为 FileSchemas\n const manifest: SchemaManifest = new Map();\n for (const { filePath, schemaName, typeInfo } of sources) {\n let fileSchemas = manifest.get(filePath);\n if (!fileSchemas) {\n fileSchemas = new Map();\n manifest.set(filePath, fileSchemas);\n }\n fileSchemas.set(schemaName, typeInfoToSchemaEntry(typeInfo, mergedAllTypes));\n }\n\n return manifest;\n}\n\n/**\n * 将 HandlerTypeInfo 转为 SchemaEntry(包含 properties 和 validator)\n *\n * typeInfo 为 null 时返回 null(跳过校验)。\n * typeInfo 非 null 时生成校验函数源码并用 new Function 创建。\n */\nfunction typeInfoToSchemaEntry(\n typeInfo: HandlerTypeInfo | null,\n allTypes: Map<string, HandlerTypeInfo>,\n): SchemaEntry {\n if (typeInfo === null) return null;\n\n const source = generateValidatorSource(typeInfo, (name) => allTypes.get(name)?.runtimeType);\n // 用 new Function 创建校验函数\n const validator = new Function('input', `${source}\\nreturn validate(input);`) as (\n input: unknown,\n ) => ReturnType<typeof Object>;\n return {\n properties: typeInfo.properties,\n validator: validator as SchemaEntry extends { validator: infer F } ? F : never,\n };\n}\n\n/**\n * 生成 schema JS 模块并写入文件\n *\n * @param entries schema 模块条目(包含 typeInfo)\n * @param allTypesMap 每个文件对应的所有类型(用于解析循环引用)\n * @param outputPath 输出路径(如 dist/faapi-schema.js)\n */\nexport async function writeSchemaModule(\n entries: SchemaModuleEntry[],\n allTypesMap: Map<string, Map<string, HandlerTypeInfo>>,\n outputPath: string,\n): Promise<void> {\n // 合并所有文件的类型解析器\n const allTypes = new Map<string, HandlerTypeInfo>();\n for (const types of allTypesMap.values()) {\n for (const [name, info] of types) {\n allTypes.set(name, info);\n }\n }\n\n const source = generateSchemaModule(entries, (name) => allTypes.get(name)?.runtimeType);\n\n await fs.mkdir(path.dirname(outputPath), { recursive: true });\n await fs.writeFile(outputPath, source, 'utf-8');\n}\n\n/**\n * 从路由清单提取 schema 并生成 JS 模块文件(dev/build 共用)\n *\n * 内部流程:collectRouteSchemaSources(AST 从源码 .ts)→ writeSchemaModule(写文件)\n *\n * @param routes 排序后的路由清单(filePath 为源码相对路径,如 src/api/hello/handler.ts)\n * @param rootDir 项目根目录\n * @param outputPath 输出路径(如 .faapi/dev/faapi-schema.js 或 dist/faapi-schema.js)\n */\nexport async function generateSchemaFile(\n routes: RouteManifest,\n rootDir: string,\n outputPath: string,\n): Promise<void> {\n const { sources, allTypesByFile } = collectRouteSchemaSources(routes, rootDir);\n const entries: SchemaModuleEntry[] = sources.map(({ filePath, schemaName, typeInfo }) => ({\n filePath,\n schemaName,\n typeInfo,\n }));\n await writeSchemaModule(entries, allTypesByFile, outputPath);\n}\n\n/**\n * 读取 schema JS 模块并转为 SchemaManifest\n *\n * 动态 import JS 模块,获取 validators 和 properties 对象。\n * 使用 importWithCacheBust:dev watch 模式下重新生成文件后能拿到最新版本(绕过 ESM 缓存)。\n */\nexport async function readManifestFile(inputPath: string): Promise<SchemaManifest> {\n const mod = (await importWithCacheBust(inputPath)) as {\n validators: Record<string, ((input: unknown) => unknown) | null>;\n properties?: Record<string, unknown[]>;\n };\n const validators = mod.validators;\n const properties = (mod.properties ?? {}) as Record<string, unknown[]>;\n\n const manifest: SchemaManifest = new Map();\n for (const [key, validator] of Object.entries(validators)) {\n const [filePath, schemaName] = key.split('#');\n if (!filePath || !schemaName) continue;\n\n let fileSchemas = manifest.get(filePath);\n if (!fileSchemas) {\n fileSchemas = new Map();\n manifest.set(filePath, fileSchemas);\n }\n\n if (validator === null) {\n fileSchemas.set(schemaName, null);\n } else {\n fileSchemas.set(schemaName, {\n properties: (properties[key] ?? []) as SchemaEntry extends { properties: infer P }\n ? P\n : never,\n validator: validator as SchemaEntry extends { validator: infer F } ? F : never,\n });\n }\n }\n\n return manifest;\n}\n\n/**\n * 重写 manifest 的 filePath key,使运行时能匹配 validateInput 传入的路径\n *\n * schema 生成时 key 形式:/abs/root/src/api/hello/handler.ts(源码绝对路径 + .ts)\n * 运行时 validateInput 传入:/abs/root/{prodDir}/src/api/hello/handler.js(产物绝对路径 + .js + prodDir 前缀)\n *\n * 转换:/abs/root/src/api/hello/handler.ts → /abs/root/{prodDir}/src/api/hello/handler.js\n *\n * @param prodDir 产物目录(dist 或 .faapi/dev)\n */\nexport function remapManifestKeys(\n manifest: SchemaManifest,\n rootDir: string,\n prodDir: string,\n): SchemaManifest {\n const remapped: SchemaManifest = new Map();\n const rootPrefix = rootDir + path.sep;\n for (const [filePath, fileSchemas] of manifest) {\n // 绝对路径 → 相对路径(src/api/hello/handler.ts)\n let rel = filePath;\n if (filePath.startsWith(rootPrefix)) {\n rel = filePath.slice(rootPrefix.length);\n } else if (filePath.startsWith(rootDir)) {\n rel = filePath.slice(rootDir.length).replace(/^[/\\\\]/, '');\n }\n // .ts → .js,加 prodDir 前缀,再转回绝对路径(与 createServer 里的 absoluteFilePath 一致)\n const prodRel = `${prodDir}/${rel.replace(/\\.ts$/, '.js')}`;\n const prodAbs = path.resolve(rootDir, prodRel);\n remapped.set(prodAbs, fileSchemas);\n }\n return remapped;\n}\n\n/**\n * 加载 schema 文件并注册到 schemaRegistry(dev/start 共用)\n *\n * 流程:readManifestFile(cache bust) → [可选] remapManifestKeys(源码路径→产物路径) → schemaRegistry.loadManifest\n *\n * @param schemaPath schema JS 模块路径\n * @param rootDir 项目根目录\n * @param prodDir 产物目录(dist 或 .faapi/dev)\n * @param remap 是否重写 key(start 模式需要,dev 模式不需要)\n * - start:route.filePath 是产物路径(dist/...js),schema key 需 remap 为产物路径\n * - dev:route.filePath 是源码路径(src/...ts),schema key 保持源码路径即可\n */\nexport async function loadSchemaToRegistry(\n schemaPath: string,\n rootDir: string,\n prodDir: string,\n remap: boolean = true,\n): Promise<SchemaManifest> {\n const manifest = await readManifestFile(schemaPath);\n const finalManifest = remap ? remapManifestKeys(manifest, rootDir, prodDir) : manifest;\n schemaRegistry.loadManifest(finalManifest);\n return finalManifest;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { RouteManifest, WsRouteManifest, RouteRecord, WsRouteRecord } from '../router/routeTypes';\nimport type { HttpMethod } from '../router/constants';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport {\n loadMiddlewaresFile,\n getCachedMiddlewares,\n setCachedMiddlewares,\n} from '../middleware/loadMiddlewares';\nimport type { LoadedMiddlewareBundle } from '../middleware/loadMiddlewares';\n\n/**\n * 序列化路由记录(可写入 JS 模块,无函数引用)\n *\n * build 时生成,start 时读取。filePath/middlewarePaths 已转为 prd 形式(prodDir 前缀 + .js)。\n */\nexport interface SerializedRouteRecord {\n method: HttpMethod;\n urlPath: string;\n filePath: string;\n paramNames: string[];\n isDynamic: boolean;\n isCatchAll?: boolean;\n /** 从根到路由目录的中间件文件绝对路径列表(已排序,根在前) */\n middlewarePaths: string[];\n}\n\nexport interface SerializedWsRouteRecord {\n urlPath: string;\n filePath: string;\n paramNames: string[];\n isDynamic: boolean;\n isCatchAll?: boolean;\n middlewarePaths: string[];\n}\n\nexport interface SerializedRouteManifest {\n routes: SerializedRouteRecord[];\n wsRoutes: SerializedWsRouteRecord[];\n}\n\n/**\n * 把源码 filePath(src/api/hello/handler.ts)转为产物路径(dist/src/api/hello/handler.js)\n *\n * @param filePath 源码相对路径\n * @param prodDir 产物目录(dist 或 .faapi/dev)\n */\nfunction toProdFilePath(filePath: string, prodDir: string): string {\n const jsPath = filePath.replace(/\\.ts$/, '.js');\n return jsPath.startsWith(`${prodDir}/`) ? jsPath : `${prodDir}/${jsPath}`;\n}\n\n/**\n * 序列化路由清单为可写入 JS 模块的结构\n *\n * - filePath 转为产物路径(prodDir 前缀 + .js)\n * - middlewares/injectors 不序列化(函数无法序列化),改为 middlewarePaths(中间件文件绝对路径列表)\n * - middlewarePaths 已排序(根在前,路由目录在后),start 时按序加载即可还原洋葱模型\n *\n * @param rootDir 项目根目录\n * @param prodDir 产物目录(dist 或 .faapi/dev),用于转换 filePath 和查找中间件\n */\nexport function serializeRoutes(\n routes: RouteManifest,\n wsRoutes: WsRouteManifest,\n rootDir: string,\n prodDir: string = 'dist',\n): SerializedRouteManifest {\n const serialize = <T extends RouteRecord | WsRouteRecord>(\n route: T,\n ): T extends RouteRecord ? SerializedRouteRecord : SerializedWsRouteRecord => {\n const middlewarePaths = extractMiddlewarePaths(route.filePath, rootDir, prodDir);\n const serialized = {\n urlPath: route.urlPath,\n filePath: toProdFilePath(route.filePath, prodDir),\n paramNames: route.paramNames,\n isDynamic: route.isDynamic,\n isCatchAll: route.isCatchAll,\n middlewarePaths,\n };\n if ('method' in route) {\n (serialized as SerializedRouteRecord).method = (route as RouteRecord).method;\n }\n return serialized as T extends RouteRecord ? SerializedRouteRecord : SerializedWsRouteRecord;\n };\n\n return {\n routes: routes.map(serialize) as SerializedRouteRecord[],\n wsRoutes: wsRoutes.map(serialize) as SerializedWsRouteRecord[],\n };\n}\n\n/**\n * 从路由文件路径,向上查找所有中间件文件绝对路径(根在前,路由目录在后)\n *\n * 与 scanRoutes.findMergedMiddlewares 的收集逻辑一致,但只返回路径不加载。\n * 检查源码形式(.ts)中间件文件是否存在,返回产物形式(.js)绝对路径。\n *\n * @param routeFilePath 源码相对路径(如 src/api/hello/handler.ts)\n * @param rootDir 项目根目录\n * @param prodDir 产物目录(dist 或 .faapi/dev)\n */\nfunction extractMiddlewarePaths(\n routeFilePath: string,\n rootDir: string,\n prodDir: string,\n): string[] {\n const routeDir = path.dirname(routeFilePath);\n const resolvedRoot = path.resolve(rootDir);\n\n const paths: string[] = [];\n let currentDir = path.resolve(rootDir, routeDir);\n while (true) {\n // 检查源码 middlewares.ts 是否存在,回退 middlewares.js(prd 残留场景)\n const mwTsPath = path.join(currentDir, 'middlewares.ts');\n const mwJsPath = path.join(currentDir, 'middlewares.js');\n const absTsPath = path.resolve(rootDir, mwTsPath);\n const absJsPath = path.resolve(rootDir, mwJsPath);\n const absMwPath = fs.existsSync(absTsPath) ? absTsPath : fs.existsSync(absJsPath) ? absJsPath : null;\n if (absMwPath) {\n // 转为产物形式绝对路径\n const relMwPath = path.relative(rootDir, absMwPath);\n const prodAbsPath = path.resolve(rootDir, toProdFilePath(relMwPath, prodDir));\n paths.push(prodAbsPath);\n }\n if (currentDir === resolvedRoot) break;\n // 不超出 appDir 目录(避免向上查到非源码目录)\n // appDir 通常是 src,到达 src 的父目录(rootDir)时停止\n const parentDir = path.dirname(currentDir);\n if (parentDir === currentDir) break;\n currentDir = parentDir;\n }\n\n // paths 是从路由目录向上收集的,需反转为根在前\n paths.reverse();\n return paths;\n}\n\n/**\n * 把序列化的路由清单写入 JS 模块\n *\n * 生成 ESM 模块,start 时通过 import() 加载。\n */\nexport async function writeRoutesModule(\n manifest: SerializedRouteManifest,\n outputPath: string,\n): Promise<void> {\n const dir = path.dirname(outputPath);\n await fs.promises.mkdir(dir, { recursive: true });\n\n // 用 JSON.stringify 嵌入,保证字符串转义安全\n const content = `// 自动生成,请勿手动编辑(faapi build 产物)\nexport const routes = ${JSON.stringify(manifest.routes, null, 2)};\nexport const wsRoutes = ${JSON.stringify(manifest.wsRoutes, null, 2)};\n`;\n\n await fs.promises.writeFile(outputPath, content, 'utf-8');\n}\n\n/**\n * 从序列化清单水合路由(加载中间件,还原 RouteRecord)\n *\n * start 时调用,对每条路由按 middlewarePaths 加载中间件文件。\n */\nexport async function hydrateRoutes(\n manifest: SerializedRouteManifest,\n): Promise<{ routes: RouteManifest; wsRoutes: WsRouteManifest }> {\n const hydrateRoute = async (\n serialized: SerializedRouteRecord,\n ): Promise<RouteRecord> => {\n const bundle = await loadMiddlewarePaths(serialized.middlewarePaths);\n return {\n method: serialized.method,\n urlPath: serialized.urlPath,\n filePath: serialized.filePath,\n paramNames: serialized.paramNames,\n isDynamic: serialized.isDynamic,\n isCatchAll: serialized.isCatchAll,\n middlewares: bundle?.middlewares,\n injectors: bundle?.injectors,\n };\n };\n\n const hydrateWsRoute = async (\n serialized: SerializedWsRouteRecord,\n ): Promise<WsRouteRecord> => {\n const bundle = await loadMiddlewarePaths(serialized.middlewarePaths);\n return {\n urlPath: serialized.urlPath,\n filePath: serialized.filePath,\n paramNames: serialized.paramNames,\n isDynamic: serialized.isDynamic,\n isCatchAll: serialized.isCatchAll,\n middlewares: bundle?.middlewares,\n injectors: bundle?.injectors,\n };\n };\n\n const routes = await Promise.all(manifest.routes.map(hydrateRoute));\n const wsRoutes = await Promise.all(manifest.wsRoutes.map(hydrateWsRoute));\n return { routes, wsRoutes };\n}\n\n/**\n * 按路径列表加载并合并中间件(根在前,路由目录在后)\n *\n * 与 scanRoutes.findMergedMiddlewares 的合并逻辑一致:\n * - 中间件:父级在前,子级追加在后(洋葱模型内层)\n * - 注入器:子级覆盖父级同名\n */\nasync function loadMiddlewarePaths(\n middlewarePaths: string[],\n): Promise<{ middlewares: FaapiMiddleware[]; injectors: InjectorMap } | undefined> {\n if (middlewarePaths.length === 0) return undefined;\n\n const mergedMiddlewares: FaapiMiddleware[] = [];\n const mergedInjectors: InjectorMap = {};\n\n for (const absMwPath of middlewarePaths) {\n let bundle: LoadedMiddlewareBundle | undefined = getCachedMiddlewares(absMwPath);\n if (bundle === undefined) {\n bundle = await loadMiddlewaresFile(absMwPath);\n setCachedMiddlewares(absMwPath, bundle);\n }\n mergedMiddlewares.push(...bundle.middlewares);\n for (const [name, injector] of Object.entries(bundle.injectors)) {\n mergedInjectors[name] = injector;\n }\n }\n\n return { middlewares: mergedMiddlewares, injectors: mergedInjectors };\n}\n","import ts from 'typescript';\nimport path from 'node:path';\nimport fs from 'node:fs';\n\n/**\n * tsconfig paths 别名配置(已规范化为绝对路径)\n *\n * - baseUrl:绝对路径(无 baseUrl 时为 tsconfig 所在目录)\n * - paths:pattern -> 绝对路径数组(保留 * 通配符,供 resolveAlias 替换)\n */\nexport interface TsconfigPathsConfig {\n baseUrl: string;\n paths: Record<string, string[]>;\n}\n\n/**\n * 读取项目 tsconfig.json,提取 baseUrl + paths,规范化为绝对路径配置\n *\n * 用 TypeScript Compiler API 解析(处理注释、extends 合并)。\n * 仅读取 rootDir 下的 tsconfig.json,不向上递归查找。\n * 无 paths 时返回 null。\n */\nexport function readTsconfig(rootDir: string): TsconfigPathsConfig | null {\n const tsconfigPath = path.resolve(rootDir, 'tsconfig.json');\n if (!fs.existsSync(tsconfigPath)) return null;\n\n const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n if (configFile.error || !configFile.config) return null;\n\n // parseJsonConfigFileContent 处理 extends 合并、解析 baseUrl 为绝对路径\n const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, rootDir);\n\n // baseUrl:parseJsonConfigFileContent 已解析为绝对路径;未设置时回退到 rootDir\n const baseUrl = parsed.options.baseUrl ?? rootDir;\n\n const rawPaths = parsed.options.paths;\n if (!rawPaths) return null;\n\n // paths 目标:原始字符串相对 baseUrl,解析为绝对路径(保留 *)\n const paths: Record<string, string[]> = {};\n for (const [pattern, targets] of Object.entries(rawPaths)) {\n paths[pattern] = targets.map((t) => path.resolve(baseUrl, t));\n }\n\n return { baseUrl, paths };\n}\n","import type { TsconfigPathsConfig } from './readTsconfig';\n\n/**\n * 按 tsconfig paths 配置把 import specifier 解析为候选绝对路径\n *\n * 纯函数,不检查文件存在性。调用方需自行尝试 .ts/.js/index 等后缀。\n * 支持精确匹配(无 *)和单个 * 通配匹配。\n */\nexport function resolveAlias(specifier: string, config: TsconfigPathsConfig): string[] {\n const candidates: string[] = [];\n\n for (const [pattern, targets] of Object.entries(config.paths)) {\n const wildcardIndex = pattern.indexOf('*');\n\n if (wildcardIndex === -1) {\n // 精确匹配\n if (specifier === pattern) {\n candidates.push(...targets);\n }\n continue;\n }\n\n // 通配匹配:按 * 分割为 prefix / suffix\n const prefix = pattern.slice(0, wildcardIndex);\n const suffix = pattern.slice(wildcardIndex + 1);\n\n if (\n specifier.startsWith(prefix) &&\n specifier.endsWith(suffix) &&\n specifier.length >= prefix.length + suffix.length\n ) {\n const captured = specifier.slice(prefix.length, specifier.length - suffix.length);\n for (const target of targets) {\n candidates.push(target.replace('*', captured));\n }\n }\n }\n\n return candidates;\n}\n","import { readTsconfig } from '../utils/readTsconfig';\nimport { resolveAlias } from '../utils/resolveAlias';\nimport type { TsconfigPathsConfig } from '../utils/readTsconfig';\nimport type { Plugin } from 'esbuild';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport fg from 'fast-glob';\n\n/**\n * 编译选项\n */\nexport interface CompileOptions {\n /** 项目根目录 */\n rootDir: string;\n /** app 目录前缀(如 src) */\n appDir: string;\n /** 输出目录(如 .faapi/dev 或 dist) */\n outDir: string;\n /**\n * 增量编译:传入要编译的文件列表(绝对路径)。\n * 不传则全量编译 appDir 下所有 .ts(排除测试文件和声明文件)。\n */\n files?: string[];\n /** 是否输出 esbuild 日志(dev 模式静默,build 模式输出) */\n logLevel?: 'silent' | 'info';\n}\n\n/**\n * 编译结果\n */\nexport interface CompileResult {\n /** 已编译的文件列表(绝对路径) */\n compiledFiles: string[];\n}\n\n/**\n * 源文件后缀 → 产物后缀映射\n *\n * .ts/.tsx/.jsx → .js;.mjs/.cjs/.js 保持。\n */\nfunction toProdExtension(filePath: string): string {\n if (filePath.endsWith('.ts')) return filePath.slice(0, -3) + '.js';\n if (filePath.endsWith('.tsx')) return filePath.slice(0, -4) + '.js';\n if (filePath.endsWith('.jsx')) return filePath.slice(0, -4) + '.js';\n return filePath;\n}\n\n/**\n * 把候选源文件路径转为产物 import 路径(相对 importer,POSIX 风格,带 .js 后缀)\n */\nfunction toProdImportPath(sourceFile: string, importer: string): string {\n const importerDir = path.dirname(importer);\n let rel = path.relative(importerDir, sourceFile);\n rel = rel.split(path.sep).join('/');\n if (!rel.startsWith('.')) rel = './' + rel;\n return toProdExtension(rel);\n}\n\n/**\n * esbuild 别名重写插件\n *\n * `bundle: false` 模式下 esbuild 不递归解析依赖(onResolve 不触发),\n * 因此改用 onLoad:读取源文件后,把 import/export 中的别名 specifier\n * 替换为产物相对路径(.js 后缀),再交给 esbuild 转译。运行时无需 loader。\n *\n * 覆盖的 import 形式:\n * - `import { x } from 'alias'`\n * - `export { x } from 'alias'`\n * - `import('alias')`(动态)\n *\n * 相对路径 / 绝对路径 / file: URL / node: 协议不处理,交 esbuild 默认。\n */\nfunction createAliasPlugin(config: TsconfigPathsConfig): Plugin {\n const EXTS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];\n const INDEX_EXTS = [\n '/index.ts',\n '/index.tsx',\n '/index.js',\n '/index.jsx',\n '/index.mjs',\n '/index.cjs',\n ];\n // 匹配 from '...' / from \"...\" 和 import('...') / import(\"...\")\n const SPEC_RE = /(\\bfrom\\s*|import\\s*\\(\\s*)(['\"])([^'\"]+)\\2/g;\n return {\n name: 'faapi-alias',\n setup(build) {\n build.onLoad({ filter: /\\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {\n let source: string;\n try {\n source = fs.readFileSync(args.path, 'utf8');\n } catch {\n return undefined;\n }\n const importer = args.path;\n let modified = false;\n const newSource = source.replace(SPEC_RE, (full, prefix, quote, specifier) => {\n if (\n specifier.startsWith('.') ||\n specifier.startsWith('/') ||\n specifier.startsWith('file:') ||\n specifier.startsWith('node:')\n ) {\n return full;\n }\n const candidates = resolveAlias(specifier, config);\n for (const candidate of candidates) {\n for (const ext of EXTS) {\n const file = candidate + ext;\n if (fs.existsSync(file)) {\n modified = true;\n return `${prefix}${quote}${toProdImportPath(file, importer)}${quote}`;\n }\n }\n for (const indexExt of INDEX_EXTS) {\n const file = candidate + indexExt;\n if (fs.existsSync(file)) {\n modified = true;\n return `${prefix}${quote}${toProdImportPath(file, importer)}${quote}`;\n }\n }\n }\n return full;\n });\n if (!modified) return undefined;\n return { contents: newSource, loader: 'default' };\n });\n },\n };\n}\n\n/**\n * 编译 TypeScript 文件到指定目录\n *\n * 使用 esbuild 逐文件编译(不 bundle),保持目录结构,\n * 这样运行时动态 import 的文件路径在编译后仍然有效。\n * 别名在编译时重写为相对路径,运行时无需 loader。\n *\n * @example\n * // dev:编译到 .faapi/dev/\n * await compileRoutes({ rootDir, appDir: 'src', outDir: '.faapi/dev' });\n * // build:编译到 dist/\n * await compileRoutes({ rootDir, appDir: 'src', outDir: 'dist', logLevel: 'info' });\n * // watch 增量:只编译变化的文件\n * await compileRoutes({ rootDir, appDir: 'src', outDir: '.faapi/dev', files: changedFiles });\n */\nexport async function compileRoutes(options: CompileOptions): Promise<CompileResult> {\n const { rootDir, appDir, outDir, files, logLevel = 'silent' } = options;\n\n // 收集要编译的 .ts 文件\n // 全量编译时扫描整个 appDir(覆盖路由、中间件、别名引用的依赖文件)\n // 增量编译时直接使用传入的文件列表\n const allFiles =\n files ??\n (await fg([`${appDir}/**/*.ts`], {\n cwd: rootDir,\n onlyFiles: true,\n absolute: true,\n ignore: ['**/*.test.ts', '**/*.e2e.test.ts', '**/*.d.ts'],\n }));\n\n if (allFiles.length === 0) {\n return { compiledFiles: [] };\n }\n\n // 确保输出目录存在\n const absOutDir = path.resolve(rootDir, outDir);\n await fs.promises.mkdir(absOutDir, { recursive: true });\n\n // 读取 tsconfig paths,构造别名重写插件(无 tsconfig/paths 时为空)\n const tsconfig = readTsconfig(rootDir);\n const plugins = tsconfig ? [createAliasPlugin(tsconfig)] : [];\n\n // 逐文件编译,保持目录结构(outbase 保证相对路径)\n const esbuild = await import('esbuild');\n await esbuild.build({\n entryPoints: allFiles,\n outdir: absOutDir,\n outbase: rootDir,\n bundle: false,\n platform: 'node',\n format: 'esm',\n sourcemap: true,\n packages: 'external',\n plugins,\n logLevel,\n });\n\n return { compiledFiles: allFiles };\n}\n\n/**\n * 扫描 appDir 下的所有 .ts 文件(排除测试文件和声明文件)\n *\n * 用于全量编译和 watch 监听。\n */\nexport async function collectSourceFiles(rootDir: string, appDir: string): Promise<string[]> {\n return fg([`${appDir}/**/*.ts`], {\n cwd: rootDir,\n onlyFiles: true,\n absolute: true,\n ignore: ['**/*.test.ts', '**/*.e2e.test.ts', '**/*.d.ts'],\n });\n}\n","import { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { detectRouteConflicts } from '../router/detectRouteConflicts';\nimport { generateTypes } from './generateTypes';\nimport { generateSchemaFile } from './generateSchema';\nimport { serializeRoutes, writeRoutesModule } from './generateRoutes';\nimport { compileRoutes } from './compileRoutes';\nimport path from 'node:path';\n\n/**\n * 构建命令选项\n */\nexport interface BuildOptions {\n rootDir: string; // 项目根目录\n patterns: string[]; // 路由模式(源码 .ts)\n appDir: string; // app 目录\n outdir: string; // 输出目录\n types?: string; // 类型文件输出路径\n}\n\n/**\n * 执行构建命令\n *\n * 参考 Next.js 实现:先编译 `.ts` 到中间产物(`dist/`),再扫描路由。\n * 运行时只加载 `.js` 产物,不依赖 tsx。\n *\n * 流程:\n * 1. 编译 TypeScript(esbuild:src 下所有 .ts → dist 下对应 .js,含别名重写)\n * 2. 扫描路由(从 dist/ 产物,import .js 拿方法名)\n * 3. 生成类型文件\n * 4. 生成 schema 模块(AST 从源码 .ts)\n * 5. 生成路由清单\n */\nexport async function buildCommand(options: BuildOptions): Promise<void> {\n const { rootDir, patterns, appDir, outdir, types } = options;\n\n console.log('faapi build started');\n console.log(`- Root: ${rootDir}`);\n console.log(`- Patterns: ${patterns.join(', ')}`);\n console.log(`- Output: ${outdir}`);\n\n // 1. 编译 TypeScript(src/**/*.ts → dist/**/*.js)\n console.log('\\n[1/5] Compiling TypeScript...');\n const result = await compileRoutes({ rootDir, appDir, outDir: outdir, logLevel: 'silent' });\n console.log(` Compiled ${result.compiledFiles.length} file(s)`);\n\n // 2. 扫描路由(扫描源码 .ts 文件列表,但 import 产物 .js 拿方法名)\n console.log('\\n[2/5] Scanning routes...');\n const { routes, wsRoutes } = await scanRoutes(rootDir, patterns, appDir, outdir);\n const sorted = sortRoutes(routes);\n console.log(` Found ${sorted.length} routes, ${wsRoutes.length} WS routes`);\n\n // 检测路由冲突\n const conflicts = detectRouteConflicts(sorted);\n if (conflicts.length > 0) {\n console.warn('! 检测到路由冲突:');\n for (const conflict of conflicts) {\n console.warn(` ${conflict.method} ${conflict.urlPath}`);\n for (const file of conflict.files) {\n console.warn(` - ${file}`);\n }\n }\n }\n\n // 3. 生成类型文件\n console.log('\\n[3/5] Generating types...');\n const typesPath = types ? path.resolve(rootDir, types) : path.resolve(rootDir, 'faapi-types.ts');\n await generateTypes(sorted, rootDir, typesPath);\n console.log(` Written to ${typesPath}`);\n\n // 4. 生成 schema 模块(prd 运行时类型校验的数据来源)\n console.log('\\n[4/5] Generating schema module...');\n const schemaPath = path.resolve(rootDir, outdir, 'faapi-schema.js');\n await generateSchemaFile(sorted, rootDir, schemaPath);\n console.log(` Written to ${schemaPath}`);\n\n // 5. 生成路由清单(prd 启动时直接读取,不再 scanRoutes)\n console.log('\\n[5/5] Generating routes manifest...');\n const routesPath = path.resolve(rootDir, outdir, 'faapi-routes.js');\n const serialized = serializeRoutes(sorted, wsRoutes, rootDir, outdir);\n await writeRoutesModule(serialized, routesPath);\n console.log(` Written to ${routesPath}`);\n\n console.log('\\nfaapi build completed');\n}\n\n/**\n * 解析构建命令参数\n */\nexport function parseBuildArgs(argv: string[]): BuildOptions {\n const rootDir = process.cwd();\n let outdir = 'dist';\n let appDir = 'src';\n let types: string | undefined;\n const patterns: string[] = [];\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--outdir' || arg === '-o') {\n outdir = argv[++i];\n } else if (arg === '--app-dir') {\n appDir = argv[++i];\n } else if (arg === '--types') {\n types = argv[++i];\n } else if (!arg.startsWith('-')) {\n patterns.push(arg);\n }\n }\n\n // 默认扫描 <appDir>/api/**/*.ts(与 parseArgs 保持一致)\n // --app-dir . 时为 api/**/*.ts\n const defaultPattern = appDir === '.' ? 'api/**/*.ts' : `${appDir}/api/**/*.ts`;\n\n return {\n rootDir,\n patterns: patterns.length > 0 ? patterns : [defaultPattern],\n appDir,\n outdir,\n types,\n };\n}\n","import { EventEmitter } from 'events';\n\nfunction toArr(any) {\n\treturn any == null ? [] : Array.isArray(any) ? any : [any];\n}\n\nfunction toVal(out, key, val, opts) {\n\tvar x, old=out[key], nxt=(\n\t\t!!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))\n\t\t: typeof val === 'boolean' ? val\n\t\t: !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))\n\t\t: (x = +val,x * 0 === 0) ? x : val\n\t);\n\tout[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);\n}\n\nfunction mri2 (args, opts) {\n\targs = args || [];\n\topts = opts || {};\n\n\tvar k, arr, arg, name, val, out={ _:[] };\n\tvar i=0, j=0, idx=0, len=args.length;\n\n\tconst alibi = opts.alias !== void 0;\n\tconst strict = opts.unknown !== void 0;\n\tconst defaults = opts.default !== void 0;\n\n\topts.alias = opts.alias || {};\n\topts.string = toArr(opts.string);\n\topts.boolean = toArr(opts.boolean);\n\n\tif (alibi) {\n\t\tfor (k in opts.alias) {\n\t\t\tarr = opts.alias[k] = toArr(opts.alias[k]);\n\t\t\tfor (i=0; i < arr.length; i++) {\n\t\t\t\t(opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (i=opts.boolean.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.boolean[i]] || [];\n\t\tfor (j=arr.length; j-- > 0;) opts.boolean.push(arr[j]);\n\t}\n\n\tfor (i=opts.string.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.string[i]] || [];\n\t\tfor (j=arr.length; j-- > 0;) opts.string.push(arr[j]);\n\t}\n\n\tif (defaults) {\n\t\tfor (k in opts.default) {\n\t\t\tname = typeof opts.default[k];\n\t\t\tarr = opts.alias[k] = opts.alias[k] || [];\n\t\t\tif (opts[name] !== void 0) {\n\t\t\t\topts[name].push(k);\n\t\t\t\tfor (i=0; i < arr.length; i++) {\n\t\t\t\t\topts[name].push(arr[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst keys = strict ? Object.keys(opts.alias) : [];\n\n\tfor (i=0; i < len; i++) {\n\t\targ = args[i];\n\n\t\tif (arg === '--') {\n\t\t\tout._ = out._.concat(args.slice(++i));\n\t\t\tbreak;\n\t\t}\n\n\t\tfor (j=0; j < arg.length; j++) {\n\t\t\tif (arg.charCodeAt(j) !== 45) break; // \"-\"\n\t\t}\n\n\t\tif (j === 0) {\n\t\t\tout._.push(arg);\n\t\t} else if (arg.substring(j, j + 3) === 'no-') {\n\t\t\tname = arg.substring(j + 3);\n\t\t\tif (strict && !~keys.indexOf(name)) {\n\t\t\t\treturn opts.unknown(arg);\n\t\t\t}\n\t\t\tout[name] = false;\n\t\t} else {\n\t\t\tfor (idx=j+1; idx < arg.length; idx++) {\n\t\t\t\tif (arg.charCodeAt(idx) === 61) break; // \"=\"\n\t\t\t}\n\n\t\t\tname = arg.substring(j, idx);\n\t\t\tval = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);\n\t\t\tarr = (j === 2 ? [name] : name);\n\n\t\t\tfor (idx=0; idx < arr.length; idx++) {\n\t\t\t\tname = arr[idx];\n\t\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);\n\t\t\t\ttoVal(out, name, (idx + 1 < arr.length) || val, opts);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (defaults) {\n\t\tfor (k in opts.default) {\n\t\t\tif (out[k] === void 0) {\n\t\t\t\tout[k] = opts.default[k];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (alibi) {\n\t\tfor (k in out) {\n\t\t\tarr = opts.alias[k] || [];\n\t\t\twhile (arr.length > 0) {\n\t\t\t\tout[arr.shift()] = out[k];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn out;\n}\n\nconst removeBrackets = (v) => v.replace(/[<[].+/, \"\").trim();\nconst findAllBrackets = (v) => {\n const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;\n const SQUARE_BRACKET_RE_GLOBAL = /\\[([^\\]]+)\\]/g;\n const res = [];\n const parse = (match) => {\n let variadic = false;\n let value = match[1];\n if (value.startsWith(\"...\")) {\n value = value.slice(3);\n variadic = true;\n }\n return {\n required: match[0].startsWith(\"<\"),\n value,\n variadic\n };\n };\n let angledMatch;\n while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {\n res.push(parse(angledMatch));\n }\n let squareMatch;\n while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {\n res.push(parse(squareMatch));\n }\n return res;\n};\nconst getMriOptions = (options) => {\n const result = {alias: {}, boolean: []};\n for (const [index, option] of options.entries()) {\n if (option.names.length > 1) {\n result.alias[option.names[0]] = option.names.slice(1);\n }\n if (option.isBoolean) {\n if (option.negated) {\n const hasStringTypeOption = options.some((o, i) => {\n return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === \"boolean\";\n });\n if (!hasStringTypeOption) {\n result.boolean.push(option.names[0]);\n }\n } else {\n result.boolean.push(option.names[0]);\n }\n }\n }\n return result;\n};\nconst findLongest = (arr) => {\n return arr.sort((a, b) => {\n return a.length > b.length ? -1 : 1;\n })[0];\n};\nconst padRight = (str, length) => {\n return str.length >= length ? str : `${str}${\" \".repeat(length - str.length)}`;\n};\nconst camelcase = (input) => {\n return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {\n return p1 + p2.toUpperCase();\n });\n};\nconst setDotProp = (obj, keys, val) => {\n let i = 0;\n let length = keys.length;\n let t = obj;\n let x;\n for (; i < length; ++i) {\n x = t[keys[i]];\n t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(\".\") || !(+keys[i + 1] > -1) ? {} : [];\n }\n};\nconst setByType = (obj, transforms) => {\n for (const key of Object.keys(transforms)) {\n const transform = transforms[key];\n if (transform.shouldTransform) {\n obj[key] = Array.prototype.concat.call([], obj[key]);\n if (typeof transform.transformFunction === \"function\") {\n obj[key] = obj[key].map(transform.transformFunction);\n }\n }\n }\n};\nconst getFileName = (input) => {\n const m = /([^\\\\\\/]+)$/.exec(input);\n return m ? m[1] : \"\";\n};\nconst camelcaseOptionName = (name) => {\n return name.split(\".\").map((v, i) => {\n return i === 0 ? camelcase(v) : v;\n }).join(\".\");\n};\nclass CACError extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n if (typeof Error.captureStackTrace === \"function\") {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = new Error(message).stack;\n }\n }\n}\n\nclass Option {\n constructor(rawName, description, config) {\n this.rawName = rawName;\n this.description = description;\n this.config = Object.assign({}, config);\n rawName = rawName.replace(/\\.\\*/g, \"\");\n this.negated = false;\n this.names = removeBrackets(rawName).split(\",\").map((v) => {\n let name = v.trim().replace(/^-{1,2}/, \"\");\n if (name.startsWith(\"no-\")) {\n this.negated = true;\n name = name.replace(/^no-/, \"\");\n }\n return camelcaseOptionName(name);\n }).sort((a, b) => a.length > b.length ? 1 : -1);\n this.name = this.names[this.names.length - 1];\n if (this.negated && this.config.default == null) {\n this.config.default = true;\n }\n if (rawName.includes(\"<\")) {\n this.required = true;\n } else if (rawName.includes(\"[\")) {\n this.required = false;\n } else {\n this.isBoolean = true;\n }\n }\n}\n\nconst processArgs = process.argv;\nconst platformInfo = `${process.platform}-${process.arch} node-${process.version}`;\n\nclass Command {\n constructor(rawName, description, config = {}, cli) {\n this.rawName = rawName;\n this.description = description;\n this.config = config;\n this.cli = cli;\n this.options = [];\n this.aliasNames = [];\n this.name = removeBrackets(rawName);\n this.args = findAllBrackets(rawName);\n this.examples = [];\n }\n usage(text) {\n this.usageText = text;\n return this;\n }\n allowUnknownOptions() {\n this.config.allowUnknownOptions = true;\n return this;\n }\n ignoreOptionDefaultValue() {\n this.config.ignoreOptionDefaultValue = true;\n return this;\n }\n version(version, customFlags = \"-v, --version\") {\n this.versionNumber = version;\n this.option(customFlags, \"Display version number\");\n return this;\n }\n example(example) {\n this.examples.push(example);\n return this;\n }\n option(rawName, description, config) {\n const option = new Option(rawName, description, config);\n this.options.push(option);\n return this;\n }\n alias(name) {\n this.aliasNames.push(name);\n return this;\n }\n action(callback) {\n this.commandAction = callback;\n return this;\n }\n isMatched(name) {\n return this.name === name || this.aliasNames.includes(name);\n }\n get isDefaultCommand() {\n return this.name === \"\" || this.aliasNames.includes(\"!\");\n }\n get isGlobalCommand() {\n return this instanceof GlobalCommand;\n }\n hasOption(name) {\n name = name.split(\".\")[0];\n return this.options.find((option) => {\n return option.names.includes(name);\n });\n }\n outputHelp() {\n const {name, commands} = this.cli;\n const {\n versionNumber,\n options: globalOptions,\n helpCallback\n } = this.cli.globalCommand;\n let sections = [\n {\n body: `${name}${versionNumber ? `/${versionNumber}` : \"\"}`\n }\n ];\n sections.push({\n title: \"Usage\",\n body: ` $ ${name} ${this.usageText || this.rawName}`\n });\n const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;\n if (showCommands) {\n const longestCommandName = findLongest(commands.map((command) => command.rawName));\n sections.push({\n title: \"Commands\",\n body: commands.map((command) => {\n return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;\n }).join(\"\\n\")\n });\n sections.push({\n title: `For more info, run any command with the \\`--help\\` flag`,\n body: commands.map((command) => ` $ ${name}${command.name === \"\" ? \"\" : ` ${command.name}`} --help`).join(\"\\n\")\n });\n }\n let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];\n if (!this.isGlobalCommand && !this.isDefaultCommand) {\n options = options.filter((option) => option.name !== \"version\");\n }\n if (options.length > 0) {\n const longestOptionName = findLongest(options.map((option) => option.rawName));\n sections.push({\n title: \"Options\",\n body: options.map((option) => {\n return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? \"\" : `(default: ${option.config.default})`}`;\n }).join(\"\\n\")\n });\n }\n if (this.examples.length > 0) {\n sections.push({\n title: \"Examples\",\n body: this.examples.map((example) => {\n if (typeof example === \"function\") {\n return example(name);\n }\n return example;\n }).join(\"\\n\")\n });\n }\n if (helpCallback) {\n sections = helpCallback(sections) || sections;\n }\n console.log(sections.map((section) => {\n return section.title ? `${section.title}:\n${section.body}` : section.body;\n }).join(\"\\n\\n\"));\n }\n outputVersion() {\n const {name} = this.cli;\n const {versionNumber} = this.cli.globalCommand;\n if (versionNumber) {\n console.log(`${name}/${versionNumber} ${platformInfo}`);\n }\n }\n checkRequiredArgs() {\n const minimalArgsCount = this.args.filter((arg) => arg.required).length;\n if (this.cli.args.length < minimalArgsCount) {\n throw new CACError(`missing required args for command \\`${this.rawName}\\``);\n }\n }\n checkUnknownOptions() {\n const {options, globalCommand} = this.cli;\n if (!this.config.allowUnknownOptions) {\n for (const name of Object.keys(options)) {\n if (name !== \"--\" && !this.hasOption(name) && !globalCommand.hasOption(name)) {\n throw new CACError(`Unknown option \\`${name.length > 1 ? `--${name}` : `-${name}`}\\``);\n }\n }\n }\n }\n checkOptionValue() {\n const {options: parsedOptions, globalCommand} = this.cli;\n const options = [...globalCommand.options, ...this.options];\n for (const option of options) {\n const value = parsedOptions[option.name.split(\".\")[0]];\n if (option.required) {\n const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));\n if (value === true || value === false && !hasNegated) {\n throw new CACError(`option \\`${option.rawName}\\` value is missing`);\n }\n }\n }\n }\n}\nclass GlobalCommand extends Command {\n constructor(cli) {\n super(\"@@global@@\", \"\", {}, cli);\n }\n}\n\nvar __assign = Object.assign;\nclass CAC extends EventEmitter {\n constructor(name = \"\") {\n super();\n this.name = name;\n this.commands = [];\n this.rawArgs = [];\n this.args = [];\n this.options = {};\n this.globalCommand = new GlobalCommand(this);\n this.globalCommand.usage(\"<command> [options]\");\n }\n usage(text) {\n this.globalCommand.usage(text);\n return this;\n }\n command(rawName, description, config) {\n const command = new Command(rawName, description || \"\", config, this);\n command.globalCommand = this.globalCommand;\n this.commands.push(command);\n return command;\n }\n option(rawName, description, config) {\n this.globalCommand.option(rawName, description, config);\n return this;\n }\n help(callback) {\n this.globalCommand.option(\"-h, --help\", \"Display this message\");\n this.globalCommand.helpCallback = callback;\n this.showHelpOnExit = true;\n return this;\n }\n version(version, customFlags = \"-v, --version\") {\n this.globalCommand.version(version, customFlags);\n this.showVersionOnExit = true;\n return this;\n }\n example(example) {\n this.globalCommand.example(example);\n return this;\n }\n outputHelp() {\n if (this.matchedCommand) {\n this.matchedCommand.outputHelp();\n } else {\n this.globalCommand.outputHelp();\n }\n }\n outputVersion() {\n this.globalCommand.outputVersion();\n }\n setParsedInfo({args, options}, matchedCommand, matchedCommandName) {\n this.args = args;\n this.options = options;\n if (matchedCommand) {\n this.matchedCommand = matchedCommand;\n }\n if (matchedCommandName) {\n this.matchedCommandName = matchedCommandName;\n }\n return this;\n }\n unsetMatchedCommand() {\n this.matchedCommand = void 0;\n this.matchedCommandName = void 0;\n }\n parse(argv = processArgs, {\n run = true\n } = {}) {\n this.rawArgs = argv;\n if (!this.name) {\n this.name = argv[1] ? getFileName(argv[1]) : \"cli\";\n }\n let shouldParse = true;\n for (const command of this.commands) {\n const parsed = this.mri(argv.slice(2), command);\n const commandName = parsed.args[0];\n if (command.isMatched(commandName)) {\n shouldParse = false;\n const parsedInfo = __assign(__assign({}, parsed), {\n args: parsed.args.slice(1)\n });\n this.setParsedInfo(parsedInfo, command, commandName);\n this.emit(`command:${commandName}`, command);\n }\n }\n if (shouldParse) {\n for (const command of this.commands) {\n if (command.name === \"\") {\n shouldParse = false;\n const parsed = this.mri(argv.slice(2), command);\n this.setParsedInfo(parsed, command);\n this.emit(`command:!`, command);\n }\n }\n }\n if (shouldParse) {\n const parsed = this.mri(argv.slice(2));\n this.setParsedInfo(parsed);\n }\n if (this.options.help && this.showHelpOnExit) {\n this.outputHelp();\n run = false;\n this.unsetMatchedCommand();\n }\n if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {\n this.outputVersion();\n run = false;\n this.unsetMatchedCommand();\n }\n const parsedArgv = {args: this.args, options: this.options};\n if (run) {\n this.runMatchedCommand();\n }\n if (!this.matchedCommand && this.args[0]) {\n this.emit(\"command:*\");\n }\n return parsedArgv;\n }\n mri(argv, command) {\n const cliOptions = [\n ...this.globalCommand.options,\n ...command ? command.options : []\n ];\n const mriOptions = getMriOptions(cliOptions);\n let argsAfterDoubleDashes = [];\n const doubleDashesIndex = argv.indexOf(\"--\");\n if (doubleDashesIndex > -1) {\n argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);\n argv = argv.slice(0, doubleDashesIndex);\n }\n let parsed = mri2(argv, mriOptions);\n parsed = Object.keys(parsed).reduce((res, name) => {\n return __assign(__assign({}, res), {\n [camelcaseOptionName(name)]: parsed[name]\n });\n }, {_: []});\n const args = parsed._;\n const options = {\n \"--\": argsAfterDoubleDashes\n };\n const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;\n let transforms = Object.create(null);\n for (const cliOption of cliOptions) {\n if (!ignoreDefault && cliOption.config.default !== void 0) {\n for (const name of cliOption.names) {\n options[name] = cliOption.config.default;\n }\n }\n if (Array.isArray(cliOption.config.type)) {\n if (transforms[cliOption.name] === void 0) {\n transforms[cliOption.name] = Object.create(null);\n transforms[cliOption.name][\"shouldTransform\"] = true;\n transforms[cliOption.name][\"transformFunction\"] = cliOption.config.type[0];\n }\n }\n }\n for (const key of Object.keys(parsed)) {\n if (key !== \"_\") {\n const keys = key.split(\".\");\n setDotProp(options, keys, parsed[key]);\n setByType(options, transforms);\n }\n }\n return {\n args,\n options\n };\n }\n runMatchedCommand() {\n const {args, options, matchedCommand: command} = this;\n if (!command || !command.commandAction)\n return;\n command.checkUnknownOptions();\n command.checkOptionValue();\n command.checkRequiredArgs();\n const actionArgs = [];\n command.args.forEach((arg, index) => {\n if (arg.variadic) {\n actionArgs.push(args.slice(index));\n } else {\n actionArgs.push(args[index]);\n }\n });\n actionArgs.push(options);\n return command.commandAction.apply(this, actionArgs);\n }\n}\n\nconst cac = (name = \"\") => new CAC(name);\n\nexport default cac;\nexport { CAC, Command, cac };\n","/**\n * 将逗号分隔的 pattern 字符串拆分为数组\n * 'api/auth/*,api/novel/*' -> ['api/auth/*', 'api/novel/*']\n * 'api/auth/*' -> ['api/auth/*']\n */\nexport function normalizePatterns(patterns: string[]): string[] {\n return patterns\n .flatMap((p) => p.split(','))\n .map((p) => p.trim())\n .filter((p) => p.length > 0);\n}\n","import { cac } from 'cac';\nimport { normalizePatterns } from './normalizePatterns';\n\nexport type CliMode = 'dev' | 'start';\n\nexport interface CliArgs {\n /** 启动模式:dev=开发模式(加载 .ts),start=生产模式(加载 dist/*.js) */\n mode: CliMode;\n patterns: string[];\n port: number;\n appDir: string;\n cors: boolean;\n staticDir?: string;\n types?: string;\n config?: string;\n}\n\n/** 命令词 → mode 映射 */\nconst COMMAND_MODES: Record<string, CliMode> = {\n dev: 'dev',\n start: 'start',\n};\n\n/**\n * 解析 CLI 参数\n * 支持:\n * - faapi # dev 模式,扫描 src/api 下的 .ts\n * - faapi dev # 同上\n * - faapi start # prd 模式,加载 dist 下的 .js(需先 faapi build)\n * - faapi api/auth/ # 指定 patterns\n * - faapi --port 3000 api/auth/\n * - faapi --app-dir . api/auth/ # 显式回退到项目根目录\n *\n * 端口优先级:--port > PORT 环境变量 > 默认 3000\n */\nexport function parseArgs(argv: string[]): CliArgs {\n const cli = cac('faapi');\n\n cli\n .option('--port <port>', 'Server port (env: PORT)')\n .option('--app-dir <dir>', 'App directory (src by default)', { default: 'src' })\n .option('--cors', 'Enable CORS (default in dev mode)')\n .option('--no-cors', 'Disable CORS')\n .option('--static <dir>', 'Static files directory', { default: undefined })\n .option('--no-static', 'Disable static file serving')\n .option('--types <path>', 'Output path for generated types file')\n .option('--config <path>', 'Path to config file (faapi.config.ts)');\n\n const { args, options } = cli.parse(['', '', ...argv]);\n\n // 第一个非命令词的位置参数为 patterns,其余为命令词\n // 命令词仅 dev/start,其他词(如 'build')由上层 cli/index.ts 分发,不进 parseArgs\n let mode: CliMode = 'dev';\n const rawPatterns: string[] = [];\n for (const arg of args) {\n const str = String(arg);\n if (str in COMMAND_MODES) {\n mode = COMMAND_MODES[str];\n } else {\n rawPatterns.push(str);\n }\n }\n const patterns = normalizePatterns(rawPatterns);\n\n // 端口优先级:--port > PORT 环境变量 > 3000\n const port = options.port ? Number(options.port) : Number(process.env.PORT) || 3000;\n\n const appDir = String(options.appDir ?? 'src');\n\n // CORS: --no-cors 显式禁用,否则默认启用\n const cors = options.cors !== false;\n\n // Static: --no-static 显式禁用,--static <dir> 指定目录\n const staticDir: string | undefined =\n options.static === false ? undefined : (options.static as string | undefined);\n\n // 默认扫描 patterns\n // dev 模式:扫描 <appDir>/api/**/*.ts(--app-dir . 时为 api/**/*.ts)\n // start 模式:加载 dist 下的 .js,由 startCommand.adjustForProd 调整\n const defaultPattern = appDir === '.' ? 'api/**/*.ts' : `${appDir}/api/**/*.ts`;\n\n return {\n mode,\n patterns: patterns.length > 0 ? patterns : [defaultPattern],\n port,\n appDir,\n cors,\n staticDir,\n types: options.types as string | undefined,\n config: options.config as string | undefined,\n };\n}\n","import type { RouteManifest, RouteMatch, WsRouteManifest, WsRouteMatch } from './routeTypes';\n\n/**\n * 根据请求路径和方法匹配路由\n * @param routes 已排序的路由清单\n * @param method HTTP 方法\n * @param path 请求路径\n * @returns 匹配结果,包含路由记录和参数\n */\nexport function matchRoute(routes: RouteManifest, method: string, path: string): RouteMatch | null {\n for (const route of routes) {\n // 方法不匹配,跳过\n if (route.method !== method) {\n continue;\n }\n\n // 静态路由直接比较\n if (!route.isDynamic) {\n if (route.urlPath === path) {\n return { route, params: {} };\n }\n continue;\n }\n\n // 动态路由匹配\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n return { route, params };\n }\n }\n\n return null;\n}\n\n/**\n * 匹配 WebSocket 路由(无 HTTP 方法维度)\n *\n * WS 路由只按路径匹配,协议升级时调用。\n * @param wsRoutes WebSocket 路由清单\n * @param path 请求路径\n */\nexport function matchWsRoute(wsRoutes: WsRouteManifest, path: string): WsRouteMatch | null {\n for (const route of wsRoutes) {\n // 静态路由直接比较\n if (!route.isDynamic) {\n if (route.urlPath === path) {\n return { route, params: {} };\n }\n continue;\n }\n\n // 动态路由匹配\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n return { route, params };\n }\n }\n\n return null;\n}\n\n/**\n * 动态路径匹配\n * 将路由模式(如 /user/:id)与请求路径(如 /user/123)匹配\n * 支持 catch-all 路由(如 /shop/:...slug 匹配 /shop/clothes/tops)\n * 返回提取的参数对象,不匹配返回 null\n */\nexport function matchDynamicPath(\n pattern: string,\n path: string,\n paramNames: string[],\n isCatchAll?: boolean,\n): Record<string, string> | null {\n const patternSegments = pattern.split('/').filter(Boolean);\n const pathSegments = path.split('/').filter(Boolean);\n\n // catch-all 路由:最后一个模式段为 :...slug\n if (isCatchAll) {\n // catch-all 前面的静态/动态段必须匹配\n // catch-all 段至少匹配一个路径段\n const nonCatchAllCount = patternSegments.length - 1;\n if (pathSegments.length <= nonCatchAllCount) {\n return null;\n }\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < nonCatchAllCount; i++) {\n const patternSeg = patternSegments[i];\n const pathSeg = pathSegments[i];\n\n if (patternSeg.startsWith(':')) {\n const paramName = patternSeg.slice(1);\n params[paramName] = pathSeg;\n } else if (patternSeg !== pathSeg) {\n return null;\n }\n }\n\n // catch-all 段:剩余所有路径段用 / 连接\n const catchAllValue = pathSegments.slice(nonCatchAllCount).join('/');\n const catchAllParamName = patternSegments[nonCatchAllCount].slice(4); // 去掉 ':...'\n params[catchAllParamName] = catchAllValue;\n\n if (Object.keys(params).length !== paramNames.length) {\n return null;\n }\n\n return params;\n }\n\n // 普通动态路由:段数必须一致\n if (patternSegments.length !== pathSegments.length) {\n return null;\n }\n\n const params: Record<string, string> = {};\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSeg = patternSegments[i];\n const pathSeg = pathSegments[i];\n\n if (patternSeg.startsWith(':')) {\n // 动态段,提取参数值\n const paramName = patternSeg.slice(1);\n params[paramName] = pathSeg;\n } else if (patternSeg !== pathSeg) {\n // 静态段不匹配\n return null;\n }\n }\n\n // 确保所有参数名都被提取到\n if (Object.keys(params).length !== paramNames.length) {\n return null;\n }\n\n return params;\n}\n","/**\n * 从模块中解析出指定名称的导出\n *\n * 解析顺序:\n * 1. 具名导出:export function GET() {}\n * 2. 默认导出的对象属性:export default { GET() {} }\n *\n * @param module 动态 import 得到的模块对象\n * @param exportName 导出名(如 'GET')\n */\nexport function resolveExport(module: Record<string, unknown>, exportName: string): unknown {\n // 1. 具名导出\n if (exportName in module && typeof module[exportName] !== 'undefined') {\n return module[exportName];\n }\n\n // 2. 默认导出的对象属性\n const defaultExport = module.default;\n if (defaultExport !== null && typeof defaultExport === 'object') {\n const value = (defaultExport as Record<string, unknown>)[exportName];\n if (value !== undefined) {\n return value;\n }\n }\n\n return undefined;\n}\n","/**\n * 校验导出值是否为合法的 handler 函数\n */\nexport function validateRouteModule(\n value: unknown,\n method: string,\n filePath: string,\n): asserts value is (...args: unknown[]) => unknown {\n if (typeof value !== 'function') {\n throw new Error(\n `Route module \"${filePath}\" does not export a valid handler for method \"${method}\". ` +\n `Expected a function, got ${typeof value}.`,\n );\n }\n}\n","import type { HttpMethod } from '../router/constants';\nimport { resolveExport } from './resolveExports';\nimport { validateRouteModule } from './validateRouteModule';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\n\nexport interface RouteModule {\n handler: (...args: unknown[]) => unknown;\n method: HttpMethod;\n}\n\n/**\n * 动态 import 路由文件并提取 handler\n * @param filePath 路由文件的绝对路径\n * @param method HTTP 方法名(也是导出名)\n */\nexport async function loadRouteModule(filePath: string, method: HttpMethod): Promise<RouteModule> {\n let module: Record<string, unknown>;\n try {\n module = await importWithCacheBust(filePath);\n } catch (err: unknown) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load route module \"${filePath}\": ${reason}`, { cause: err });\n }\n\n const handler = resolveExport(module, method);\n validateRouteModule(handler, method, filePath);\n\n return { handler, method };\n}\n","/**\n * SSE(Server-Sent Events)支持\n *\n * 让 handler 能向客户端推送流式事件,用于 LLM token 流、进度通知等场景。\n *\n * 核心导出:\n * - `encodeSseEvent(event)`:把 SSE 事件对象编码为符合 HTML5 SSE 规范的字符串\n * - `createSseWriter()`:创建一个 SseWriter,封装 ReadableStream + Response,提供 send/close/sendError API\n * - `SseWriter`:writer 类型,ctx.sse() 返回此类型\n *\n * 设计要点:\n * - writer 内部用 ReadableStream + TextEncoder,send 时 enqueue,close 时 close controller\n * - response 预设 text/event-stream、no-cache、keep-alive 头,状态码默认 200\n * - close 后再 send 静默忽略,避免 handler 异步流程中误写已关闭的流\n * - sendError 向流写入 event: error 后关闭,用于流式输出中报错的优雅终止\n *\n * 与 ctx 的集成:\n * - ctx.sse() 调用 createSseWriter(),并把 response 缓存到 ctx 内部字段\n * - invokeHandler 在 handler 返回后检查 ctx 是否持有 SSE response,有则优先使用\n */\n\n/**\n * SSE 事件字段\n *\n * 遵循 HTML5 SSE 规范:\n * - `data`:消息数据,多行时每行加 `data: ` 前缀;对象自动 JSON.stringify\n * - `event`:事件类型,客户端可用 addEventListener(event) 监听\n * - `id`:事件 ID,客户端断线重连时通过 Last-Event-ID 头发送\n * - `retry`:重连等待时间(毫秒)\n * - `comment`:注释行(以 `:` 开头),用于 keep-alive 心跳,不传递给客户端消息\n */\nexport interface SseEvent {\n /** 消息数据。字符串原样输出;对象自动 JSON.stringify;多行时每行加 data: 前缀 */\n data?: unknown;\n /** 事件类型,客户端可用 addEventListener 监听 */\n event?: string;\n /** 事件 ID,客户端断线重连时通过 Last-Event-ID 头发送 */\n id?: string | number;\n /** 重连等待时间(毫秒) */\n retry?: number;\n /** 注释行(以 : 开头),用于 keep-alive 心跳 */\n comment?: string;\n}\n\n/**\n * 把 SSE 事件对象编码为符合 HTML5 SSE 规范的字符串\n *\n * 字段顺序固定:comment > event > id > retry > data,末尾空行分隔事件。\n *\n * @param event SSE 事件对象\n * @returns 编码后的字符串(含末尾空行)\n */\nexport function encodeSseEvent(event: SseEvent): string {\n let out = '';\n\n // comment(注释行,以 : 开头)\n if (event.comment !== undefined) {\n out += `: ${event.comment}\\n`;\n }\n\n // event\n if (event.event !== undefined) {\n out += `event: ${event.event}\\n`;\n }\n\n // id\n if (event.id !== undefined) {\n out += `id: ${event.id}\\n`;\n }\n\n // retry\n if (event.retry !== undefined) {\n out += `retry: ${event.retry}\\n`;\n }\n\n // data:对象 JSON.stringify,多行每行加前缀\n if (event.data !== undefined) {\n let dataStr: string;\n if (typeof event.data === 'string') {\n dataStr = event.data;\n } else if (event.data === null) {\n dataStr = 'null';\n } else {\n dataStr = JSON.stringify(event.data);\n }\n // 多行 data:每行加 data: 前缀\n const lines = dataStr.split('\\n');\n for (const line of lines) {\n out += `data: ${line}\\n`;\n }\n }\n\n // 空行结束事件\n out += '\\n';\n return out;\n}\n\n/**\n * SSE writer:封装流式推送 API\n *\n * 通过 `ctx.sse()` 创建,handler 调用 `send` 推送事件,`close` 关闭流。\n * 框架在 handler 返回后,自动使用 writer.response 作为 HTTP 响应。\n */\nexport interface SseWriter {\n /** 推送一个 SSE 事件 */\n send(event: SseEvent): void;\n /** 推送一个 error 事件并关闭流(用于流式输出中报错的优雅终止) */\n sendError(error: unknown): void;\n /** 关闭流(多次调用安全) */\n close(): void;\n /** 流是否已关闭(handler 主动 close 或框架自动 close) */\n readonly closed: boolean;\n /** 客户端是否已断开(ReadableStream 被 cancel) */\n readonly aborted: boolean;\n /** 对应的 HTTP Response(由框架使用,用户一般不需要直接访问) */\n readonly response: Response;\n}\n\n/**\n * 创建一个 SSE writer\n *\n * 内部用 ReadableStream + TextEncoder 实现,send 时把编码后的事件 enqueue 到流,\n * close 时关闭 controller。response 预设标准 SSE 头。\n *\n * aborted 检测:监听 ReadableStream 的 cancel 钩子,客户端断开(cancel)时置为 true。\n * 此时 send 静默忽略,handler 可通过 writer.aborted 退出循环。\n */\nexport function createSseWriter(): SseWriter {\n const encoder = new TextEncoder();\n let controller: ReadableStreamDefaultController<Uint8Array> | null = null;\n let closed = false;\n let aborted = false;\n\n const stream = new ReadableStream<Uint8Array>({\n start(c) {\n controller = c;\n },\n cancel() {\n // 客户端断开连接(cancel ReadableStream)\n aborted = true;\n closed = true;\n controller = null;\n },\n });\n\n const response = new Response(stream, {\n status: 200,\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n },\n });\n\n const writer: SseWriter = {\n send(event: SseEvent): void {\n if (closed || !controller) return;\n const text = encodeSseEvent(event);\n controller.enqueue(encoder.encode(text));\n },\n\n sendError(error: unknown): void {\n if (closed || !controller) return;\n const message = error instanceof Error ? error.message : String(error);\n const text = encodeSseEvent({ event: 'error', data: message });\n try {\n controller.enqueue(encoder.encode(text));\n } finally {\n writer.close();\n }\n },\n\n close(): void {\n if (closed) return;\n closed = true;\n if (controller) {\n try {\n controller.close();\n } catch {\n // controller 可能已关闭,忽略\n }\n controller = null;\n }\n },\n\n get closed(): boolean {\n return closed;\n },\n\n get aborted(): boolean {\n return aborted;\n },\n\n get response(): Response {\n return response;\n },\n };\n\n return writer;\n}\n","import type { FaapiContext, ResponseMeta, CookieOptions } from './contextTypes';\nimport { createSseWriter, type SseWriter } from './sse';\n\n/**\n * 解析 Cookie 请求头为 Map\n */\nfunction parseCookies(cookieHeader: string): Map<string, string> {\n const cookies = new Map<string, string>();\n if (!cookieHeader) return cookies;\n for (const pair of cookieHeader.split(';')) {\n const [name, ...rest] = pair.split('=');\n const trimmed = name?.trim();\n if (trimmed) {\n cookies.set(trimmed, rest.join('=').trim());\n }\n }\n return cookies;\n}\n\n/**\n * 格式化 Set-Cookie 值\n */\nfunction formatSetCookie(name: string, value: string, options?: CookieOptions): string {\n let cookie = `${name}=${value}`;\n if (options?.domain) cookie += `; Domain=${options.domain}`;\n if (options?.path) cookie += `; Path=${options.path}`;\n if (options?.maxAge !== undefined) cookie += `; Max-Age=${options.maxAge}`;\n if (options?.expires) cookie += `; Expires=${options.expires.toUTCString()}`;\n if (options?.httpOnly) cookie += `; HttpOnly`;\n if (options?.secure) cookie += `; Secure`;\n if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;\n return cookie;\n}\n\n/**\n * 从 Request 对象创建 FaapiContext\n * @param request Web Request 对象\n * @param params 动态路由参数\n * @param config 自定义业务配置(来自 faapi.config.ts)\n * @param ip 客户端 IP(由调用方从 IncomingMessage 提取,HTTP/WS 握手均通过 utils/getClientIp)\n */\nexport function createContext(\n request: Request,\n params: Record<string, string>,\n config: Record<string, unknown> = {},\n ip: string = '',\n): FaapiContext {\n const url = new URL(request.url);\n const meta: ResponseMeta = { headers: {}, setCookies: [] };\n const parsedCookies = parseCookies(request.headers.get('cookie') ?? '');\n const cookiesObj: Record<string, string> = {};\n for (const [key, val] of parsedCookies) {\n cookiesObj[key] = val;\n }\n\n const ctx = {\n request,\n params,\n query: url.searchParams,\n headers: request.headers,\n method: request.method,\n path: url.pathname,\n ip,\n cookies: cookiesObj,\n config,\n meta,\n\n setStatus(status: number) {\n meta.status = status;\n },\n\n setHeader(key: string, value: string) {\n meta.headers[key] = value;\n },\n\n redirect(url: string, status = 302): Response {\n return new Response(null, {\n status,\n headers: { Location: url },\n });\n },\n\n json(data: unknown, status?: number): Response {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n return new Response(JSON.stringify(data), {\n status: status ?? 200,\n headers,\n });\n },\n\n html(html: string, status?: number): Response {\n const headers: Record<string, string> = { 'Content-Type': 'text/html; charset=utf-8' };\n return new Response(html, {\n status: status ?? 200,\n headers,\n });\n },\n\n getCookie(name: string): string | undefined {\n return parsedCookies.get(name);\n },\n\n setCookie(name: string, value: string, options?: CookieOptions): void {\n meta.setCookies.push(formatSetCookie(name, value, options));\n },\n\n deleteCookie(name: string): void {\n meta.setCookies.push(formatSetCookie(name, '', { maxAge: 0 }));\n },\n\n /**\n * 创建 SSE writer,用于流式推送事件\n *\n * handler 调用此方法后,通过返回的 writer 推送事件,框架自动把 writer.response\n * 作为 HTTP 响应(Content-Type: text/event-stream)。\n *\n * 与 ctx.json / ctx.html 互斥:一个 handler 只能用一种响应方式。\n */\n sse(): SseWriter {\n const writer = createSseWriter();\n const ctxWithSse = ctx as FaapiContext & {\n __sseResponse?: Response;\n __sseWriter?: SseWriter;\n };\n ctxWithSse.__sseResponse = writer.response;\n ctxWithSse.__sseWriter = writer;\n return writer;\n },\n } as FaapiContext & { meta: ResponseMeta; __sseResponse?: Response; __sseWriter?: SseWriter };\n\n // 执行用户自定义的 ctx 扩展钩子(config.extendContext)\n const extend = config?.extendContext;\n if (typeof extend === 'function') {\n extend(ctx);\n }\n\n return ctx;\n}\n","export function queryToObject(params: URLSearchParams): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of params) {\n result[key] = value;\n }\n return result;\n}\n","export type JsonParseResult = { success: true; data: unknown } | { success: false; error: string };\n\nexport function parseJsonBody(text: string): JsonParseResult {\n try {\n const data = JSON.parse(text);\n return { success: true, data };\n } catch {\n return { success: false, error: 'Invalid JSON body' };\n }\n}\n","/**\n * 解析 multipart/form-data 请求\n * 使用 Web 标准 Request.formData() API\n */\n\nexport interface UploadedFile {\n name: string; // 字段名\n filename: string; // 原始文件名\n type: string; // MIME 类型\n size: number; // 文件大小(字节)\n arrayBuffer: () => Promise<ArrayBuffer>; // 获取文件内容\n}\n\nexport interface MultipartResult {\n /** 表单字段(同名字段用数组收集,单值保持 string) */\n fields: Record<string, string | string[]>;\n files: UploadedFile[];\n}\n\n/**\n * 解析 multipart/form-data\n *\n * 同名字段的处理:\n * - 第一次出现:string\n * - 第二次出现:string[](包含所有同名字段的值)\n * - 文件始终收集到 files 数组(通过 name 字段标识归属)\n */\nexport async function parseMultipart(request: Request): Promise<MultipartResult> {\n const formData = await request.formData();\n const fields: Record<string, string | string[]> = {};\n const files: UploadedFile[] = [];\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n files.push({\n name: key,\n filename: value.name,\n type: value.type,\n size: value.size,\n arrayBuffer: () => value.arrayBuffer(),\n });\n } else {\n // 同名字段收集为数组\n if (key in fields) {\n const existing = fields[key];\n if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n fields[key] = [existing, value];\n }\n } else {\n fields[key] = value;\n }\n }\n }\n\n return { fields, files };\n}\n","import type { ErrorCode } from './errorCodes';\n\nexport class FaapiError extends Error {\n constructor(\n public readonly code: ErrorCode,\n message: string,\n public readonly statusCode: number,\n ) {\n super(message);\n this.name = 'FaapiError';\n }\n}\n","import { FaapiError } from './FaapiError';\n\n/**\n * 根据 issues 中的 code 推导 HTTP 状态码\n *\n * 语义参考 RFC 7807 / Rails / Laravel / Spring:\n * - 400 Bad Request:请求语法错误或结构不完整\n * - INVALID_FORMAT:JSON 格式错误、Date 非 ISO 8601\n * - MISSING_FIELD:缺少必填字段\n * - 422 Unprocessable Entity:请求语法正确但语义错误\n * - TYPE_MISMATCH:类型不匹配(string 期望 number)\n * - INVALID_VALUE:值不在允许范围(字面量/enum 不匹配)\n * - COERCE_FAILED:query 字符串转换失败\n *\n * 多个 issue 时取最高严重度(400 优先于 422)。\n */\nfunction deriveStatusCode(issues: ValidationIssue[]): number {\n // 有 400 类 issue → 400;否则 422\n const has400 = issues.some((i) => i.code === 'INVALID_FORMAT' || i.code === 'MISSING_FIELD');\n return has400 ? 400 : 422;\n}\n\nexport class ValidationError extends FaapiError {\n constructor(\n message: string,\n public readonly issues: ValidationIssue[],\n ) {\n super('VALIDATION_ERROR', message, deriveStatusCode(issues));\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends FaapiError {\n constructor(path: string) {\n super('ROUTE_NOT_FOUND', `Route not found: ${path}`, 404);\n this.name = 'RouteNotFoundError';\n }\n}\n\nexport class MethodNotAllowedError extends FaapiError {\n constructor(\n method: string,\n path: string,\n public readonly allowedMethods: string[],\n ) {\n super('METHOD_NOT_ALLOWED', `Method ${method} not allowed for ${path}`, 405);\n this.name = 'MethodNotAllowedError';\n }\n}\n\nexport class InternalError extends FaapiError {\n constructor(message: string) {\n super('INTERNAL_ERROR', message, 500);\n this.name = 'InternalError';\n }\n}\n\nexport class ModuleLoadError extends FaapiError {\n constructor(filePath: string, reason: string) {\n super('MODULE_LOAD_ERROR', `Failed to load module ${filePath}: ${reason}`, 500);\n this.name = 'ModuleLoadError';\n }\n}\n\n/**\n * 校验问题类型\n *\n * 结构化错误信息,便于上层(errorFormat/前端)按 code 做不同处理,\n * 不依赖字符串解析。message 仅为人类可读的兜底描述。\n *\n * code 与 HTTP 状态码的映射(由 ValidationError 推导):\n * - INVALID_FORMAT / MISSING_FIELD → 400 Bad Request\n * - TYPE_MISMATCH / INVALID_VALUE / COERCE_FAILED → 422 Unprocessable Entity\n */\nexport interface ValidationIssue {\n /** 字段路径,如 'user.address.city' */\n path: string;\n /** 错误码,机器可读的契约 */\n code: ValidationErrorCode;\n /** 期望类型/值,如 'number' / '\"admin\" | \"user\"' */\n expected: string;\n /** 实际类型/值,如 'string' / 'undefined' */\n received: string;\n /** 人类可读的本地化消息(兜底,不保证稳定) */\n message: string;\n}\n\nexport type ValidationErrorCode =\n | 'TYPE_MISMATCH' // 类型不匹配(string 期望 number) → 422\n | 'MISSING_FIELD' // 缺少必填字段 → 400\n | 'INVALID_FORMAT' // 格式错误(JSON 解析失败、Date 非 ISO 等) → 400\n | 'INVALID_VALUE' // 值不在允许范围(字面量/enum 不匹配) → 422\n | 'COERCE_FAILED'; // 类型转换失败(query 字符串转 number/boolean 失败) → 422\n","import { queryToObject } from '../utils/queryToObject';\nimport { parseJsonBody } from '../utils/parseJsonBody';\nimport { parseMultipart } from '../utils/parseMultipart';\nimport { getInputTypeForMethod } from './inputType';\nimport { ValidationError } from '../errors/httpErrors';\n\n/**\n * 根据 HTTP 方法解析主输入\n *\n * - GET / DELETE / HEAD:主输入是 query(URL 查询参数)\n * - POST / PUT / PATCH:主输入是 body(请求体)\n *\n * 注意:DELETE 也可能有 body,但主输入(用于校验)是 query。\n * body 通过 injectParams 单独注入。\n *\n * HTTP 传输语义:\n * - 空请求体(或纯空白)视为无 body,返回 null(handler 可不声明 body 参数)\n * - 请求体非空但 JSON 格式非法,抛 ValidationError(code=INVALID_FORMAT),\n * 不再静默返回 null 导致后续报\"字段缺失\"\n *\n * @param method HTTP 方法\n * @param request Request 对象\n * @returns 解析后的输入值(query 对象或 body 对象)\n * @throws {ValidationError} 当请求体非空但 JSON 格式非法时\n */\nexport async function resolveInput(method: string, request: Request): Promise<unknown> {\n const inputType = getInputTypeForMethod(method);\n\n // 主输入是 body 的方法:解析请求体\n if (inputType === 'body') {\n const contentType = request.headers.get('content-type') ?? '';\n\n // multipart/form-data:字段 + 文件\n if (contentType.includes('multipart/form-data')) {\n return parseMultipart(request);\n }\n\n // application/x-www-form-urlencoded:表单字段\n if (contentType.includes('application/x-www-form-urlencoded')) {\n const text = await request.text();\n if (text.trim() === '') return null;\n const params = new URLSearchParams(text);\n const obj: Record<string, string> = {};\n for (const [key, value] of params) {\n obj[key] = value;\n }\n return obj;\n }\n\n // 默认按 JSON 解析(application/json 及其它未明确类型)\n const text = await request.text();\n\n // 空请求体:视为无 body(handler 可不声明 body 参数)\n if (text.trim() === '') {\n return null;\n }\n\n // 非空请求体:必须能解析为 JSON,否则是格式错误\n const result = parseJsonBody(text);\n if (!result.success) {\n throw new ValidationError('请求体不是合法的 JSON', [\n {\n path: 'body',\n code: 'INVALID_FORMAT',\n expected: 'JSON',\n received: 'text',\n message: '请求体不是合法的 JSON',\n },\n ]);\n }\n return result.data;\n }\n\n // 主输入是 query 的方法(GET / DELETE / HEAD):从 URL 提取 query\n const url = new URL(request.url);\n return queryToObject(url.searchParams);\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n // 数组不是普通对象\n if (Array.isArray(value)) {\n return false;\n }\n\n // 检查原型链:普通对象的 prototype 是 Object.prototype 或 null(Object.create(null))\n const proto = Object.getPrototypeOf(value);\n return proto === null || proto === Object.prototype;\n}\n","import { isPlainObject } from '../utils/isPlainObject';\nimport type { ResponseMeta } from '../runtime/contextTypes';\n\n/**\n * 将 handler 返回值统一转换为 Response\n *\n * 规则:\n * - Response 对象:原样返回\n * - ReadableStream:直接作为 body\n * - Buffer / Uint8Array:作为二进制 body\n * - 普通对象/数组:JSON.stringify,Content-Type: application/json\n * - string:text/plain\n * - number/boolean:text/plain,String(value)\n * - null/undefined:204 No Content\n * - Promise:await 后再处理\n *\n * 如果传入了 meta,会将 ctx.setStatus / ctx.setHeader 的设置合并到 Response 中\n */\nexport async function toResponse(value: unknown, meta?: ResponseMeta): Promise<Response> {\n // Promise:await 后再处理\n if (value instanceof Promise) {\n return toResponse(await value, meta);\n }\n\n // 辅助函数:将 meta headers 和 setCookies 合并到 Headers 对象\n const applyMeta = (headers: Headers): void => {\n if (!meta) return;\n for (const [key, val] of Object.entries(meta.headers)) {\n headers.set(key, val);\n }\n for (const cookie of meta.setCookies ?? []) {\n headers.append('set-cookie', cookie);\n }\n };\n\n // Response 对象:原样返回(但合并 meta headers)\n if (value instanceof Response) {\n if (\n meta &&\n (meta.status !== undefined ||\n Object.keys(meta.headers).length > 0 ||\n meta.setCookies.length > 0)\n ) {\n const headers = new Headers(value.headers);\n applyMeta(headers);\n return new Response(value.body, {\n status: meta.status ?? value.status,\n headers,\n });\n }\n return value;\n }\n\n // null/undefined:204 No Content\n if (value === null || value === undefined) {\n const status = meta?.status ?? 204;\n const headers = new Headers();\n applyMeta(headers);\n return new Response(null, { status, headers });\n }\n\n // ReadableStream:直接作为 body\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // Buffer / Uint8Array:作为二进制 body\n if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value as BodyInit, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n if (value instanceof Uint8Array) {\n const headers = new Headers({ 'Content-Type': 'application/octet-stream' });\n applyMeta(headers);\n return new Response(value as BodyInit, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // 普通对象/数组:JSON.stringify,Content-Type: application/json\n if (isPlainObject(value) || Array.isArray(value)) {\n const body = JSON.stringify(value);\n const headers = new Headers({ 'Content-Type': 'application/json' });\n applyMeta(headers);\n return new Response(body, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // string:text/plain\n if (typeof value === 'string') {\n const headers = new Headers({ 'Content-Type': 'text/plain' });\n applyMeta(headers);\n return new Response(value, {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // number/boolean:text/plain,String(value)\n if (typeof value === 'number' || typeof value === 'boolean') {\n const headers = new Headers({ 'Content-Type': 'text/plain' });\n applyMeta(headers);\n return new Response(String(value), {\n status: meta?.status ?? 200,\n headers,\n });\n }\n\n // 其他类型 fallback:JSON.stringify\n const body = JSON.stringify(value);\n const headers = new Headers({ 'Content-Type': 'application/json' });\n applyMeta(headers);\n return new Response(body, {\n status: meta?.status ?? 200,\n headers,\n });\n}\n","import type { FaapiContext } from '../runtime/contextTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { resolveInjection, type InjectionType } from './resolveInjection';\nimport { queryToObject } from '../utils/queryToObject';\nimport type { MultipartResult } from '../utils/parseMultipart';\n\n/**\n * 根据注入类型获取对应的值(内置)\n */\nfunction getBuiltinInjectionValue(type: InjectionType, ctx: FaapiContext, body?: unknown): unknown {\n switch (type) {\n case 'query':\n return queryToObject(ctx.query);\n case 'params':\n return ctx.params;\n case 'headers':\n return ctx.headers;\n case 'context':\n return ctx;\n case 'cookies':\n return ctx.cookies;\n case 'ip':\n return ctx.ip;\n case 'body':\n return body;\n case 'files':\n if (body && typeof body === 'object' && 'files' in body) {\n return (body as MultipartResult).files;\n }\n return [];\n case 'fields':\n if (body && typeof body === 'object' && 'fields' in body) {\n return (body as MultipartResult).fields;\n }\n return {};\n default:\n return undefined;\n }\n}\n\n/**\n * 根据注入信息,准备参数值并调用 handler(异步版本)\n *\n * 支持 async handler。内置注入优先于注入器(避免 query/body 等被覆盖)。\n * 非内置参数从注入器注册表按参数名查找,按需执行。\n */\nexport async function injectParamsAsync(\n handler: (...args: unknown[]) => unknown,\n ctx: FaapiContext,\n body?: unknown,\n injectors?: InjectorMap,\n): Promise<unknown> {\n const injections = resolveInjection(handler);\n\n if (injections.length === 0) {\n return await handler();\n }\n\n const args = await Promise.all(\n injections.map(async (injection) => {\n // 内置注入优先\n if (injection.type !== 'unknown') {\n return getBuiltinInjectionValue(injection.type, ctx, body);\n }\n // 注入器按参数名匹配\n if (injectors && injection.name in injectors) {\n return await injectors[injection.name](ctx);\n }\n return undefined;\n }),\n );\n\n return await handler(...args);\n}\n","import type { FaapiContext } from './contextTypes';\nimport type { ResponseMeta } from './contextTypes';\nimport type { SseWriter } from './sse';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { toResponse } from '../response/toResponse';\nimport { injectParamsAsync } from '../injection/injectParams';\n\n/**\n * 将 ctx.meta(setStatus/setHeader/setCookie 设置的响应元数据)合并到 Response\n *\n * 用于中间件返回 Response 时,确保用户通过 ctx.setStatus/setHeader 设置的\n * 状态码、响应头、cookie 能正确附加到中间件返回的 Response 上。\n */\nexport function mergeMeta(response: Response, meta: ResponseMeta): Response {\n const hasMeta =\n meta.status !== undefined || Object.keys(meta.headers).length > 0 || meta.setCookies.length > 0;\n if (!hasMeta) return response;\n\n const headers = new Headers(response.headers);\n for (const [key, value] of Object.entries(meta.headers)) {\n headers.set(key, value);\n }\n for (const cookie of meta.setCookies) {\n headers.append('set-cookie', cookie);\n }\n return new Response(response.body, {\n status: meta.status ?? response.status,\n headers,\n });\n}\n\n/**\n * 洋葱模型调度:将中间件链包装成 next 函数\n *\n * 每个中间件的 `await next()` 会执行下一个中间件并返回其 Response;\n * 最内层的 next 执行 handler(含参数注入)。\n *\n * 中间件返回 Response 的语义:\n * - 在 await next() 之前返回:拦截请求(不执行后续中间件和 handler)\n * - 在 await next() 之后返回:替换内层返回的响应\n * - 在 catch 块中返回:作为错误响应\n *\n * 中间件返回 void/undefined:使用 await next() 返回的内层响应。\n * 中间件不调用 next() 也不返回 Response:抛错(语义模糊,禁止使用)。\n *\n * 中间件返回 Response 时会合并 ctx.meta(setStatus/setHeader/setCookie 的设置),\n * 确保 ctx 便捷方法在中间件拦截场景下也生效。\n */\nexport async function compose(\n middlewares: FaapiMiddleware[],\n ctx: FaapiContext,\n finalHandler: () => Promise<Response>,\n): Promise<Response> {\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n let index = -1;\n\n async function dispatch(i: number): Promise<Response> {\n if (i <= index) {\n throw new Error('next() called multiple times');\n }\n index = i;\n\n // 所有中间件执行完,运行 handler\n if (i >= middlewares.length) {\n return await finalHandler();\n }\n\n const mw = middlewares[i];\n // next() 返回内层 Response,中间件可选择使用或替换\n let innerResponse: Response | undefined;\n const next = async (): Promise<Response> => {\n innerResponse = await dispatch(i + 1);\n return innerResponse;\n };\n\n const result = await mw(ctx, next);\n\n // 中间件返回 Response:使用它(拦截或替换),并合并 ctx.meta\n if (result instanceof Response) {\n return mergeMeta(result, meta);\n }\n // 中间件返回 void:使用 next() 返回的内层响应\n if (innerResponse !== undefined) {\n return innerResponse;\n }\n // 中间件既没返回 Response 也没调用 next():语义模糊,禁止\n throw new Error('中间件必须 await next() 或返回 Response');\n }\n\n return await dispatch(0);\n}\n\n/**\n * 调用路由 handler 并将返回值转为 Response\n *\n * 流程(洋葱模型):\n * 1. 中间件按洋葱模型执行:mw1.before → mw2.before → ... → handler → ... → mw2.after → mw1.after\n * 2. 中间件不调用 next() 即拦截请求(必须返回 Response)\n * 3. 中间件可用 try/catch 捕获内层错误\n * 4. 最内层执行注入器(按需)→ handler\n *\n * 注入器与中间件解耦:\n * - 注入器按 handler 参数名匹配,只执行需要的\n * - 注入器可读取中间件塞进 ctx 的值\n */\nexport async function invokeHandler(\n handler: (...args: unknown[]) => unknown,\n ctx: FaapiContext,\n body?: unknown,\n middlewares?: FaapiMiddleware[],\n injectors?: InjectorMap,\n): Promise<Response> {\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n /**\n * 若 handler 调用了 ctx.sse(),优先使用 SSE Response\n * (handler 返回值被忽略,SSE 流由 writer 控制)\n *\n * 同时执行自动 close 兜底:若 handler 返回时 writer 仍未关闭,自动调用 close(),\n * 避免连接泄漏。handler 异步循环未退出、忘记 close、或抛错的场景由这里兜底。\n */\n const pickSseAndAutoClose = (): Response | null => {\n const sseWriter = (ctx as FaapiContext & { __sseWriter?: SseWriter }).__sseWriter;\n if (!sseWriter) return null;\n // 兜底:handler 未显式 close 时自动关闭\n if (!sseWriter.closed && !sseWriter.aborted) {\n sseWriter.close();\n }\n return mergeMeta(sseWriter.response, meta);\n };\n\n // 抛错时也保证 writer 被关闭(避免流泄漏)\n const autoCloseSseOnError = (): void => {\n const sseWriter = (ctx as FaapiContext & { __sseWriter?: SseWriter }).__sseWriter;\n if (sseWriter && !sseWriter.closed && !sseWriter.aborted) {\n sseWriter.close();\n }\n };\n\n // 无中间件:直接执行 handler\n if (!middlewares || middlewares.length === 0) {\n try {\n const result = await injectParamsAsync(handler, ctx, body, injectors);\n const sseResponse = pickSseAndAutoClose();\n if (sseResponse) return sseResponse;\n return toResponse(result, meta);\n } catch (err) {\n // handler 抛错时关闭未完成的 SSE 流,避免泄漏\n autoCloseSseOnError();\n throw err;\n }\n }\n\n // 有中间件:洋葱模型调度\n const finalHandler = async (): Promise<Response> => {\n try {\n const result = await injectParamsAsync(handler, ctx, body, injectors);\n const sseResponse = pickSseAndAutoClose();\n if (sseResponse) return sseResponse;\n return toResponse(result, meta);\n } catch (err) {\n // handler 抛错时关闭未完成的 SSE 流,避免泄漏\n autoCloseSseOnError();\n throw err;\n }\n };\n\n return await compose(middlewares, ctx, finalHandler);\n}\n","import type { ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\n\n/**\n * 将 Web Response 写入 Node.js ServerResponse\n *\n * 使用 stream pipe 处理背压,避免高并发下内存膨胀。\n */\nexport async function sendNodeResponse(response: Response, res: ServerResponse): Promise<void> {\n // 设置状态码\n res.statusCode = response.status;\n\n // 设置 headers\n for (const [key, value] of response.headers) {\n if (key.toLowerCase() === 'set-cookie') {\n // Set-Cookie 使用 appendHeader 支持多个值\n res.appendHeader(key, value);\n } else {\n res.setHeader(key, value);\n }\n }\n\n // 写入 body(使用 pipe 处理背压)\n if (response.body) {\n // TS 5.7 lib.dom 的 ReadableStream 与 node:stream/web 的 ReadableStream 是不同类型,cast 绕过\n const nodeStream = Readable.fromWeb(response.body as never);\n await new Promise<void>((resolve, reject) => {\n nodeStream.on('error', reject);\n res.on('error', reject);\n res.on('finish', resolve);\n nodeStream.pipe(res);\n });\n return;\n }\n\n res.end();\n}\n","import type { PropertyType } from '../ast/resolveTypeNode';\nimport type { RuntimeType } from '../ast/resolveTypeNode';\nimport type { ValidationIssue } from '../errors/httpErrors';\n\nexport interface CoerceResult {\n data: Record<string, unknown>;\n issues: ValidationIssue[];\n}\n\n/**\n * 将输入值根据类型信息做类型转换(coerce)\n * 主要用于 query/params,这些来源的值都是 string\n *\n * 转换规则:\n * - string → number:Number() 转换,NaN 则失败\n * - string → boolean:'true'/'1' → true,'false'/'0' → false,其他失败\n * - string → string:不转换\n * - string[] → number[]:逐元素转换\n * - 其他类型:不转换\n *\n * @param input 输入值\n * @param properties 属性类型列表(来自 SchemaEntry.properties)\n */\nexport function coerceInput(\n input: Record<string, unknown>,\n properties: PropertyType[],\n): CoerceResult {\n const issues: ValidationIssue[] = [];\n const data: Record<string, unknown> = { ...input };\n\n for (const prop of properties) {\n const value = data[prop.name];\n const isPresent = prop.name in data;\n\n // 不存在的字段不转换\n if (!isPresent || value === undefined) continue;\n\n data[prop.name] = coerceValue(value, prop.type, prop.name, issues);\n }\n\n return { data, issues };\n}\n\n/**\n * 递归 coerce 值\n */\nfunction coerceValue(\n value: unknown,\n type: RuntimeType,\n path: string,\n issues: ValidationIssue[],\n): unknown {\n switch (type.kind) {\n case 'number':\n if (typeof value === 'string') {\n return coerceStringToNumber(value, path, issues);\n }\n return value;\n\n case 'boolean':\n if (typeof value === 'string') {\n return coerceStringToBoolean(value, path, issues);\n }\n return value;\n\n case 'array':\n // query 中的数组可能是逗号分隔字符串或重复 key\n if (typeof value === 'string') {\n // 单个字符串无法直接转为数组,保持原样\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((item, i) => coerceValue(item, type.element, `${path}[${i}]`, issues));\n }\n return value;\n\n case 'tuple': {\n // 元组按位置 coerce 每个元素\n // - 非-rest 元素:用 type.elements[i] 对应类型\n // - rest 范围内的元素:用 rest.type;否则不应出现(validator 会报错)\n if (!Array.isArray(value)) return value;\n const restElement = type.elements.find((e) => e.rest);\n return value.map((item, i) => {\n const elem = type.elements[i];\n if (elem && !elem.rest) {\n return coerceValue(item, elem.type, `${path}[${i}]`, issues);\n }\n // rest 范围内的元素\n if (restElement) {\n return coerceValue(item, restElement.type, `${path}[${i}]`, issues);\n }\n return item;\n });\n }\n\n case 'union':\n // 尝试 coerce 到联合类型中的每个成员,返回第一个成功的\n for (const member of type.members) {\n const tempIssues: ValidationIssue[] = [];\n const coerced = coerceValue(value, member, path, tempIssues);\n if (tempIssues.length === 0) {\n return coerced;\n }\n }\n return value;\n\n case 'literal':\n // 数值字面量(来自数值枚举):将 query 字符串转为数字,由 validator 检查是否匹配\n if (typeof type.value === 'number' && typeof value === 'string' && value.trim() !== '') {\n const num = Number(value);\n if (!Number.isNaN(num)) return num;\n }\n return value;\n\n case 'object':\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const obj = value as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n for (const prop of type.properties) {\n if (prop.name in obj) {\n result[prop.name] = coerceValue(\n obj[prop.name],\n prop.type,\n `${path}.${prop.name}`,\n issues,\n );\n }\n }\n return { ...obj, ...result };\n }\n return value;\n\n default:\n // string / date / record / any / null / undefined / bigint / tuple 不转换\n return value;\n }\n}\n\n/**\n * string → number\n */\nfunction coerceStringToNumber(\n value: string,\n path: string,\n issues: ValidationIssue[],\n): number | string {\n if (value.trim() === '') {\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'number',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 number`,\n });\n return value;\n }\n const num = Number(value);\n if (Number.isNaN(num)) {\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'number',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 number`,\n });\n return value;\n }\n return num;\n}\n\n/**\n * string → boolean\n */\nfunction coerceStringToBoolean(\n value: string,\n path: string,\n issues: ValidationIssue[],\n): boolean | string {\n if (value === 'true' || value === '1') {\n return true;\n }\n if (value === 'false' || value === '0') {\n return false;\n }\n issues.push({\n path,\n code: 'COERCE_FAILED',\n expected: 'boolean',\n received: 'string',\n message: `字段 \"${path}\" 类型转换失败:无法将 \"${value}\" 转为 boolean`,\n });\n return value;\n}\n","import { schemaRegistry } from './schemaRegistry';\nimport { getSchemaName } from './schemaName';\nimport { coerceInput } from './coerceInput';\nimport { InternalError } from '../errors/httpErrors';\nimport type { ValidationResult } from '../ast/generateValidatorCode';\n\n/**\n * 校验输入参数\n *\n * 流程:从 schemaRegistry 查询 schema → 类型转换(仅 query)→ 调用校验函数\n *\n * schema 来源由调用方确保已注册:\n * - dev 模式:启动时全量提取并生成函数,watch 时全量重建\n * - prd 模式:启动时从 dist/faapi-schema.js import 加载\n *\n * 三种状态:\n * - SchemaEntry:执行校验\n * - null:无类型声明,跳过校验\n * - undefined:manifest 不完整,抛 InternalError\n *\n * @param filePath 路由文件路径\n * @param method HTTP 方法\n * @param inputType 输入类型\n * @param input 输入值\n */\nexport async function validateInput(\n filePath: string,\n method: string,\n inputType: 'query' | 'body' | 'params',\n input: unknown,\n): Promise<ValidationResult> {\n const schemaName = getSchemaName(method, inputType);\n const entry = schemaRegistry.get(filePath, schemaName);\n\n // manifest 不完整:schema 未注册\n if (entry === undefined) {\n throw new InternalError(`Schema 未注册: ${filePath}#${schemaName}`);\n }\n\n // 无类型声明:跳过校验\n if (entry === null) {\n const data =\n typeof input === 'object' && input !== null && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n return { valid: true, issues: [], data };\n }\n\n const inputObj =\n typeof input === 'object' && input !== null && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n\n // 类型转换(coerce):仅 query 需要,因为 URL 参数都是 string\n let dataToValidate = inputObj;\n if (inputType === 'query') {\n const { data: coercedData, issues: coerceIssues } = coerceInput(inputObj, entry.properties);\n\n if (coerceIssues.length > 0) {\n return {\n valid: false,\n issues: coerceIssues,\n data: coercedData,\n };\n }\n dataToValidate = coercedData;\n }\n\n // 调用校验函数\n return entry.validator(dataToValidate);\n}\n","import type { IncomingMessage } from 'node:http';\n\n/**\n * 从 IncomingMessage 提取客户端 IP\n *\n * 优先级:\n * 1. `x-forwarded-for` 第一个 IP(反向代理场景,如 nginx/CDN)\n * 2. `req.socket.remoteAddress`(直连场景)\n *\n * `x-forwarded-for` 格式:`client, proxy1, proxy2`,取第一个即客户端真实 IP。\n * 注意:仅在受信任的反向代理后才有效;若客户端直连且未经过代理,该 header 可被伪造。\n *\n * @returns 客户端 IP,无法获取时返回空字符串\n */\nexport function getClientIp(req: IncomingMessage): string {\n // 1. x-forwarded-for 优先(反向代理场景)\n const xff = req.headers['x-forwarded-for'];\n if (typeof xff === 'string' && xff.length > 0) {\n const first = xff.split(',')[0]?.trim();\n if (first) return first;\n }\n\n // 2. 直连 socket IP\n const remote = req.socket.remoteAddress;\n if (remote) {\n // 去掉 IPv6 前缀 ::ffff:,统一返回 IPv4 形式\n if (remote.startsWith('::ffff:')) {\n return remote.slice(7);\n }\n return remote;\n }\n\n return '';\n}\n","import type { FaapiMiddleware } from './middlewareTypes';\n\nexport interface CorsOptions {\n origin?: string | string[] | true;\n methods?: string[];\n allowedHeaders?: string[];\n exposeHeaders?: string[];\n credentials?: boolean;\n maxAge?: number;\n}\n\nconst DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];\n\n/**\n * 创建 CORS 中间件(洋葱模型)\n *\n * - origin=true: 允许所有来源(反射请求的 Origin)\n * - origin=string: 允许指定来源\n * - origin=string[]: 允许多个来源\n *\n * OPTIONS 预检请求直接返回 204,不调用 next()。\n */\nexport function cors(options: CorsOptions = {}): FaapiMiddleware {\n const {\n origin = true,\n methods = DEFAULT_METHODS,\n allowedHeaders,\n exposeHeaders,\n credentials = false,\n maxAge,\n } = options;\n\n return async (ctx, next) => {\n const reqOrigin = ctx.headers.get('origin');\n if (!reqOrigin) {\n await next();\n return;\n }\n\n // 确定允许的来源\n let allowOrigin: string | null = null;\n if (origin === true) {\n allowOrigin = reqOrigin; // 反射 Origin\n } else if (typeof origin === 'string') {\n allowOrigin = reqOrigin === origin ? origin : null;\n } else if (Array.isArray(origin)) {\n allowOrigin = origin.includes(reqOrigin) ? reqOrigin : null;\n }\n\n if (!allowOrigin) {\n await next();\n return;\n }\n\n // 设置 CORS 响应头\n ctx.setHeader('Access-Control-Allow-Origin', allowOrigin);\n\n // 当 origin 为动态值(true 或数组)时,必须设置 Vary: Origin,\n // 防止 CDN/浏览器错误缓存针对某个 Origin 的响应给其他 Origin\n if (origin === true || Array.isArray(origin)) {\n const existingVary = ctx.headers.get('vary');\n if (existingVary) {\n if (!existingVary.toLowerCase().includes('origin')) {\n ctx.setHeader('Vary', `${existingVary}, Origin`);\n }\n } else {\n ctx.setHeader('Vary', 'Origin');\n }\n }\n\n ctx.setHeader('Access-Control-Allow-Methods', methods.join(', '));\n\n if (allowedHeaders) {\n ctx.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));\n } else {\n // 反射请求头\n const requestHeaders = ctx.headers.get('access-control-request-headers');\n if (requestHeaders) {\n ctx.setHeader('Access-Control-Allow-Headers', requestHeaders);\n }\n }\n\n if (exposeHeaders && exposeHeaders.length > 0) {\n ctx.setHeader('Access-Control-Expose-Headers', exposeHeaders.join(', '));\n }\n\n if (credentials) {\n ctx.setHeader('Access-Control-Allow-Credentials', 'true');\n }\n\n if (maxAge !== undefined) {\n ctx.setHeader('Access-Control-Max-Age', String(maxAge));\n }\n\n // 处理 preflight 请求:直接返回 204,不调用 next()\n if (ctx.method === 'OPTIONS') {\n return new Response(null, { status: 204 });\n }\n\n await next();\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { createReadStream } from 'node:fs';\nimport { Readable } from 'node:stream';\n\n/**\n * MIME 类型映射表\n *\n * 覆盖常见的 Web 静态资源类型。\n */\nconst MIME_TYPES: Record<string, string> = {\n // 文本\n '.html': 'text/html; charset=utf-8',\n '.htm': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.cjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.json5': 'application/json5',\n '.txt': 'text/plain; charset=utf-8',\n '.md': 'text/markdown; charset=utf-8',\n '.csv': 'text/csv; charset=utf-8',\n '.xml': 'application/xml; charset=utf-8',\n '.yaml': 'application/x-yaml',\n '.yml': 'application/x-yaml',\n '.toml': 'application/toml',\n\n // 图片\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n '.heic': 'image/heic',\n\n // 字体\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject',\n\n // 音频\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n '.ogg': 'audio/ogg',\n '.oga': 'audio/ogg',\n '.flac': 'audio/flac',\n '.m4a': 'audio/mp4',\n '.aac': 'audio/aac',\n\n // 视频\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogv': 'video/ogg',\n '.mov': 'video/quicktime',\n '.m4v': 'video/mp4',\n '.avi': 'video/x-msvideo',\n\n // 文档\n '.pdf': 'application/pdf',\n\n // 压缩\n '.zip': 'application/zip',\n '.gz': 'application/gzip',\n '.tar': 'application/x-tar',\n '.rar': 'application/vnd.rar',\n '.7z': 'application/x-7z-compressed',\n\n // 其他\n '.wasm': 'application/wasm',\n '.map': 'application/json',\n '.webmanifest': 'application/manifest+json',\n};\n\n/**\n * 尝试提供静态文件\n *\n * 使用流式响应(createReadStream)避免大文件占用内存。\n * 路径遍历检查使用 path.relative 严格判断。\n *\n * @param urlPath 请求路径\n * @param staticDir 静态文件根目录的绝对路径\n * @returns Response 或 null(未找到文件)\n */\nexport async function serveStatic(urlPath: string, staticDir: string): Promise<Response | null> {\n // 安全检查:防止路径遍历\n // 使用 path.relative 判断解析后的路径是否仍在 staticDir 内\n const resolved = path.resolve(staticDir, '.' + urlPath);\n const relative = path.relative(staticDir, resolved);\n\n // relative 如果以 '..' 开头或为绝对路径,说明逃逸了 staticDir\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n return null;\n }\n\n let stat: fs.Stats;\n try {\n stat = await fs.promises.stat(resolved);\n } catch {\n return null;\n }\n\n if (stat.isDirectory()) {\n // 尝试 index.html\n const indexPath = path.join(resolved, 'index.html');\n try {\n const indexStat = await fs.promises.stat(indexPath);\n if (indexStat.isFile()) {\n return serveFile(indexPath, indexStat.size);\n }\n } catch {\n // index.html 不存在\n }\n return null;\n }\n\n if (!stat.isFile()) {\n return null;\n }\n\n return serveFile(resolved, stat.size);\n}\n\n/**\n * 流式响应文件\n *\n * 使用 createReadStream 避免大文件占用内存。\n * 设置 ETag 和 Last-Modified 支持条件请求。\n */\nfunction serveFile(filePath: string, size: number): Response {\n const ext = path.extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n\n // 使用 mtime 作为 ETag 和 Last-Modified\n const stream = createReadStream(filePath);\n const webStream = Readable.toWeb(stream) as ReadableStream<Uint8Array>;\n\n return new Response(webStream, {\n status: 200,\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'public, max-age=3600',\n 'Content-Length': String(size),\n },\n });\n}\n","import { FaapiError } from './FaapiError';\nimport { ValidationError, MethodNotAllowedError } from './httpErrors';\n\n/**\n * 将错误转换为统一的 JSON 响应结构\n *\n * 格式:\n * {\n * \"error\": {\n * \"code\": \"VALIDATION_ERROR\",\n * \"message\": \"Invalid query parameters\",\n * \"issues\": [...] // 仅 ValidationError 包含\n * }\n * }\n */\nexport function formatErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n const body: Record<string, unknown> = {\n code: error.code,\n message: error.message,\n issues: error.issues,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n if (error instanceof MethodNotAllowedError) {\n const body = {\n code: error.code,\n message: error.message,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: {\n 'Content-Type': 'application/json',\n Allow: error.allowedMethods.join(', '),\n },\n });\n }\n\n if (error instanceof FaapiError) {\n const body = {\n code: error.code,\n message: error.message,\n };\n return new Response(JSON.stringify({ error: body }), {\n status: error.statusCode,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n // 未知错误:500 INTERNAL_ERROR\n const body = {\n code: 'INTERNAL_ERROR',\n message: error instanceof Error ? error.message : 'An unknown error occurred',\n };\n return new Response(JSON.stringify({ error: body }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n });\n}\n","import type { IncomingMessage } from 'node:http';\nimport type { FaapiContext } from '../runtime/contextTypes';\nimport type { ErrorFormatFn } from '../config/configTypes';\nimport { formatErrorResponse } from '../errors/formatErrorResponse';\n\n/**\n * 将 Node.js IncomingMessage 的 headers 转为 Web Headers\n *\n * 处理数组型 header 值(如 set-cookie)和 undefined 值。\n */\nexport function nodeHttpToWebHeaders(req: IncomingMessage): Headers {\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const v of value) headers.append(key, v);\n } else {\n headers.set(key, value);\n }\n }\n return headers;\n}\n\n/**\n * 构建错误响应(兜底链)\n *\n * 1. 配置了 errorFormat → 优先调用;返回 Response 表示已处理\n * 2. errorFormat 返回 null/undefined(未处理)或抛错 → 框架内置 formatErrorResponse 兜底\n * 3. 内置兜底仍抛错 → 最简 500 JSON 响应\n */\nexport function buildErrorResponse(\n err: unknown,\n ctx: FaapiContext,\n errorFormat?: ErrorFormatFn,\n): Response {\n if (errorFormat) {\n try {\n const res = errorFormat(err, ctx);\n if (res) return res;\n } catch {\n // errorFormat 抛错,落入下方 formatErrorResponse 兜底\n }\n }\n try {\n return formatErrorResponse(err);\n } catch {\n // 极端情况:内置兜底也失败,返回最简 500\n return new Response(\n JSON.stringify({ error: { code: 'INTERNAL_ERROR', message: 'Internal Server Error' } }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n },\n );\n }\n}\n","/**\n * WebSocket Handler 类型定义与 socket 封装\n *\n * 用户在 handler.ts 中导出 WS 函数,返回事件回调对象。\n * 框架在协议升级成功后调用对应回调,传递封装后的 WsSocket。\n *\n * @see wsHandler.md 功能说明\n */\n\n/**\n * faapi 封装的 WebSocket socket 抽象\n *\n * 不直接暴露 ws 库的原生 socket,提供更安全、易用的 API。\n * send 对象时自动 JSON.stringify。\n */\nexport interface WsSocket {\n /** 发送数据(string/Buffer 直发,对象自动 JSON.stringify) */\n send(data: string | Buffer | object): void;\n /** 关闭连接 */\n close(code?: number, reason?: string | Buffer): void;\n /** 连接状态:0=connecting, 1=open, 2=closing, 3=closed */\n readonly readyState: number;\n}\n\n/**\n * WebSocket 事件回调集合\n *\n * 用户在 WS handler 中返回此对象,框架在对应事件触发时调用。\n * 所有回调可选,未提供则忽略事件。\n */\nexport interface WsEventHandlers {\n /** 连接建立时触发 */\n onOpen?: (ws: WsSocket) => void;\n /** 收到客户端消息时触发 */\n onMessage?: (ws: WsSocket, message: string | Buffer) => void;\n /** 连接关闭时触发 */\n onClose?: (ws: WsSocket, code: number, reason: string) => void;\n /** 发生错误时触发 */\n onError?: (ws: WsSocket, error: Error) => void;\n}\n\n/**\n * WebSocket 上下文(握手阶段构造)\n *\n * 与 HTTP FaapiContext 类似但精简,提供路由参数、查询参数、请求头、配置。\n * 可通过 declare module '@faapi/faapi' 增强自定义字段。\n */\nexport interface WsContext {\n /** 动态路由参数(如 [id] → params.id) */\n params: Record<string, string>;\n /** URL 查询参数 */\n query: URLSearchParams;\n /** 请求头 */\n headers: Headers;\n /** 业务配置(来自 faapi.config.ts) */\n config: Record<string, unknown>;\n /** 中间件塞入的用户信息(鉴权等) */\n user?: unknown;\n /** 允许通过 declare module 扩展 */\n [key: string]: unknown;\n}\n\n/**\n * WS handler 签名:接收 WsContext,返回事件回调对象(或无返回)\n */\nexport type WsHandler = (ctx: WsContext) => WsEventHandlers | void;\n\n/**\n * 将 ws 库的原生 WebSocket 封装为 faapi 的 WsSocket\n *\n * - send 对象时自动 JSON.stringify\n * - close/re.readyState 透传原生 socket\n */\nexport function wrapWsSocket(rawSocket: {\n send: (data: string | Buffer, cb?: (err?: Error) => void) => void;\n close: (code?: number, reason?: string | Buffer) => void;\n readonly readyState: number;\n}): WsSocket {\n return {\n send(data: string | Buffer | object): void {\n const payload =\n typeof data === 'string' || Buffer.isBuffer(data) ? data : JSON.stringify(data);\n rawSocket.send(payload);\n },\n close(code?: number, reason?: string | Buffer): void {\n rawSocket.close(code, reason);\n },\n get readyState(): number {\n return rawSocket.readyState;\n },\n };\n}\n","/**\n * WebSocket 协议升级处理\n *\n * 监听 HTTP server 的 upgrade 事件,匹配 WS 路由后调用 ws 库完成协议升级,\n * 加载 handler.ts 的 WS 导出,绑定事件回调。\n *\n * 握手阶段复用洋葱中间件链(鉴权/CORS/限流/日志等),与同目录 HTTP 路由共享中间件。\n * 中间件塞入 ctx 的值(如 ctx.user)传入 WS handler。连接建立后切到事件模型,不走中间件。\n *\n * @see wsHandler.md WS handler 约定与握手中间件链设计\n */\nimport type { IncomingMessage } from 'node:http';\nimport type { Server } from 'node:http';\nimport type { Socket } from 'node:net';\nimport { WebSocketServer, WebSocket } from 'ws';\nimport path from 'node:path';\nimport type { WsRouteManifest, WsRouteMatch } from '../router/routeTypes';\nimport { matchWsRoute } from '../router/matchRoute';\nimport { createContext } from '../runtime/createContext';\nimport { compose, mergeMeta } from '../runtime/invokeHandler';\nimport type { FaapiContext, ResponseMeta } from '../runtime/contextTypes';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\nimport { getClientIp } from '../utils/getClientIp';\nimport { nodeHttpToWebHeaders, buildErrorResponse } from './serverUtils';\nimport type { ErrorFormatFn } from '../config/configTypes';\nimport {\n wrapWsSocket,\n type WsContext,\n type WsEventHandlers,\n type WsHandler,\n} from '../runtime/wsHandler';\n\n/**\n * 从 IncomingMessage 提取 URL pathname(不含 query)\n */\nfunction getPathname(req: IncomingMessage): string {\n const url = req.url ?? '/';\n const idx = url.indexOf('?');\n return idx >= 0 ? url.slice(0, idx) : url;\n}\n\n/**\n * 加载 WS handler 并执行,返回事件回调对象(可能为空)\n *\n * 直接动态 import handler.ts 并取 `WS` 导出(不经过 loadRouteModule,\n * 因为 WS 不是 HTTP 方法,loadRouteModule 的 method 维度不适用)。\n * watch 模式下通过时间戳 query string 绕过 ESM 缓存。\n */\nasync function loadWsHandler(filePath: string, ctx: WsContext): Promise<WsEventHandlers | void> {\n const module = await importWithCacheBust(filePath);\n const handler = module['WS'];\n if (typeof handler !== 'function') {\n throw new Error(`WS export not found in ${filePath}`);\n }\n return (handler as WsHandler)(ctx);\n}\n\n/**\n * 绑定 ws 库原生事件到 faapi 的 WsEventHandlers\n *\n * 注意:wss.handleUpgrade 回调触发时 socket 已经处于 OPEN 状态,\n * 'open' 事件不会再触发,需要直接同步调用 onOpen。\n */\nfunction bindEvents(rawSocket: WebSocket, handlers: WsEventHandlers | void): void {\n if (!handlers) return;\n const ws = wrapWsSocket(rawSocket);\n\n if (handlers.onOpen) {\n // handleUpgrade 回调触发时 socket 已是 OPEN,直接同步调用\n if (rawSocket.readyState === WebSocket.OPEN) {\n handlers.onOpen!(ws);\n } else {\n rawSocket.once('open', () => handlers.onOpen!(ws));\n }\n }\n if (handlers.onMessage) {\n rawSocket.on('message', (data: Buffer) => {\n // ws 库 message 事件传 Buffer[],合并为单个 Buffer 后转 string\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data as unknown as Uint8Array);\n handlers.onMessage!(ws, buf.toString('utf8'));\n });\n }\n if (handlers.onClose) {\n rawSocket.on('close', (code: number, reason: Buffer) => {\n handlers.onClose!(ws, code, reason.toString('utf8'));\n });\n }\n if (handlers.onError) {\n rawSocket.on('error', (err: Error) => {\n handlers.onError!(ws, err);\n });\n }\n}\n\n/**\n * 把 Web Response 写回原始 socket(握手被中间件拦截或出错时使用)\n *\n * socket 未升级为 WebSocket 时,按 HTTP 响应格式写回并销毁。\n */\nasync function sendResponseToSocket(socket: Socket, response: Response): Promise<void> {\n const body = await response.text().catch(() => '');\n const statusLine = `HTTP/1.1 ${response.status} ${response.statusText || ''}\\r\\n`;\n const headerLines: string[] = [];\n let hasContentLength = false;\n for (const [key, value] of response.headers) {\n if (key.toLowerCase() === 'content-length') {\n hasContentLength = true;\n }\n headerLines.push(`${key}: ${value}`);\n }\n if (!hasContentLength) {\n headerLines.push(`Content-Length: ${Buffer.byteLength(body)}`);\n }\n socket.write(statusLine + headerLines.join('\\r\\n') + '\\r\\n\\r\\n' + body);\n socket.destroy();\n}\n\nexport interface AttachWsOptions {\n /** HTTP server 实例(已由 createServer 创建) */\n server: Server;\n /** WS 路由清单(watch 模式下可通过更新此数组热更新) */\n wsRoutes: WsRouteManifest;\n /** 项目根目录,用于解析路由文件绝对路径 */\n rootDir: string;\n /** 业务配置,注入到 WsContext.config */\n config?: Record<string, unknown>;\n /** 错误响应格式化函数(来自 faapi.config.ts) */\n errorFormat?: ErrorFormatFn;\n /** 全局中间件(来自 faapi.config.ts,WS 握手最外层) */\n globalMiddlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,WS handler 可通过 ctx 间接访问全局依赖) */\n globalInjectors?: InjectorMap;\n}\n\n/**\n * 在 HTTP server 上挂载 WebSocket 升级处理\n *\n * 创建独立的 WebSocketServer(noServer 模式),监听 server 的 upgrade 事件。\n * 路由匹配成功后,走洋葱中间件链:\n * - 中间件放行(await next):finalHandler 内调用 ws.handleUpgrade 完成协议升级、绑定事件回调\n * - 中间件拦截(返回 Response):把 Response 写回 socket 后销毁,不进行协议升级\n * - 中间件抛错:由 errorFormat/内置兜底生成错误 Response,写回 socket 后销毁\n *\n * 中间件链顺序:全局中间件(外)→ 目录中间件(内)→ finalHandler。\n * watch 模式下 wsRoutes 通过引用更新(见 createServer 的 globalRef 模式)。\n */\nexport function attachWebSocket(options: AttachWsOptions): WebSocketServer {\n const { server, rootDir, config, errorFormat, globalMiddlewares } = options;\n // wsRoutes 通过闭包引用 globalRef,支持 watch 热更新\n const globalRef = globalThis as Record<string, unknown>;\n\n const wss = new WebSocketServer({ noServer: true });\n\n server.on('upgrade', async (req: IncomingMessage, socket: Socket, head: Buffer) => {\n const currentWsRoutes = (globalRef.__FAAPI_WS_ROUTES__ as WsRouteManifest) ?? options.wsRoutes;\n const pathname = getPathname(req);\n const match: WsRouteMatch | null = matchWsRoute(currentWsRoutes, pathname);\n\n if (!match) {\n // 路由不匹配:返回 404 并销毁 socket\n socket.write('HTTP/1.1 404 Not Found\\r\\n\\r\\n');\n socket.destroy();\n return;\n }\n\n const { route, params } = match;\n const headers = nodeHttpToWebHeaders(req);\n const host = req.headers.host ?? 'localhost';\n const url = `http://${host}${req.url ?? '/'}`;\n\n // 构造 Web Request 与 FaapiContext(与 HTTP 请求一致,供中间件使用)\n const request = new Request(url, { method: 'GET', headers });\n const ctx = createContext(request, params, config, getClientIp(req));\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n // 标记握手是否已完成协议升级(用于判断 socket 是否可写)\n let upgraded = false;\n\n // finalHandler:加载 WS handler + 协议升级 + 绑定事件\n const finalHandler = async (): Promise<Response> => {\n let handlers: WsEventHandlers | void;\n try {\n const absoluteFilePath = path.resolve(rootDir, route.filePath);\n // WsContext 是 FaapiContext 的结构子集,直接复用 ctx 实例\n // 中间件塞入的字段(如 ctx.user)对 WS handler 可见\n handlers = await loadWsHandler(absoluteFilePath, ctx as unknown as WsContext);\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n console.error(`[faapi] WS handler 加载失败 ${route.filePath}: ${reason}`);\n return new Response('Internal Server Error', { status: 500 });\n }\n\n // 协议升级:等 wss.handleUpgrade 回调完成 bindEvents\n await new Promise<void>((resolve, reject) => {\n wss.handleUpgrade(req, socket, head, (rawSocket: WebSocket) => {\n try {\n bindEvents(rawSocket, handlers);\n wss.emit('connection', rawSocket, req);\n upgraded = true;\n resolve();\n } catch (err) {\n reject(err);\n }\n });\n });\n\n // 占位 Response,表示握手成功(socket 已升级,不会被写出)\n return new Response(null, { status: 200 });\n };\n\n // 执行中间件链:全局中间件(外)+ 目录中间件(内)\n let response: Response;\n try {\n const dirMiddlewares = route.middlewares ?? [];\n const allMiddlewares =\n globalMiddlewares && globalMiddlewares.length > 0\n ? [...globalMiddlewares, ...dirMiddlewares]\n : dirMiddlewares;\n if (allMiddlewares.length > 0) {\n response = await compose(allMiddlewares, ctx, finalHandler);\n } else {\n response = await finalHandler();\n }\n } catch (err) {\n if (upgraded) {\n // 握手已完成(socket 已被 ws 库接管),中间件 after 阶段抛错无法改写响应\n console.error('[faapi] WS 握手后中间件抛错:', err);\n return;\n }\n // 错误兜底链:errorFormat 返回 null/未处理或抛错 → 内置 formatErrorResponse 兜底\n response = buildErrorResponse(err, ctx, errorFormat);\n }\n\n // 握手成功:socket 已升级,中间件 after 阶段已执行完,无需再写\n if (upgraded) {\n return;\n }\n\n // 中间件拦截或错误:把 Response 写回 socket 后销毁\n await sendResponseToSocket(socket, mergeMeta(response, meta));\n });\n\n return wss;\n}\n","import {\n createServer as createHttpServer,\n type Server,\n type IncomingMessage,\n type ServerResponse,\n} from 'node:http';\nimport { Readable } from 'node:stream';\nimport path from 'node:path';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport { matchRoute, matchDynamicPath } from '../router/matchRoute';\nimport { loadRouteModule } from '../loader/loadRouteModule';\nimport { createContext } from '../runtime/createContext';\nimport { resolveInput } from '../runtime/resolveInput';\nimport { invokeHandler, compose, mergeMeta } from '../runtime/invokeHandler';\nimport type { FaapiContext, ResponseMeta } from '../runtime/contextTypes';\nimport { sendNodeResponse } from '../response/sendNodeResponse';\nimport { RouteNotFoundError, MethodNotAllowedError, ValidationError } from '../errors/httpErrors';\nimport { validateInput } from '../validator/validateInput';\nimport { getInputTypeForMethod, hasBody } from '../runtime/inputType';\nimport { getClientIp } from '../utils/getClientIp';\nimport { cors, type CorsOptions } from '../middleware/cors';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport type { ResponseFormatFn, ErrorFormatFn } from '../config/configTypes';\nimport { serveStatic } from './serveStatic';\nimport { schemaRegistry } from '../validator/schemaRegistry';\nimport { extractSchemasForRoutes } from '../cli/generateSchema';\nimport { attachWebSocket } from './handleWsUpgrade';\nimport { nodeHttpToWebHeaders, buildErrorResponse } from './serverUtils';\n\n/**\n * 将 Node.js IncomingMessage 转为 Web Request 对象\n *\n * 协议判断:\n * 1. 优先使用 X-Forwarded-Proto 头(反向代理场景)\n * 2. 回退到 http(HTTPS 由外部代理处理)\n *\n * 请求体大小限制:10MB(防止 DoS)\n */\nconst MAX_BODY_SIZE = 10 * 1024 * 1024; // 10MB\n\nfunction toWebRequest(req: IncomingMessage): Request {\n // 协议判断:优先 X-Forwarded-Proto(反向代理),否则 http\n const forwardedProto = req.headers['x-forwarded-proto'];\n const protocol = Array.isArray(forwardedProto)\n ? (forwardedProto[0]?.split(',')[0]?.trim() ?? 'http')\n : (forwardedProto?.split(',')[0]?.trim() ?? 'http');\n const host = req.headers.host ?? 'localhost';\n const url = new URL(req.url ?? '/', `${protocol}://${host}`);\n\n const headers = nodeHttpToWebHeaders(req);\n\n const method = req.method ?? 'GET';\n\n // GET/HEAD 不应该有 body\n if (method === 'GET' || method === 'HEAD') {\n return new Request(url.toString(), { method, headers });\n }\n\n // 将 Node.js IncomingMessage 转为 Web ReadableStream\n // 并限制请求体大小(防止 DoS)\n const stream = Readable.toWeb(req) as ReadableStream<Uint8Array>;\n const limitedStream = limitStreamSize(stream, MAX_BODY_SIZE);\n return new Request(url.toString(), {\n method,\n headers,\n body: limitedStream,\n duplex: 'half',\n } as RequestInit);\n}\n\n/**\n * 限制 ReadableStream 的总字节数,超过限制时抛错\n */\nfunction limitStreamSize(\n stream: ReadableStream<Uint8Array>,\n maxSize: number,\n): ReadableStream<Uint8Array> {\n let totalSize = 0;\n const reader = stream.getReader();\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n reader.releaseLock();\n return;\n }\n totalSize += value.byteLength;\n if (totalSize > maxSize) {\n controller.error(new Error(`请求体超过大小限制 ${maxSize} 字节`));\n reader.releaseLock();\n return;\n }\n controller.enqueue(value);\n },\n cancel(reason) {\n reader.cancel(reason);\n },\n });\n}\n\n/**\n * 检查指定路径是否有其他方法的路由(用于 405 响应)\n */\nfunction findAllowedMethods(routes: RouteManifest, path: string): string[] {\n const methods = new Set<string>();\n for (const route of routes) {\n if (route.urlPath === path) {\n methods.add(route.method);\n continue;\n }\n // 也检查动态路由\n if (route.isDynamic) {\n const params = matchDynamicPath(route.urlPath, path, route.paramNames, route.isCatchAll);\n if (params !== null) {\n methods.add(route.method);\n }\n }\n }\n return Array.from(methods);\n}\n\nexport interface CreateServerOptions {\n routes: RouteManifest;\n rootDir: string;\n cors?: CorsOptions | boolean; // true = dev mode auto-enable, false = disabled\n staticDir?: string;\n /** 统一响应格式化函数 */\n responseFormat?: ResponseFormatFn;\n /** 错误响应格式化函数(优先于内置 formatErrorResponse 处理;返回 null/undefined 表示不处理) */\n errorFormat?: ErrorFormatFn;\n /** 请求错误钩子(在错误响应生成后调用,用于副作用;不修改已发出的响应) */\n onError?: (error: unknown, ctx: FaapiContext) => Promise<void> | void;\n /** 自定义业务配置(来自 faapi.config.ts,注入到 ctx.config) */\n config?: Record<string, unknown>;\n /** WebSocket 路由清单(空数组则不挂载 WS 支持) */\n wsRoutes?: WsRouteManifest;\n /** 全局中间件(来自 faapi.config.ts,对所有路由生效,最外层) */\n middlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,对所有路由 handler 参数注入生效) */\n injectors?: InjectorMap;\n}\n\n/**\n * 创建 faapi HTTP server\n *\n * @param options 路由清单、根目录\n * @returns Node.js Server 实例\n */\nexport function createServer(options: CreateServerOptions): Server {\n const {\n routes,\n rootDir,\n cors: corsOption,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares: globalMiddlewares,\n injectors: globalInjectors,\n } = options;\n\n // 初始化全局路由状态(watch 模式会更新这些值)\n const globalRef = globalThis as Record<string, unknown>;\n globalRef.__FAAPI_ROUTES__ = routes;\n if (wsRoutes) {\n globalRef.__FAAPI_WS_ROUTES__ = wsRoutes;\n }\n\n // 确保 schema 已注册到 registry\n // - 如果 registry 已有数据(startCommand 已加载 manifest 或 dev 已提取),跳过\n // - 如果 registry 为空(e2e 测试或直接调用 createServer),自动提取\n if (schemaRegistry.size === 0 && routes.length > 0) {\n const manifest = extractSchemasForRoutes(routes, rootDir);\n schemaRegistry.loadManifest(manifest);\n }\n\n // Build CORS middleware if enabled\n const corsMiddleware: FaapiMiddleware | null =\n corsOption === false\n ? null\n : corsOption === true || corsOption === undefined\n ? cors() // default: allow all (dev mode)\n : cors(corsOption);\n\n const server = createHttpServer((req: IncomingMessage, res: ServerResponse) => {\n // 每次请求读取最新的路由状态(支持 watch 模式热更新)\n const currentRoutes = (globalRef.__FAAPI_ROUTES__ as RouteManifest) ?? routes;\n\n handleRequest(\n currentRoutes,\n rootDir,\n req,\n res,\n corsMiddleware,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n globalMiddlewares,\n globalInjectors,\n ).catch(() => {\n res.statusCode = 500;\n res.end();\n });\n });\n\n // 挂载 WebSocket 升级处理(仅当提供了 WS 路由)\n if (wsRoutes && wsRoutes.length > 0) {\n attachWebSocket({ server, wsRoutes, rootDir, config, errorFormat, globalMiddlewares });\n }\n\n return server;\n}\n\nasync function handleRequest(\n routes: RouteManifest,\n rootDir: string,\n req: IncomingMessage,\n res: ServerResponse,\n corsMiddleware: FaapiMiddleware | null,\n staticDir: string | undefined,\n responseFormat: ResponseFormatFn | undefined,\n errorFormat: ErrorFormatFn | undefined,\n onError: ((error: unknown, ctx: FaapiContext) => Promise<void> | void) | undefined,\n config: Record<string, unknown> | undefined,\n globalMiddlewares: FaapiMiddleware[] | undefined,\n globalInjectors: InjectorMap | undefined,\n): Promise<void> {\n const request = toWebRequest(req);\n const method = request.method.toUpperCase();\n const urlPath = new URL(request.url).pathname;\n const ctx = createContext(request, {}, config, getClientIp(req));\n const meta = (ctx as FaapiContext & { meta: ResponseMeta }).meta;\n\n // 路由处理管线:作为 CORS 中间件的 next\n // 包含路由匹配、静态文件、参数校验、handler 调用、响应格式化\n const routePipeline = async (): Promise<Response> => {\n // 尝试匹配路由\n const match = matchRoute(routes, method, urlPath);\n\n if (!match) {\n // 静态文件 fallback\n if (staticDir) {\n const absStaticDir = path.resolve(rootDir, staticDir);\n const staticResponse = await serveStatic(urlPath, absStaticDir);\n if (staticResponse) {\n return mergeMeta(staticResponse, meta);\n }\n }\n\n // 检查是否有其他方法匹配该路径\n const allowedMethods = findAllowedMethods(routes, urlPath);\n if (allowedMethods.length > 0) {\n throw new MethodNotAllowedError(method, urlPath, allowedMethods);\n }\n\n // 路由未匹配,返回 404\n throw new RouteNotFoundError(urlPath);\n }\n\n // 匹配成功,填充路由参数\n ctx.params = match.params;\n const { route } = match;\n\n // 处理 API 路由(handler.ts)\n const absoluteFilePath = path.resolve(rootDir, route.filePath);\n const routeModule = await loadRouteModule(absoluteFilePath, route.method);\n const input = await resolveInput(route.method, request);\n\n // 参数校验(统一从 inputType 模块获取输入类型)\n const inputType = getInputTypeForMethod(route.method);\n const result = await validateInput(absoluteFilePath, route.method, inputType, input);\n if (!result.valid) {\n throw new ValidationError('参数校验失败', result.issues);\n }\n\n const body = hasBody(route.method) ? result.data : undefined;\n // 合并注入器:全局注入器为基线,目录注入器覆盖同名\n const mergedInjectors = globalInjectors\n ? { ...globalInjectors, ...route.injectors }\n : route.injectors;\n let response = await invokeHandler(\n routeModule.handler,\n ctx,\n body,\n route.middlewares,\n mergedInjectors,\n );\n\n // 统一响应格式化:对非 Response 的成功响应应用 responseFormat\n if (responseFormat && response.status >= 200 && response.status < 300) {\n // 只对 JSON 响应(handler 返回的对象)应用格式化,跳过 Response 原样透传的情况\n const contentType = response.headers.get('Content-Type') ?? '';\n if (contentType.includes('application/json')) {\n const data = await response.json();\n const formatted = responseFormat(data, ctx);\n // 重新构建响应(保留原有 meta 信息)\n const { toResponse } = await import('../response/toResponse.js');\n response = await toResponse(formatted, meta);\n }\n }\n\n return response;\n };\n\n try {\n let response: Response;\n // 外层中间件链:CORS + 全局中间件(CORS 最外,全局次外)\n // 顺序:CORS.before → 全局.before → routePipeline(含目录中间件 + handler)→ 全局.after → CORS.after\n const outerMiddlewares: FaapiMiddleware[] = [];\n if (corsMiddleware) outerMiddlewares.push(corsMiddleware);\n if (globalMiddlewares && globalMiddlewares.length > 0) {\n outerMiddlewares.push(...globalMiddlewares);\n }\n\n if (outerMiddlewares.length > 0) {\n response = await compose(outerMiddlewares, ctx, routePipeline);\n } else {\n response = await routePipeline();\n }\n await sendNodeResponse(response, res);\n } catch (err: unknown) {\n // 错误处理兜底链(参考 Fastify 语义):\n // 1. 用户 errorFormat 返回 Response 表示已处理\n // 2. errorFormat 未处理(返回 null/undefined)或抛错 → 框架内置 formatErrorResponse 兜底\n // 3. 内置兜底仍抛错 → 最简 500 JSON 响应\n // 4. 响应发出后 → onError 触发副作用(不修改已发出的响应)\n const errorResponse = buildErrorResponse(err, ctx, errorFormat);\n await sendNodeResponse(mergeMeta(errorResponse, meta), res);\n\n // 响应已发出,触发 onError 副作用(日志/告警),自身抛错被忽略\n if (onError) {\n try {\n await onError(err, ctx);\n } catch {\n // onError 自身抛错不影响已发出的响应\n }\n }\n }\n}\n","import type { Server } from 'node:http';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport type { CorsOptions } from '../middleware/cors';\nimport type { ResponseFormatFn, ErrorFormatFn } from '../config/configTypes';\nimport type { FaapiContext } from '../runtime/contextTypes';\nimport type { FaapiMiddleware } from '../middleware/middlewareTypes';\nimport type { InjectorMap } from '../middleware/injectorTypes';\nimport type { RequestHandler, UpgradeHandler } from '../config/pluginTypes';\nimport { createServer } from './createServer';\n\nexport interface StartOptions {\n port: number;\n routes: RouteManifest;\n rootDir: string;\n cors?: CorsOptions | boolean;\n staticDir?: string;\n /** 统一响应格式化函数 */\n responseFormat?: ResponseFormatFn;\n /** 错误响应格式化函数(优先于内置 formatErrorResponse 处理;返回 null/undefined 表示不处理) */\n errorFormat?: ErrorFormatFn;\n /** 请求错误钩子(在错误响应生成后调用,用于副作用,不修改已发出的响应) */\n onError?: (error: unknown, ctx: FaapiContext) => Promise<void> | void;\n /** 自定义业务配置(来自 faapi.config.ts,注入到 ctx.config) */\n config?: Record<string, unknown>;\n /** WebSocket 路由清单 */\n wsRoutes?: WsRouteManifest;\n /** 全局中间件(来自 faapi.config.ts,对所有路由生效,最外层) */\n middlewares?: FaapiMiddleware[];\n /** 全局注入器(来自 faapi.config.ts,对所有路由 handler 参数注入生效) */\n injectors?: InjectorMap;\n /**\n * server.listen 之前的钩子(用于加载插件、应用 handler 包装等)\n *\n * 钩子在 server 创建后、listen 之前调用,可修改 server 的 request/upgrade listener。\n */\n beforeListen?: (server: Server) => Promise<void> | void;\n}\n\n/**\n * 启动 HTTP server 并打印路由表\n *\n * 流程:createServer → beforeListen(可选,加载插件/应用包装)→ listen → 打印路由表\n */\nexport function startServer(options: StartOptions): Promise<Server> {\n const {\n port,\n routes,\n rootDir,\n cors,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares,\n injectors,\n beforeListen,\n } = options;\n const server = createServer({\n routes,\n rootDir,\n cors,\n staticDir,\n responseFormat,\n errorFormat,\n onError,\n config,\n wsRoutes,\n middlewares,\n injectors,\n });\n\n return (async () => {\n // beforeListen 钩子:加载插件、应用 handler 包装等\n if (beforeListen) {\n await beforeListen(server);\n }\n\n return new Promise<Server>((resolve) => {\n server.listen(port, () => {\n const address = server.address();\n const actualPort = typeof address === 'object' && address !== null ? address.port : port;\n\n console.log('faapi dev server started');\n console.log(`- Local: http://localhost:${actualPort}`);\n console.log('- Loaded routes:');\n\n for (const route of routes) {\n const method = route.method.padEnd(6);\n console.log(` ${method}${route.urlPath} ${route.filePath}`);\n }\n\n if (wsRoutes && wsRoutes.length > 0) {\n console.log('- WebSocket routes:');\n for (const route of wsRoutes) {\n console.log(` WS ${route.urlPath} ${route.filePath}`);\n }\n }\n\n resolve(server);\n });\n });\n })();\n}\n\n/**\n * 应用 handler / upgrade 包装器到 server\n *\n * 在 server.listen 之前调用,替换 server 的 request/upgrade listener。\n * 包装器按数组顺序嵌套:finalHandler = wrap1(wrap2(originalHandler))。\n *\n * @param server 目标 server(未 listen)\n * @param handlerWrappers HTTP handler 包装器数组\n * @param upgradeWrappers WS upgrade handler 包装器数组\n */\nexport function applyPluginWrappers(\n server: Server,\n handlerWrappers: Array<(original: RequestHandler) => RequestHandler>,\n upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler>,\n): void {\n // 应用 HTTP handler 包装\n if (handlerWrappers.length > 0) {\n const listeners = server.listeners('request');\n const original = listeners[0] as RequestHandler | undefined;\n if (original) {\n server.removeAllListeners('request');\n let handler: RequestHandler = original;\n for (const wrap of handlerWrappers) {\n handler = wrap(handler);\n }\n server.on('request', handler);\n }\n }\n\n // 应用 WS upgrade handler 包装\n if (upgradeWrappers.length > 0) {\n const listeners = server.listeners('upgrade');\n const original = listeners[0] as UpgradeHandler | undefined;\n server.removeAllListeners('upgrade');\n let upgrade: UpgradeHandler | undefined = original;\n for (const wrap of upgradeWrappers) {\n upgrade = wrap(upgrade);\n }\n if (upgrade) {\n server.on('upgrade', upgrade);\n }\n }\n}\n","import { stat, lstat, readdir, realpath } from 'node:fs/promises';\nimport { Readable } from 'node:stream';\nimport { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from 'node:path';\nexport const EntryTypes = {\n FILE_TYPE: 'files',\n DIR_TYPE: 'directories',\n FILE_DIR_TYPE: 'files_directories',\n EVERYTHING_TYPE: 'all',\n};\nconst defaultOptions = {\n root: '.',\n fileFilter: (_entryInfo) => true,\n directoryFilter: (_entryInfo) => true,\n type: EntryTypes.FILE_TYPE,\n lstat: false,\n depth: 2147483648,\n alwaysStat: false,\n highWaterMark: 4096,\n};\nObject.freeze(defaultOptions);\nconst RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR';\nconst NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]);\nconst ALL_TYPES = [\n EntryTypes.DIR_TYPE,\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n EntryTypes.FILE_TYPE,\n];\nconst DIR_TYPES = new Set([\n EntryTypes.DIR_TYPE,\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n]);\nconst FILE_TYPES = new Set([\n EntryTypes.EVERYTHING_TYPE,\n EntryTypes.FILE_DIR_TYPE,\n EntryTypes.FILE_TYPE,\n]);\nconst isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code);\nconst wantBigintFsStats = process.platform === 'win32';\nconst emptyFn = (_entryInfo) => true;\nconst normalizeFilter = (filter) => {\n if (filter === undefined)\n return emptyFn;\n if (typeof filter === 'function')\n return filter;\n if (typeof filter === 'string') {\n const fl = filter.trim();\n return (entry) => entry.basename === fl;\n }\n if (Array.isArray(filter)) {\n const trItems = filter.map((item) => item.trim());\n return (entry) => trItems.some((f) => entry.basename === f);\n }\n return emptyFn;\n};\n/** Readable readdir stream, emitting new files as they're being listed. */\nexport class ReaddirpStream extends Readable {\n constructor(options = {}) {\n super({\n objectMode: true,\n autoDestroy: true,\n highWaterMark: options.highWaterMark,\n });\n const opts = { ...defaultOptions, ...options };\n const { root, type } = opts;\n this._fileFilter = normalizeFilter(opts.fileFilter);\n this._directoryFilter = normalizeFilter(opts.directoryFilter);\n const statMethod = opts.lstat ? lstat : stat;\n // Use bigint stats if it's windows and stat() supports options (node 10+).\n if (wantBigintFsStats) {\n this._stat = (path) => statMethod(path, { bigint: true });\n }\n else {\n this._stat = statMethod;\n }\n this._maxDepth = opts.depth ?? defaultOptions.depth;\n this._wantsDir = type ? DIR_TYPES.has(type) : false;\n this._wantsFile = type ? FILE_TYPES.has(type) : false;\n this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;\n this._root = presolve(root);\n this._isDirent = !opts.alwaysStat;\n this._statsProp = this._isDirent ? 'dirent' : 'stats';\n this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent };\n // Launch stream with one parent, the root dir.\n this.parents = [this._exploreDir(root, 1)];\n this.reading = false;\n this.parent = undefined;\n }\n async _read(batch) {\n if (this.reading)\n return;\n this.reading = true;\n try {\n while (!this.destroyed && batch > 0) {\n const par = this.parent;\n const fil = par && par.files;\n if (fil && fil.length > 0) {\n const { path, depth } = par;\n const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path));\n const awaited = await Promise.all(slice);\n for (const entry of awaited) {\n if (!entry)\n continue;\n if (this.destroyed)\n return;\n const entryType = await this._getEntryType(entry);\n if (entryType === 'directory' && this._directoryFilter(entry)) {\n if (depth <= this._maxDepth) {\n this.parents.push(this._exploreDir(entry.fullPath, depth + 1));\n }\n if (this._wantsDir) {\n this.push(entry);\n batch--;\n }\n }\n else if ((entryType === 'file' || this._includeAsFile(entry)) &&\n this._fileFilter(entry)) {\n if (this._wantsFile) {\n this.push(entry);\n batch--;\n }\n }\n }\n }\n else {\n const parent = this.parents.pop();\n if (!parent) {\n this.push(null);\n break;\n }\n this.parent = await parent;\n if (this.destroyed)\n return;\n }\n }\n }\n catch (error) {\n this.destroy(error);\n }\n finally {\n this.reading = false;\n }\n }\n async _exploreDir(path, depth) {\n let files;\n try {\n files = await readdir(path, this._rdOptions);\n }\n catch (error) {\n this._onError(error);\n }\n return { files, depth, path };\n }\n async _formatEntry(dirent, path) {\n let entry;\n const basename = this._isDirent ? dirent.name : dirent;\n try {\n const fullPath = presolve(pjoin(path, basename));\n entry = { path: prelative(this._root, fullPath), fullPath, basename };\n entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);\n }\n catch (err) {\n this._onError(err);\n return;\n }\n return entry;\n }\n _onError(err) {\n if (isNormalFlowError(err) && !this.destroyed) {\n this.emit('warn', err);\n }\n else {\n this.destroy(err);\n }\n }\n async _getEntryType(entry) {\n // entry may be undefined, because a warning or an error were emitted\n // and the statsProp is undefined\n if (!entry && this._statsProp in entry) {\n return '';\n }\n const stats = entry[this._statsProp];\n if (stats.isFile())\n return 'file';\n if (stats.isDirectory())\n return 'directory';\n if (stats && stats.isSymbolicLink()) {\n const full = entry.fullPath;\n try {\n const entryRealPath = await realpath(full);\n const entryRealPathStats = await lstat(entryRealPath);\n if (entryRealPathStats.isFile()) {\n return 'file';\n }\n if (entryRealPathStats.isDirectory()) {\n const len = entryRealPath.length;\n if (full.startsWith(entryRealPath) && full.substr(len, 1) === psep) {\n const recursiveError = new Error(`Circular symlink detected: \"${full}\" points to \"${entryRealPath}\"`);\n // @ts-ignore\n recursiveError.code = RECURSIVE_ERROR_CODE;\n return this._onError(recursiveError);\n }\n return 'directory';\n }\n }\n catch (error) {\n this._onError(error);\n return '';\n }\n }\n }\n _includeAsFile(entry) {\n const stats = entry && entry[this._statsProp];\n return stats && this._wantsEverything && !stats.isDirectory();\n }\n}\n/**\n * Streaming version: Reads all files and directories in given root recursively.\n * Consumes ~constant small amount of RAM.\n * @param root Root directory\n * @param options Options to specify root (start directory), filters and recursion depth\n */\nexport function readdirp(root, options = {}) {\n // @ts-ignore\n let type = options.entryType || options.type;\n if (type === 'both')\n type = EntryTypes.FILE_DIR_TYPE; // backwards-compatibility\n if (type)\n options.type = type;\n if (!root) {\n throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)');\n }\n else if (typeof root !== 'string') {\n throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)');\n }\n else if (type && !ALL_TYPES.includes(type)) {\n throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`);\n }\n options.root = root;\n return new ReaddirpStream(options);\n}\n/**\n * Promise version: Reads all files and directories in given root recursively.\n * Compared to streaming version, will consume a lot of RAM e.g. when 1 million files are listed.\n * @returns array of paths and their entry infos\n */\nexport function readdirpPromise(root, options = {}) {\n return new Promise((resolve, reject) => {\n const files = [];\n readdirp(root, options)\n .on('data', (entry) => files.push(entry))\n .on('end', () => resolve(files))\n .on('error', (error) => reject(error));\n });\n}\nexport default readdirp;\n","import { watchFile, unwatchFile, watch as fs_watch } from 'fs';\nimport { open, stat, lstat, realpath as fsrealpath } from 'fs/promises';\nimport * as sysPath from 'path';\nimport { type as osType } from 'os';\nexport const STR_DATA = 'data';\nexport const STR_END = 'end';\nexport const STR_CLOSE = 'close';\nexport const EMPTY_FN = () => { };\nexport const IDENTITY_FN = (val) => val;\nconst pl = process.platform;\nexport const isWindows = pl === 'win32';\nexport const isMacos = pl === 'darwin';\nexport const isLinux = pl === 'linux';\nexport const isFreeBSD = pl === 'freebsd';\nexport const isIBMi = osType() === 'OS400';\nexport const EVENTS = {\n ALL: 'all',\n READY: 'ready',\n ADD: 'add',\n CHANGE: 'change',\n ADD_DIR: 'addDir',\n UNLINK: 'unlink',\n UNLINK_DIR: 'unlinkDir',\n RAW: 'raw',\n ERROR: 'error',\n};\nconst EV = EVENTS;\nconst THROTTLE_MODE_WATCH = 'watch';\nconst statMethods = { lstat, stat };\nconst KEY_LISTENERS = 'listeners';\nconst KEY_ERR = 'errHandlers';\nconst KEY_RAW = 'rawEmitters';\nconst HANDLER_KEYS = [KEY_LISTENERS, KEY_ERR, KEY_RAW];\n// prettier-ignore\nconst binaryExtensions = new Set([\n '3dm', '3ds', '3g2', '3gp', '7z', 'a', 'aac', 'adp', 'afdesign', 'afphoto', 'afpub', 'ai',\n 'aif', 'aiff', 'alz', 'ape', 'apk', 'appimage', 'ar', 'arj', 'asf', 'au', 'avi',\n 'bak', 'baml', 'bh', 'bin', 'bk', 'bmp', 'btif', 'bz2', 'bzip2',\n 'cab', 'caf', 'cgm', 'class', 'cmx', 'cpio', 'cr2', 'cur', 'dat', 'dcm', 'deb', 'dex', 'djvu',\n 'dll', 'dmg', 'dng', 'doc', 'docm', 'docx', 'dot', 'dotm', 'dra', 'DS_Store', 'dsk', 'dts',\n 'dtshd', 'dvb', 'dwg', 'dxf',\n 'ecelp4800', 'ecelp7470', 'ecelp9600', 'egg', 'eol', 'eot', 'epub', 'exe',\n 'f4v', 'fbs', 'fh', 'fla', 'flac', 'flatpak', 'fli', 'flv', 'fpx', 'fst', 'fvt',\n 'g3', 'gh', 'gif', 'graffle', 'gz', 'gzip',\n 'h261', 'h263', 'h264', 'icns', 'ico', 'ief', 'img', 'ipa', 'iso',\n 'jar', 'jpeg', 'jpg', 'jpgv', 'jpm', 'jxr', 'key', 'ktx',\n 'lha', 'lib', 'lvp', 'lz', 'lzh', 'lzma', 'lzo',\n 'm3u', 'm4a', 'm4v', 'mar', 'mdi', 'mht', 'mid', 'midi', 'mj2', 'mka', 'mkv', 'mmr', 'mng',\n 'mobi', 'mov', 'movie', 'mp3',\n 'mp4', 'mp4a', 'mpeg', 'mpg', 'mpga', 'mxu',\n 'nef', 'npx', 'numbers', 'nupkg',\n 'o', 'odp', 'ods', 'odt', 'oga', 'ogg', 'ogv', 'otf', 'ott',\n 'pages', 'pbm', 'pcx', 'pdb', 'pdf', 'pea', 'pgm', 'pic', 'png', 'pnm', 'pot', 'potm',\n 'potx', 'ppa', 'ppam',\n 'ppm', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', 'psd', 'pya', 'pyc', 'pyo', 'pyv',\n 'qt',\n 'rar', 'ras', 'raw', 'resources', 'rgb', 'rip', 'rlc', 'rmf', 'rmvb', 'rpm', 'rtf', 'rz',\n 's3m', 's7z', 'scpt', 'sgi', 'shar', 'snap', 'sil', 'sketch', 'slk', 'smv', 'snk', 'so',\n 'stl', 'suo', 'sub', 'swf',\n 'tar', 'tbz', 'tbz2', 'tga', 'tgz', 'thmx', 'tif', 'tiff', 'tlz', 'ttc', 'ttf', 'txz',\n 'udf', 'uvh', 'uvi', 'uvm', 'uvp', 'uvs', 'uvu',\n 'viv', 'vob',\n 'war', 'wav', 'wax', 'wbmp', 'wdp', 'weba', 'webm', 'webp', 'whl', 'wim', 'wm', 'wma',\n 'wmv', 'wmx', 'woff', 'woff2', 'wrm', 'wvx',\n 'xbm', 'xif', 'xla', 'xlam', 'xls', 'xlsb', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', 'xm',\n 'xmind', 'xpi', 'xpm', 'xwd', 'xz',\n 'z', 'zip', 'zipx',\n]);\nconst isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());\n// TODO: emit errors properly. Example: EMFILE on Macos.\nconst foreach = (val, fn) => {\n if (val instanceof Set) {\n val.forEach(fn);\n }\n else {\n fn(val);\n }\n};\nconst addAndConvert = (main, prop, item) => {\n let container = main[prop];\n if (!(container instanceof Set)) {\n main[prop] = container = new Set([container]);\n }\n container.add(item);\n};\nconst clearItem = (cont) => (key) => {\n const set = cont[key];\n if (set instanceof Set) {\n set.clear();\n }\n else {\n delete cont[key];\n }\n};\nconst delFromSet = (main, prop, item) => {\n const container = main[prop];\n if (container instanceof Set) {\n container.delete(item);\n }\n else if (container === item) {\n delete main[prop];\n }\n};\nconst isEmptySet = (val) => (val instanceof Set ? val.size === 0 : !val);\nconst FsWatchInstances = new Map();\n/**\n * Instantiates the fs_watch interface\n * @param path to be watched\n * @param options to be passed to fs_watch\n * @param listener main event handler\n * @param errHandler emits info about errors\n * @param emitRaw emits raw event data\n * @returns {NativeFsWatcher}\n */\nfunction createFsWatchInstance(path, options, listener, errHandler, emitRaw) {\n const handleEvent = (rawEvent, evPath) => {\n listener(path);\n emitRaw(rawEvent, evPath, { watchedPath: path });\n // emit based on events occurring for files from a directory's watcher in\n // case the file's watcher misses it (and rely on throttling to de-dupe)\n if (evPath && path !== evPath) {\n fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));\n }\n };\n try {\n return fs_watch(path, {\n persistent: options.persistent,\n }, handleEvent);\n }\n catch (error) {\n errHandler(error);\n return undefined;\n }\n}\n/**\n * Helper for passing fs_watch event data to a collection of listeners\n * @param fullPath absolute path bound to fs_watch instance\n */\nconst fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {\n const cont = FsWatchInstances.get(fullPath);\n if (!cont)\n return;\n foreach(cont[listenerType], (listener) => {\n listener(val1, val2, val3);\n });\n};\n/**\n * Instantiates the fs_watch interface or binds listeners\n * to an existing one covering the same file system entry\n * @param path\n * @param fullPath absolute path\n * @param options to be passed to fs_watch\n * @param handlers container for event listener functions\n */\nconst setFsWatchListener = (path, fullPath, options, handlers) => {\n const { listener, errHandler, rawEmitter } = handlers;\n let cont = FsWatchInstances.get(fullPath);\n let watcher;\n if (!options.persistent) {\n watcher = createFsWatchInstance(path, options, listener, errHandler, rawEmitter);\n if (!watcher)\n return;\n return watcher.close.bind(watcher);\n }\n if (cont) {\n addAndConvert(cont, KEY_LISTENERS, listener);\n addAndConvert(cont, KEY_ERR, errHandler);\n addAndConvert(cont, KEY_RAW, rawEmitter);\n }\n else {\n watcher = createFsWatchInstance(path, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, // no need to use broadcast here\n fsWatchBroadcast.bind(null, fullPath, KEY_RAW));\n if (!watcher)\n return;\n watcher.on(EV.ERROR, async (error) => {\n const broadcastErr = fsWatchBroadcast.bind(null, fullPath, KEY_ERR);\n if (cont)\n cont.watcherUnusable = true; // documented since Node 10.4.1\n // Workaround for https://github.com/joyent/node/issues/4337\n if (isWindows && error.code === 'EPERM') {\n try {\n const fd = await open(path, 'r');\n await fd.close();\n broadcastErr(error);\n }\n catch (err) {\n // do nothing\n }\n }\n else {\n broadcastErr(error);\n }\n });\n cont = {\n listeners: listener,\n errHandlers: errHandler,\n rawEmitters: rawEmitter,\n watcher,\n };\n FsWatchInstances.set(fullPath, cont);\n }\n // const index = cont.listeners.indexOf(listener);\n // removes this instance's listeners and closes the underlying fs_watch\n // instance if there are no more listeners left\n return () => {\n delFromSet(cont, KEY_LISTENERS, listener);\n delFromSet(cont, KEY_ERR, errHandler);\n delFromSet(cont, KEY_RAW, rawEmitter);\n if (isEmptySet(cont.listeners)) {\n // Check to protect against issue gh-730.\n // if (cont.watcherUnusable) {\n cont.watcher.close();\n // }\n FsWatchInstances.delete(fullPath);\n HANDLER_KEYS.forEach(clearItem(cont));\n // @ts-ignore\n cont.watcher = undefined;\n Object.freeze(cont);\n }\n };\n};\n// fs_watchFile helpers\n// object to hold per-process fs_watchFile instances\n// (may be shared across chokidar FSWatcher instances)\nconst FsWatchFileInstances = new Map();\n/**\n * Instantiates the fs_watchFile interface or binds listeners\n * to an existing one covering the same file system entry\n * @param path to be watched\n * @param fullPath absolute path\n * @param options options to be passed to fs_watchFile\n * @param handlers container for event listener functions\n * @returns closer\n */\nconst setFsWatchFileListener = (path, fullPath, options, handlers) => {\n const { listener, rawEmitter } = handlers;\n let cont = FsWatchFileInstances.get(fullPath);\n // let listeners = new Set();\n // let rawEmitters = new Set();\n const copts = cont && cont.options;\n if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {\n // \"Upgrade\" the watcher to persistence or a quicker interval.\n // This creates some unlikely edge case issues if the user mixes\n // settings in a very weird way, but solving for those cases\n // doesn't seem worthwhile for the added complexity.\n // listeners = cont.listeners;\n // rawEmitters = cont.rawEmitters;\n unwatchFile(fullPath);\n cont = undefined;\n }\n if (cont) {\n addAndConvert(cont, KEY_LISTENERS, listener);\n addAndConvert(cont, KEY_RAW, rawEmitter);\n }\n else {\n // TODO\n // listeners.add(listener);\n // rawEmitters.add(rawEmitter);\n cont = {\n listeners: listener,\n rawEmitters: rawEmitter,\n options,\n watcher: watchFile(fullPath, options, (curr, prev) => {\n foreach(cont.rawEmitters, (rawEmitter) => {\n rawEmitter(EV.CHANGE, fullPath, { curr, prev });\n });\n const currmtime = curr.mtimeMs;\n if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {\n foreach(cont.listeners, (listener) => listener(path, curr));\n }\n }),\n };\n FsWatchFileInstances.set(fullPath, cont);\n }\n // const index = cont.listeners.indexOf(listener);\n // Removes this instance's listeners and closes the underlying fs_watchFile\n // instance if there are no more listeners left.\n return () => {\n delFromSet(cont, KEY_LISTENERS, listener);\n delFromSet(cont, KEY_RAW, rawEmitter);\n if (isEmptySet(cont.listeners)) {\n FsWatchFileInstances.delete(fullPath);\n unwatchFile(fullPath);\n cont.options = cont.watcher = undefined;\n Object.freeze(cont);\n }\n };\n};\n/**\n * @mixin\n */\nexport class NodeFsHandler {\n constructor(fsW) {\n this.fsw = fsW;\n this._boundHandleError = (error) => fsW._handleError(error);\n }\n /**\n * Watch file for changes with fs_watchFile or fs_watch.\n * @param path to file or dir\n * @param listener on fs change\n * @returns closer for the watcher instance\n */\n _watchWithNodeFs(path, listener) {\n const opts = this.fsw.options;\n const directory = sysPath.dirname(path);\n const basename = sysPath.basename(path);\n const parent = this.fsw._getWatchedDir(directory);\n parent.add(basename);\n const absolutePath = sysPath.resolve(path);\n const options = {\n persistent: opts.persistent,\n };\n if (!listener)\n listener = EMPTY_FN;\n let closer;\n if (opts.usePolling) {\n const enableBin = opts.interval !== opts.binaryInterval;\n options.interval = enableBin && isBinaryPath(basename) ? opts.binaryInterval : opts.interval;\n closer = setFsWatchFileListener(path, absolutePath, options, {\n listener,\n rawEmitter: this.fsw._emitRaw,\n });\n }\n else {\n closer = setFsWatchListener(path, absolutePath, options, {\n listener,\n errHandler: this._boundHandleError,\n rawEmitter: this.fsw._emitRaw,\n });\n }\n return closer;\n }\n /**\n * Watch a file and emit add event if warranted.\n * @returns closer for the watcher instance\n */\n _handleFile(file, stats, initialAdd) {\n if (this.fsw.closed) {\n return;\n }\n const dirname = sysPath.dirname(file);\n const basename = sysPath.basename(file);\n const parent = this.fsw._getWatchedDir(dirname);\n // stats is always present\n let prevStats = stats;\n // if the file is already being watched, do nothing\n if (parent.has(basename))\n return;\n const listener = async (path, newStats) => {\n if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))\n return;\n if (!newStats || newStats.mtimeMs === 0) {\n try {\n const newStats = await stat(file);\n if (this.fsw.closed)\n return;\n // Check that change event was not fired because of changed only accessTime.\n const at = newStats.atimeMs;\n const mt = newStats.mtimeMs;\n if (!at || at <= mt || mt !== prevStats.mtimeMs) {\n this.fsw._emit(EV.CHANGE, file, newStats);\n }\n if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats.ino) {\n this.fsw._closeFile(path);\n prevStats = newStats;\n const closer = this._watchWithNodeFs(file, listener);\n if (closer)\n this.fsw._addPathCloser(path, closer);\n }\n else {\n prevStats = newStats;\n }\n }\n catch (error) {\n // Fix issues where mtime is null but file is still present\n this.fsw._remove(dirname, basename);\n }\n // add is about to be emitted if file not already tracked in parent\n }\n else if (parent.has(basename)) {\n // Check that change event was not fired because of changed only accessTime.\n const at = newStats.atimeMs;\n const mt = newStats.mtimeMs;\n if (!at || at <= mt || mt !== prevStats.mtimeMs) {\n this.fsw._emit(EV.CHANGE, file, newStats);\n }\n prevStats = newStats;\n }\n };\n // kick off the watcher\n const closer = this._watchWithNodeFs(file, listener);\n // emit an add event if we're supposed to\n if (!(initialAdd && this.fsw.options.ignoreInitial) && this.fsw._isntIgnored(file)) {\n if (!this.fsw._throttle(EV.ADD, file, 0))\n return;\n this.fsw._emit(EV.ADD, file, stats);\n }\n return closer;\n }\n /**\n * Handle symlinks encountered while reading a dir.\n * @param entry returned by readdirp\n * @param directory path of dir being read\n * @param path of this item\n * @param item basename of this item\n * @returns true if no more processing is needed for this entry.\n */\n async _handleSymlink(entry, directory, path, item) {\n if (this.fsw.closed) {\n return;\n }\n const full = entry.fullPath;\n const dir = this.fsw._getWatchedDir(directory);\n if (!this.fsw.options.followSymlinks) {\n // watch symlink directly (don't follow) and detect changes\n this.fsw._incrReadyCount();\n let linkPath;\n try {\n linkPath = await fsrealpath(path);\n }\n catch (e) {\n this.fsw._emitReady();\n return true;\n }\n if (this.fsw.closed)\n return;\n if (dir.has(item)) {\n if (this.fsw._symlinkPaths.get(full) !== linkPath) {\n this.fsw._symlinkPaths.set(full, linkPath);\n this.fsw._emit(EV.CHANGE, path, entry.stats);\n }\n }\n else {\n dir.add(item);\n this.fsw._symlinkPaths.set(full, linkPath);\n this.fsw._emit(EV.ADD, path, entry.stats);\n }\n this.fsw._emitReady();\n return true;\n }\n // don't follow the same symlink more than once\n if (this.fsw._symlinkPaths.has(full)) {\n return true;\n }\n this.fsw._symlinkPaths.set(full, true);\n }\n _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {\n // Normalize the directory name on Windows\n directory = sysPath.join(directory, '');\n throttler = this.fsw._throttle('readdir', directory, 1000);\n if (!throttler)\n return;\n const previous = this.fsw._getWatchedDir(wh.path);\n const current = new Set();\n let stream = this.fsw._readdirp(directory, {\n fileFilter: (entry) => wh.filterPath(entry),\n directoryFilter: (entry) => wh.filterDir(entry),\n });\n if (!stream)\n return;\n stream\n .on(STR_DATA, async (entry) => {\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n const item = entry.path;\n let path = sysPath.join(directory, item);\n current.add(item);\n if (entry.stats.isSymbolicLink() &&\n (await this._handleSymlink(entry, directory, path, item))) {\n return;\n }\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n // Files that present in current directory snapshot\n // but absent in previous are added to watch list and\n // emit `add` event.\n if (item === target || (!target && !previous.has(item))) {\n this.fsw._incrReadyCount();\n // ensure relativeness of path is preserved in case of watcher reuse\n path = sysPath.join(dir, sysPath.relative(dir, path));\n this._addToNodeFs(path, initialAdd, wh, depth + 1);\n }\n })\n .on(EV.ERROR, this._boundHandleError);\n return new Promise((resolve, reject) => {\n if (!stream)\n return reject();\n stream.once(STR_END, () => {\n if (this.fsw.closed) {\n stream = undefined;\n return;\n }\n const wasThrottled = throttler ? throttler.clear() : false;\n resolve(undefined);\n // Files that absent in current directory snapshot\n // but present in previous emit `remove` event\n // and are removed from @watched[directory].\n previous\n .getChildren()\n .filter((item) => {\n return item !== directory && !current.has(item);\n })\n .forEach((item) => {\n this.fsw._remove(directory, item);\n });\n stream = undefined;\n // one more time for any missed in case changes came in extremely quickly\n if (wasThrottled)\n this._handleRead(directory, false, wh, target, dir, depth, throttler);\n });\n });\n }\n /**\n * Read directory to add / remove files from `@watched` list and re-read it on change.\n * @param dir fs path\n * @param stats\n * @param initialAdd\n * @param depth relative to user-supplied path\n * @param target child path targeted for watch\n * @param wh Common watch helpers for this path\n * @param realpath\n * @returns closer for the watcher instance.\n */\n async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {\n const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));\n const tracked = parentDir.has(sysPath.basename(dir));\n if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {\n this.fsw._emit(EV.ADD_DIR, dir, stats);\n }\n // ensure dir is tracked (harmless if redundant)\n parentDir.add(sysPath.basename(dir));\n this.fsw._getWatchedDir(dir);\n let throttler;\n let closer;\n const oDepth = this.fsw.options.depth;\n if ((oDepth == null || depth <= oDepth) && !this.fsw._symlinkPaths.has(realpath)) {\n if (!target) {\n await this._handleRead(dir, initialAdd, wh, target, dir, depth, throttler);\n if (this.fsw.closed)\n return;\n }\n closer = this._watchWithNodeFs(dir, (dirPath, stats) => {\n // if current directory is removed, do nothing\n if (stats && stats.mtimeMs === 0)\n return;\n this._handleRead(dirPath, false, wh, target, dir, depth, throttler);\n });\n }\n return closer;\n }\n /**\n * Handle added file, directory, or glob pattern.\n * Delegates call to _handleFile / _handleDir after checks.\n * @param path to file or ir\n * @param initialAdd was the file added at watch instantiation?\n * @param priorWh depth relative to user-supplied path\n * @param depth Child path actually targeted for watch\n * @param target Child path actually targeted for watch\n */\n async _addToNodeFs(path, initialAdd, priorWh, depth, target) {\n const ready = this.fsw._emitReady;\n if (this.fsw._isIgnored(path) || this.fsw.closed) {\n ready();\n return false;\n }\n const wh = this.fsw._getWatchHelpers(path);\n if (priorWh) {\n wh.filterPath = (entry) => priorWh.filterPath(entry);\n wh.filterDir = (entry) => priorWh.filterDir(entry);\n }\n // evaluate what is at the path we're being asked to watch\n try {\n const stats = await statMethods[wh.statMethod](wh.watchPath);\n if (this.fsw.closed)\n return;\n if (this.fsw._isIgnored(wh.watchPath, stats)) {\n ready();\n return false;\n }\n const follow = this.fsw.options.followSymlinks;\n let closer;\n if (stats.isDirectory()) {\n const absPath = sysPath.resolve(path);\n const targetPath = follow ? await fsrealpath(path) : path;\n if (this.fsw.closed)\n return;\n closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);\n if (this.fsw.closed)\n return;\n // preserve this symlink's target path\n if (absPath !== targetPath && targetPath !== undefined) {\n this.fsw._symlinkPaths.set(absPath, targetPath);\n }\n }\n else if (stats.isSymbolicLink()) {\n const targetPath = follow ? await fsrealpath(path) : path;\n if (this.fsw.closed)\n return;\n const parent = sysPath.dirname(wh.watchPath);\n this.fsw._getWatchedDir(parent).add(wh.watchPath);\n this.fsw._emit(EV.ADD, wh.watchPath, stats);\n closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);\n if (this.fsw.closed)\n return;\n // preserve this symlink's target path\n if (targetPath !== undefined) {\n this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);\n }\n }\n else {\n closer = this._handleFile(wh.watchPath, stats, initialAdd);\n }\n ready();\n if (closer)\n this.fsw._addPathCloser(path, closer);\n return false;\n }\n catch (error) {\n if (this.fsw._handleError(error)) {\n ready();\n return path;\n }\n }\n }\n}\n","/*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */\nimport { stat as statcb } from 'fs';\nimport { stat, readdir } from 'fs/promises';\nimport { EventEmitter } from 'events';\nimport * as sysPath from 'path';\nimport { readdirp } from 'readdirp';\nimport { NodeFsHandler, EVENTS as EV, isWindows, isIBMi, EMPTY_FN, STR_CLOSE, STR_END, } from './handler.js';\nconst SLASH = '/';\nconst SLASH_SLASH = '//';\nconst ONE_DOT = '.';\nconst TWO_DOTS = '..';\nconst STRING_TYPE = 'string';\nconst BACK_SLASH_RE = /\\\\/g;\nconst DOUBLE_SLASH_RE = /\\/\\//;\nconst DOT_RE = /\\..*\\.(sw[px])$|~$|\\.subl.*\\.tmp/;\nconst REPLACER_RE = /^\\.[/\\\\]/;\nfunction arrify(item) {\n return Array.isArray(item) ? item : [item];\n}\nconst isMatcherObject = (matcher) => typeof matcher === 'object' && matcher !== null && !(matcher instanceof RegExp);\nfunction createPattern(matcher) {\n if (typeof matcher === 'function')\n return matcher;\n if (typeof matcher === 'string')\n return (string) => matcher === string;\n if (matcher instanceof RegExp)\n return (string) => matcher.test(string);\n if (typeof matcher === 'object' && matcher !== null) {\n return (string) => {\n if (matcher.path === string)\n return true;\n if (matcher.recursive) {\n const relative = sysPath.relative(matcher.path, string);\n if (!relative) {\n return false;\n }\n return !relative.startsWith('..') && !sysPath.isAbsolute(relative);\n }\n return false;\n };\n }\n return () => false;\n}\nfunction normalizePath(path) {\n if (typeof path !== 'string')\n throw new Error('string expected');\n path = sysPath.normalize(path);\n path = path.replace(/\\\\/g, '/');\n let prepend = false;\n if (path.startsWith('//'))\n prepend = true;\n const DOUBLE_SLASH_RE = /\\/\\//;\n while (path.match(DOUBLE_SLASH_RE))\n path = path.replace(DOUBLE_SLASH_RE, '/');\n if (prepend)\n path = '/' + path;\n return path;\n}\nfunction matchPatterns(patterns, testString, stats) {\n const path = normalizePath(testString);\n for (let index = 0; index < patterns.length; index++) {\n const pattern = patterns[index];\n if (pattern(path, stats)) {\n return true;\n }\n }\n return false;\n}\nfunction anymatch(matchers, testString) {\n if (matchers == null) {\n throw new TypeError('anymatch: specify first argument');\n }\n // Early cache for matchers.\n const matchersArray = arrify(matchers);\n const patterns = matchersArray.map((matcher) => createPattern(matcher));\n if (testString == null) {\n return (testString, stats) => {\n return matchPatterns(patterns, testString, stats);\n };\n }\n return matchPatterns(patterns, testString);\n}\nconst unifyPaths = (paths_) => {\n const paths = arrify(paths_).flat();\n if (!paths.every((p) => typeof p === STRING_TYPE)) {\n throw new TypeError(`Non-string provided as watch path: ${paths}`);\n }\n return paths.map(normalizePathToUnix);\n};\n// If SLASH_SLASH occurs at the beginning of path, it is not replaced\n// because \"//StoragePC/DrivePool/Movies\" is a valid network path\nconst toUnix = (string) => {\n let str = string.replace(BACK_SLASH_RE, SLASH);\n let prepend = false;\n if (str.startsWith(SLASH_SLASH)) {\n prepend = true;\n }\n while (str.match(DOUBLE_SLASH_RE)) {\n str = str.replace(DOUBLE_SLASH_RE, SLASH);\n }\n if (prepend) {\n str = SLASH + str;\n }\n return str;\n};\n// Our version of upath.normalize\n// TODO: this is not equal to path-normalize module - investigate why\nconst normalizePathToUnix = (path) => toUnix(sysPath.normalize(toUnix(path)));\n// TODO: refactor\nconst normalizeIgnored = (cwd = '') => (path) => {\n if (typeof path === 'string') {\n return normalizePathToUnix(sysPath.isAbsolute(path) ? path : sysPath.join(cwd, path));\n }\n else {\n return path;\n }\n};\nconst getAbsolutePath = (path, cwd) => {\n if (sysPath.isAbsolute(path)) {\n return path;\n }\n return sysPath.join(cwd, path);\n};\nconst EMPTY_SET = Object.freeze(new Set());\n/**\n * Directory entry.\n */\nclass DirEntry {\n constructor(dir, removeWatcher) {\n this.path = dir;\n this._removeWatcher = removeWatcher;\n this.items = new Set();\n }\n add(item) {\n const { items } = this;\n if (!items)\n return;\n if (item !== ONE_DOT && item !== TWO_DOTS)\n items.add(item);\n }\n async remove(item) {\n const { items } = this;\n if (!items)\n return;\n items.delete(item);\n if (items.size > 0)\n return;\n const dir = this.path;\n try {\n await readdir(dir);\n }\n catch (err) {\n if (this._removeWatcher) {\n this._removeWatcher(sysPath.dirname(dir), sysPath.basename(dir));\n }\n }\n }\n has(item) {\n const { items } = this;\n if (!items)\n return;\n return items.has(item);\n }\n getChildren() {\n const { items } = this;\n if (!items)\n return [];\n return [...items.values()];\n }\n dispose() {\n this.items.clear();\n this.path = '';\n this._removeWatcher = EMPTY_FN;\n this.items = EMPTY_SET;\n Object.freeze(this);\n }\n}\nconst STAT_METHOD_F = 'stat';\nconst STAT_METHOD_L = 'lstat';\nexport class WatchHelper {\n constructor(path, follow, fsw) {\n this.fsw = fsw;\n const watchPath = path;\n this.path = path = path.replace(REPLACER_RE, '');\n this.watchPath = watchPath;\n this.fullWatchPath = sysPath.resolve(watchPath);\n this.dirParts = [];\n this.dirParts.forEach((parts) => {\n if (parts.length > 1)\n parts.pop();\n });\n this.followSymlinks = follow;\n this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;\n }\n entryPath(entry) {\n return sysPath.join(this.watchPath, sysPath.relative(this.watchPath, entry.fullPath));\n }\n filterPath(entry) {\n const { stats } = entry;\n if (stats && stats.isSymbolicLink())\n return this.filterDir(entry);\n const resolvedPath = this.entryPath(entry);\n // TODO: what if stats is undefined? remove !\n return this.fsw._isntIgnored(resolvedPath, stats) && this.fsw._hasReadPermissions(stats);\n }\n filterDir(entry) {\n return this.fsw._isntIgnored(this.entryPath(entry), entry.stats);\n }\n}\n/**\n * Watches files & directories for changes. Emitted events:\n * `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `all`, `error`\n *\n * new FSWatcher()\n * .add(directories)\n * .on('add', path => log('File', path, 'was added'))\n */\nexport class FSWatcher extends EventEmitter {\n // Not indenting methods for history sake; for now.\n constructor(_opts = {}) {\n super();\n this.closed = false;\n this._closers = new Map();\n this._ignoredPaths = new Set();\n this._throttled = new Map();\n this._streams = new Set();\n this._symlinkPaths = new Map();\n this._watched = new Map();\n this._pendingWrites = new Map();\n this._pendingUnlinks = new Map();\n this._readyCount = 0;\n this._readyEmitted = false;\n const awf = _opts.awaitWriteFinish;\n const DEF_AWF = { stabilityThreshold: 2000, pollInterval: 100 };\n const opts = {\n // Defaults\n persistent: true,\n ignoreInitial: false,\n ignorePermissionErrors: false,\n interval: 100,\n binaryInterval: 300,\n followSymlinks: true,\n usePolling: false,\n // useAsync: false,\n atomic: true, // NOTE: overwritten later (depends on usePolling)\n ..._opts,\n // Change format\n ignored: _opts.ignored ? arrify(_opts.ignored) : arrify([]),\n awaitWriteFinish: awf === true ? DEF_AWF : typeof awf === 'object' ? { ...DEF_AWF, ...awf } : false,\n };\n // Always default to polling on IBM i because fs.watch() is not available on IBM i.\n if (isIBMi)\n opts.usePolling = true;\n // Editor atomic write normalization enabled by default with fs.watch\n if (opts.atomic === undefined)\n opts.atomic = !opts.usePolling;\n // opts.atomic = typeof _opts.atomic === 'number' ? _opts.atomic : 100;\n // Global override. Useful for developers, who need to force polling for all\n // instances of chokidar, regardless of usage / dependency depth\n const envPoll = process.env.CHOKIDAR_USEPOLLING;\n if (envPoll !== undefined) {\n const envLower = envPoll.toLowerCase();\n if (envLower === 'false' || envLower === '0')\n opts.usePolling = false;\n else if (envLower === 'true' || envLower === '1')\n opts.usePolling = true;\n else\n opts.usePolling = !!envLower;\n }\n const envInterval = process.env.CHOKIDAR_INTERVAL;\n if (envInterval)\n opts.interval = Number.parseInt(envInterval, 10);\n // This is done to emit ready only once, but each 'add' will increase that?\n let readyCalls = 0;\n this._emitReady = () => {\n readyCalls++;\n if (readyCalls >= this._readyCount) {\n this._emitReady = EMPTY_FN;\n this._readyEmitted = true;\n // use process.nextTick to allow time for listener to be bound\n process.nextTick(() => this.emit(EV.READY));\n }\n };\n this._emitRaw = (...args) => this.emit(EV.RAW, ...args);\n this._boundRemove = this._remove.bind(this);\n this.options = opts;\n this._nodeFsHandler = new NodeFsHandler(this);\n // You’re frozen when your heart’s not open.\n Object.freeze(opts);\n }\n _addIgnoredPath(matcher) {\n if (isMatcherObject(matcher)) {\n // return early if we already have a deeply equal matcher object\n for (const ignored of this._ignoredPaths) {\n if (isMatcherObject(ignored) &&\n ignored.path === matcher.path &&\n ignored.recursive === matcher.recursive) {\n return;\n }\n }\n }\n this._ignoredPaths.add(matcher);\n }\n _removeIgnoredPath(matcher) {\n this._ignoredPaths.delete(matcher);\n // now find any matcher objects with the matcher as path\n if (typeof matcher === 'string') {\n for (const ignored of this._ignoredPaths) {\n // TODO (43081j): make this more efficient.\n // probably just make a `this._ignoredDirectories` or some\n // such thing.\n if (isMatcherObject(ignored) && ignored.path === matcher) {\n this._ignoredPaths.delete(ignored);\n }\n }\n }\n }\n // Public methods\n /**\n * Adds paths to be watched on an existing FSWatcher instance.\n * @param paths_ file or file list. Other arguments are unused\n */\n add(paths_, _origAdd, _internal) {\n const { cwd } = this.options;\n this.closed = false;\n this._closePromise = undefined;\n let paths = unifyPaths(paths_);\n if (cwd) {\n paths = paths.map((path) => {\n const absPath = getAbsolutePath(path, cwd);\n // Check `path` instead of `absPath` because the cwd portion can't be a glob\n return absPath;\n });\n }\n paths.forEach((path) => {\n this._removeIgnoredPath(path);\n });\n this._userIgnored = undefined;\n if (!this._readyCount)\n this._readyCount = 0;\n this._readyCount += paths.length;\n Promise.all(paths.map(async (path) => {\n const res = await this._nodeFsHandler._addToNodeFs(path, !_internal, undefined, 0, _origAdd);\n if (res)\n this._emitReady();\n return res;\n })).then((results) => {\n if (this.closed)\n return;\n results.forEach((item) => {\n if (item)\n this.add(sysPath.dirname(item), sysPath.basename(_origAdd || item));\n });\n });\n return this;\n }\n /**\n * Close watchers or start ignoring events from specified paths.\n */\n unwatch(paths_) {\n if (this.closed)\n return this;\n const paths = unifyPaths(paths_);\n const { cwd } = this.options;\n paths.forEach((path) => {\n // convert to absolute path unless relative path already matches\n if (!sysPath.isAbsolute(path) && !this._closers.has(path)) {\n if (cwd)\n path = sysPath.join(cwd, path);\n path = sysPath.resolve(path);\n }\n this._closePath(path);\n this._addIgnoredPath(path);\n if (this._watched.has(path)) {\n this._addIgnoredPath({\n path,\n recursive: true,\n });\n }\n // reset the cached userIgnored anymatch fn\n // to make ignoredPaths changes effective\n this._userIgnored = undefined;\n });\n return this;\n }\n /**\n * Close watchers and remove all listeners from watched paths.\n */\n close() {\n if (this._closePromise) {\n return this._closePromise;\n }\n this.closed = true;\n // Memory management.\n this.removeAllListeners();\n const closers = [];\n this._closers.forEach((closerList) => closerList.forEach((closer) => {\n const promise = closer();\n if (promise instanceof Promise)\n closers.push(promise);\n }));\n this._streams.forEach((stream) => stream.destroy());\n this._userIgnored = undefined;\n this._readyCount = 0;\n this._readyEmitted = false;\n this._watched.forEach((dirent) => dirent.dispose());\n this._closers.clear();\n this._watched.clear();\n this._streams.clear();\n this._symlinkPaths.clear();\n this._throttled.clear();\n this._closePromise = closers.length\n ? Promise.all(closers).then(() => undefined)\n : Promise.resolve();\n return this._closePromise;\n }\n /**\n * Expose list of watched paths\n * @returns for chaining\n */\n getWatched() {\n const watchList = {};\n this._watched.forEach((entry, dir) => {\n const key = this.options.cwd ? sysPath.relative(this.options.cwd, dir) : dir;\n const index = key || ONE_DOT;\n watchList[index] = entry.getChildren().sort();\n });\n return watchList;\n }\n emitWithAll(event, args) {\n this.emit(event, ...args);\n if (event !== EV.ERROR)\n this.emit(EV.ALL, event, ...args);\n }\n // Common helpers\n // --------------\n /**\n * Normalize and emit events.\n * Calling _emit DOES NOT MEAN emit() would be called!\n * @param event Type of event\n * @param path File or directory path\n * @param stats arguments to be passed with event\n * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag\n */\n async _emit(event, path, stats) {\n if (this.closed)\n return;\n const opts = this.options;\n if (isWindows)\n path = sysPath.normalize(path);\n if (opts.cwd)\n path = sysPath.relative(opts.cwd, path);\n const args = [path];\n if (stats != null)\n args.push(stats);\n const awf = opts.awaitWriteFinish;\n let pw;\n if (awf && (pw = this._pendingWrites.get(path))) {\n pw.lastChange = new Date();\n return this;\n }\n if (opts.atomic) {\n if (event === EV.UNLINK) {\n this._pendingUnlinks.set(path, [event, ...args]);\n setTimeout(() => {\n this._pendingUnlinks.forEach((entry, path) => {\n this.emit(...entry);\n this.emit(EV.ALL, ...entry);\n this._pendingUnlinks.delete(path);\n });\n }, typeof opts.atomic === 'number' ? opts.atomic : 100);\n return this;\n }\n if (event === EV.ADD && this._pendingUnlinks.has(path)) {\n event = EV.CHANGE;\n this._pendingUnlinks.delete(path);\n }\n }\n if (awf && (event === EV.ADD || event === EV.CHANGE) && this._readyEmitted) {\n const awfEmit = (err, stats) => {\n if (err) {\n event = EV.ERROR;\n args[0] = err;\n this.emitWithAll(event, args);\n }\n else if (stats) {\n // if stats doesn't exist the file must have been deleted\n if (args.length > 1) {\n args[1] = stats;\n }\n else {\n args.push(stats);\n }\n this.emitWithAll(event, args);\n }\n };\n this._awaitWriteFinish(path, awf.stabilityThreshold, event, awfEmit);\n return this;\n }\n if (event === EV.CHANGE) {\n const isThrottled = !this._throttle(EV.CHANGE, path, 50);\n if (isThrottled)\n return this;\n }\n if (opts.alwaysStat &&\n stats === undefined &&\n (event === EV.ADD || event === EV.ADD_DIR || event === EV.CHANGE)) {\n const fullPath = opts.cwd ? sysPath.join(opts.cwd, path) : path;\n let stats;\n try {\n stats = await stat(fullPath);\n }\n catch (err) {\n // do nothing\n }\n // Suppress event when fs_stat fails, to avoid sending undefined 'stat'\n if (!stats || this.closed)\n return;\n args.push(stats);\n }\n this.emitWithAll(event, args);\n return this;\n }\n /**\n * Common handler for errors\n * @returns The error if defined, otherwise the value of the FSWatcher instance's `closed` flag\n */\n _handleError(error) {\n const code = error && error.code;\n if (error &&\n code !== 'ENOENT' &&\n code !== 'ENOTDIR' &&\n (!this.options.ignorePermissionErrors || (code !== 'EPERM' && code !== 'EACCES'))) {\n this.emit(EV.ERROR, error);\n }\n return error || this.closed;\n }\n /**\n * Helper utility for throttling\n * @param actionType type being throttled\n * @param path being acted upon\n * @param timeout duration of time to suppress duplicate actions\n * @returns tracking object or false if action should be suppressed\n */\n _throttle(actionType, path, timeout) {\n if (!this._throttled.has(actionType)) {\n this._throttled.set(actionType, new Map());\n }\n const action = this._throttled.get(actionType);\n if (!action)\n throw new Error('invalid throttle');\n const actionPath = action.get(path);\n if (actionPath) {\n actionPath.count++;\n return false;\n }\n // eslint-disable-next-line prefer-const\n let timeoutObject;\n const clear = () => {\n const item = action.get(path);\n const count = item ? item.count : 0;\n action.delete(path);\n clearTimeout(timeoutObject);\n if (item)\n clearTimeout(item.timeoutObject);\n return count;\n };\n timeoutObject = setTimeout(clear, timeout);\n const thr = { timeoutObject, clear, count: 0 };\n action.set(path, thr);\n return thr;\n }\n _incrReadyCount() {\n return this._readyCount++;\n }\n /**\n * Awaits write operation to finish.\n * Polls a newly created file for size variations. When files size does not change for 'threshold' milliseconds calls callback.\n * @param path being acted upon\n * @param threshold Time in milliseconds a file size must be fixed before acknowledging write OP is finished\n * @param event\n * @param awfEmit Callback to be called when ready for event to be emitted.\n */\n _awaitWriteFinish(path, threshold, event, awfEmit) {\n const awf = this.options.awaitWriteFinish;\n if (typeof awf !== 'object')\n return;\n const pollInterval = awf.pollInterval;\n let timeoutHandler;\n let fullPath = path;\n if (this.options.cwd && !sysPath.isAbsolute(path)) {\n fullPath = sysPath.join(this.options.cwd, path);\n }\n const now = new Date();\n const writes = this._pendingWrites;\n function awaitWriteFinishFn(prevStat) {\n statcb(fullPath, (err, curStat) => {\n if (err || !writes.has(path)) {\n if (err && err.code !== 'ENOENT')\n awfEmit(err);\n return;\n }\n const now = Number(new Date());\n if (prevStat && curStat.size !== prevStat.size) {\n writes.get(path).lastChange = now;\n }\n const pw = writes.get(path);\n const df = now - pw.lastChange;\n if (df >= threshold) {\n writes.delete(path);\n awfEmit(undefined, curStat);\n }\n else {\n timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);\n }\n });\n }\n if (!writes.has(path)) {\n writes.set(path, {\n lastChange: now,\n cancelWait: () => {\n writes.delete(path);\n clearTimeout(timeoutHandler);\n return event;\n },\n });\n timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);\n }\n }\n /**\n * Determines whether user has asked to ignore this path.\n */\n _isIgnored(path, stats) {\n if (this.options.atomic && DOT_RE.test(path))\n return true;\n if (!this._userIgnored) {\n const { cwd } = this.options;\n const ign = this.options.ignored;\n const ignored = (ign || []).map(normalizeIgnored(cwd));\n const ignoredPaths = [...this._ignoredPaths];\n const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];\n this._userIgnored = anymatch(list, undefined);\n }\n return this._userIgnored(path, stats);\n }\n _isntIgnored(path, stat) {\n return !this._isIgnored(path, stat);\n }\n /**\n * Provides a set of common helpers and properties relating to symlink handling.\n * @param path file or directory pattern being watched\n */\n _getWatchHelpers(path) {\n return new WatchHelper(path, this.options.followSymlinks, this);\n }\n // Directory helpers\n // -----------------\n /**\n * Provides directory tracking objects\n * @param directory path of the directory\n */\n _getWatchedDir(directory) {\n const dir = sysPath.resolve(directory);\n if (!this._watched.has(dir))\n this._watched.set(dir, new DirEntry(dir, this._boundRemove));\n return this._watched.get(dir);\n }\n // File helpers\n // ------------\n /**\n * Check for read permissions: https://stackoverflow.com/a/11781404/1358405\n */\n _hasReadPermissions(stats) {\n if (this.options.ignorePermissionErrors)\n return true;\n return Boolean(Number(stats.mode) & 0o400);\n }\n /**\n * Handles emitting unlink events for\n * files and directories, and via recursion, for\n * files and directories within directories that are unlinked\n * @param directory within which the following item is located\n * @param item base path of item/directory\n */\n _remove(directory, item, isDirectory) {\n // if what is being deleted is a directory, get that directory's paths\n // for recursive deleting and cleaning of watched object\n // if it is not a directory, nestedDirectoryChildren will be empty array\n const path = sysPath.join(directory, item);\n const fullPath = sysPath.resolve(path);\n isDirectory =\n isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);\n // prevent duplicate handling in case of arriving here nearly simultaneously\n // via multiple paths (such as _handleFile and _handleDir)\n if (!this._throttle('remove', path, 100))\n return;\n // if the only watched file is removed, watch for its return\n if (!isDirectory && this._watched.size === 1) {\n this.add(directory, item, true);\n }\n // This will create a new entry in the watched object in either case\n // so we got to do the directory check beforehand\n const wp = this._getWatchedDir(path);\n const nestedDirectoryChildren = wp.getChildren();\n // Recursively remove children directories / files.\n nestedDirectoryChildren.forEach((nested) => this._remove(path, nested));\n // Check if item was on the watched list and remove it\n const parent = this._getWatchedDir(directory);\n const wasTracked = parent.has(item);\n parent.remove(item);\n // Fixes issue #1042 -> Relative paths were detected and added as symlinks\n // (https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L612),\n // but never removed from the map in case the path was deleted.\n // This leads to an incorrect state if the path was recreated:\n // https://github.com/paulmillr/chokidar/blob/e1753ddbc9571bdc33b4a4af172d52cb6e611c10/lib/nodefs-handler.js#L553\n if (this._symlinkPaths.has(fullPath)) {\n this._symlinkPaths.delete(fullPath);\n }\n // If we wait for this file to be fully written, cancel the wait.\n let relPath = path;\n if (this.options.cwd)\n relPath = sysPath.relative(this.options.cwd, path);\n if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {\n const event = this._pendingWrites.get(relPath).cancelWait();\n if (event === EV.ADD)\n return;\n }\n // The Entry will either be a directory that just got removed\n // or a bogus entry to a file, in either case we have to remove it\n this._watched.delete(path);\n this._watched.delete(fullPath);\n const eventName = isDirectory ? EV.UNLINK_DIR : EV.UNLINK;\n if (wasTracked && !this._isIgnored(path))\n this._emit(eventName, path);\n // Avoid conflicts if we later create another file with the same name\n this._closePath(path);\n }\n /**\n * Closes all watchers for a path\n */\n _closePath(path) {\n this._closeFile(path);\n const dir = sysPath.dirname(path);\n this._getWatchedDir(dir).remove(sysPath.basename(path));\n }\n /**\n * Closes only file-specific watchers\n */\n _closeFile(path) {\n const closers = this._closers.get(path);\n if (!closers)\n return;\n closers.forEach((closer) => closer());\n this._closers.delete(path);\n }\n _addPathCloser(path, closer) {\n if (!closer)\n return;\n let list = this._closers.get(path);\n if (!list) {\n list = [];\n this._closers.set(path, list);\n }\n list.push(closer);\n }\n _readdirp(root, opts) {\n if (this.closed)\n return;\n const options = { type: EV.ALL, alwaysStat: true, lstat: true, ...opts, depth: 0 };\n let stream = readdirp(root, options);\n this._streams.add(stream);\n stream.once(STR_CLOSE, () => {\n stream = undefined;\n });\n stream.once(STR_END, () => {\n if (stream) {\n this._streams.delete(stream);\n stream = undefined;\n }\n });\n return stream;\n }\n}\n/**\n * Instantiates watcher with paths to be tracked.\n * @param paths file / directory paths\n * @param options opts, such as `atomic`, `awaitWriteFinish`, `ignored`, and others\n * @returns an instance of FSWatcher for chaining.\n * @example\n * const watcher = watch('.').on('all', (event, path) => { console.log(event, path); });\n * watch('.', { atomic: true, awaitWriteFinish: true, ignored: (f, stats) => stats?.isFile() && !f.endsWith('.js') })\n */\nexport function watch(paths, options = {}) {\n const watcher = new FSWatcher(options);\n watcher.add(paths);\n return watcher;\n}\nexport default { watch, FSWatcher };\n","import chokidar from 'chokidar';\nimport type { Server } from 'node:http';\nimport path from 'node:path';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\nimport { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { invalidateMiddlewareCache } from '../middleware/loadMiddlewares';\nimport { invalidateProgramCache } from '../ast/createProgram';\nimport { generateSchemaFile, loadSchemaToRegistry } from './generateSchema';\nimport { compileRoutes } from './compileRoutes';\n\n/** dev 模式产物目录(与 startCommand 保持一致) */\nconst DEV_OUT_DIR = '.faapi/dev';\n\nexport interface WatchOptions {\n rootDir: string;\n patterns: string[];\n appDir: string;\n server: Server;\n port: number;\n cors?: boolean;\n staticDir?: string;\n types?: string;\n}\n\n/**\n * 启动 watch 模式(仅 dev)\n *\n * 参考 Next.js dev 模式:监听源码 `.ts` 变化,增量编译到 `.faapi/dev/`,热替换路由。\n *\n * chokidar v4 移除了 glob 模式支持,改为监听整个 `appDir` 目录 + `ignored` 函数过滤。\n * 监听整个 appDir 比 glob 更合理:handler.ts 引用的 util.ts 变化也能触发重建。\n *\n * 重建流程(debounce 100ms):\n * 1. 更新 `__FAAPI_LOAD_TS__`(ESM import 时拼接时间戳绕过缓存)\n * 2. 清理中间件 + Program 缓存(避免加载旧版本)\n * 3. 增量编译变化的文件(compileRoutes with files 参数,只编译 add/change 的文件)\n * 4. 全量扫描路由(import 产物 .js,filePath 保持源码 .ts)\n * 5. 重新生成 schema 文件(.faapi/dev/faapi-schema.js)\n * 6. 重新加载 schema(readManifestFile + schemaRegistry.loadManifest)\n * 7. 更新 server 路由引用(globalThis.__FAAPI_ROUTES__ / __FAAPI_WS_ROUTES__)\n *\n * 增量编译 + 全量扫描的理由:\n * - 增量编译:只编译变化的文件,速度快\n * - 全量扫描:路由结构可能变化(新增/删除 handler.ts),需要全量扫描保证一致性;\n * scanRoutes 内部用 importWithCacheBust,已更新时间戳后会重新 import 产物\n *\n * unlink(文件删除)不增量编译(无文件可编译),但触发全量扫描,\n * scanRoutes 通过 patterns glob 自然排除已删除的文件。\n */\nexport function startWatcher(options: WatchOptions): void {\n const { rootDir, patterns, appDir } = options;\n\n // 重建定时器(debounce)\n let rebuildTimer: ReturnType<typeof setTimeout> | null = null;\n // 累积变化的文件(绝对路径),用于增量编译\n let pendingFiles: Set<string> = new Set();\n\n async function rebuildRoutes(): Promise<void> {\n try {\n // 1. 更新模块加载时间戳,ESM import 时拼接该时间戳绕过缓存\n const timestamp = Date.now();\n (globalThis as Record<string, unknown>).__FAAPI_LOAD_TS__ = timestamp;\n\n // 2. 清理所有缓存(中间件 + Program)\n invalidateMiddlewareCache();\n invalidateProgramCache();\n\n // 3. 增量编译变化的文件(add/change 事件累积的文件)\n const filesToCompile = Array.from(pendingFiles);\n pendingFiles = new Set();\n if (filesToCompile.length > 0) {\n await compileRoutes({\n rootDir,\n appDir,\n outDir: DEV_OUT_DIR,\n files: filesToCompile,\n });\n }\n\n // 4. 重新扫描路由(全量扫描,import 产物 .js 拿方法名)\n const { routes, wsRoutes } = await scanRoutes(rootDir, patterns, appDir, DEV_OUT_DIR);\n const sorted = sortRoutes(routes);\n\n // 5. 重新生成 schema 文件(AST 从源码 .ts)\n const schemaPath = path.resolve(rootDir, DEV_OUT_DIR, 'faapi-schema.js');\n await generateSchemaFile(sorted, rootDir, schemaPath);\n\n // 6. 重新加载 schema(dev 模式 route.filePath 是源码路径,不需要 remap)\n await loadSchemaToRegistry(schemaPath, rootDir, DEV_OUT_DIR, false);\n\n // 7. 更新服务器的路由引用(HTTP + WS)\n updateServerRoutes(sorted, wsRoutes);\n\n const recompiledCount = filesToCompile.length;\n console.log(\n `- Routes rebuilt: ${sorted.length} route(s), ${wsRoutes.length} WS route(s)${recompiledCount > 0 ? `, ${recompiledCount} file(s) recompiled` : ''}`,\n );\n } catch (err) {\n console.error('- Error rebuilding routes:', err instanceof Error ? err.message : String(err));\n }\n }\n\n // debounce 重建:编辑器保存时可能触发多次写操作\n function scheduleRebuild(): void {\n if (rebuildTimer) clearTimeout(rebuildTimer);\n rebuildTimer = setTimeout(() => {\n rebuildTimer = null;\n void rebuildRoutes();\n }, 100);\n }\n\n // 监听文件变化\n // chokidar v4 移除了 glob 模式支持,改为监听 appDir 整个目录 + ignored 函数过滤\n // 监听整个 appDir 比 glob 更合理:handler.ts 引用的 util.ts 变化也能触发重建\n const watcher = chokidar.watch(appDir, {\n cwd: rootDir,\n ignoreInitial: true,\n ignored: (filePath, stats) => {\n // 忽略非源码目录\n if (\n filePath.includes('node_modules') ||\n filePath.includes('.faapi') ||\n filePath.includes('dist') ||\n filePath.includes('.git')\n ) {\n return true;\n }\n // 无 stats 时不忽略(chokidar 会再次调用并传入 stats)\n if (!stats) return false;\n // 目录不忽略(chokidar 需要递归进入子目录)\n if (stats.isDirectory()) return false;\n // 只监听 .ts 文件\n return !filePath.endsWith('.ts');\n },\n });\n\n watcher.on('add', (file) => {\n pendingFiles.add(path.resolve(rootDir, file));\n scheduleRebuild();\n });\n watcher.on('change', (file) => {\n pendingFiles.add(path.resolve(rootDir, file));\n scheduleRebuild();\n });\n watcher.on('unlink', () => {\n // 文件删除:不增量编译(无文件可编译),但触发全量扫描(路由结构变化)\n scheduleRebuild();\n });\n watcher.on('error', (err) => {\n console.error('- Watcher error:', err instanceof Error ? err.message : String(err));\n });\n watcher.on('ready', () => {\n const watched = watcher.getWatched();\n const dirCount = Object.keys(watched).length;\n const fileCount = Object.values(watched).reduce((sum, files) => sum + files.length, 0);\n console.log(`- Watcher ready: ${dirCount} dir(s), ${fileCount} file(s) watched`);\n });\n\n console.log('- Watch mode enabled');\n}\n\n/**\n * 更新服务器的路由引用(HTTP + WS)\n * 通过修改全局状态实现热更新,server 内部读取该全局变量\n */\nfunction updateServerRoutes(routes: RouteManifest, wsRoutes: WsRouteManifest): void {\n (globalThis as Record<string, unknown>).__FAAPI_ROUTES__ = routes;\n (globalThis as Record<string, unknown>).__FAAPI_WS_ROUTES__ = wsRoutes;\n}\n","import path from 'node:path';\nimport fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport type { FaapiConfig } from './configTypes';\n\n/**\n * 配置文件查找顺序\n *\n * 1. faapi.config.ts / faapi.config.js(基础配置)\n * 2. faapi.config.{env}.ts / faapi.config.{env}.js(环境覆盖)\n *\n * 环境覆盖深度合并到基础配置上(见 deepMerge)\n */\nconst BASE_CONFIG_FILES = ['faapi.config.ts', 'faapi.config.js'];\n\n/**\n * 获取当前运行环境(用于加载 faapi.config.{env}.ts)\n *\n * 优先级:FAAPI_ENV → NODE_ENV → 'development'\n *\n * FAAPI_ENV 优先:让 faapi 的环境切换不污染全局 NODE_ENV(其他库也读 NODE_ENV)。\n * FAAPI_ENV 未设时回退 NODE_ENV,符合 Node 生态默认直觉。\n */\nfunction getEnv(): string {\n return process.env.FAAPI_ENV || process.env.NODE_ENV || 'development';\n}\n\n/**\n * 深度合并两个配置对象(后者覆盖前者)\n *\n * 特殊对象(Date / RegExp / Map / Set)直接替换,不递归合并。\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n base: T,\n override: Record<string, unknown>,\n): T {\n const result = { ...base };\n for (const key of Object.keys(override)) {\n const baseVal = (base as Record<string, unknown>)[key];\n const overVal = override[key];\n\n // 特殊对象类型直接替换(不递归合并)\n if (\n baseVal instanceof Date ||\n overVal instanceof Date ||\n baseVal instanceof RegExp ||\n overVal instanceof RegExp ||\n baseVal instanceof Map ||\n overVal instanceof Map ||\n baseVal instanceof Set ||\n overVal instanceof Set\n ) {\n (result as Record<string, unknown>)[key] = overVal;\n continue;\n }\n\n // 普通对象递归合并\n if (\n baseVal !== null &&\n overVal !== null &&\n typeof baseVal === 'object' &&\n typeof overVal === 'object' &&\n !Array.isArray(baseVal) &&\n !Array.isArray(overVal) &&\n !(baseVal instanceof Function) &&\n !(overVal instanceof Function)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n baseVal as Record<string, unknown>,\n overVal as Record<string, unknown>,\n );\n } else {\n (result as Record<string, unknown>)[key] = overVal;\n }\n }\n return result;\n}\n\n/**\n * 加载单个配置文件\n */\nasync function loadConfigFile(filePath: string): Promise<Partial<FaapiConfig> | null> {\n if (!fs.existsSync(filePath)) {\n return null;\n }\n\n try {\n const url = pathToFileURL(filePath).href;\n const module = (await import(url)) as { default?: Partial<FaapiConfig> };\n return module.default ?? {};\n } catch (err) {\n throw new Error(\n `Failed to load config file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n}\n\n/**\n * 加载 faapi 配置文件\n *\n * 查找顺序:\n * 1. 指定的 configPath\n * 2. faapi.config.ts / faapi.config.js(基础配置)\n * 3. faapi.config.{env}.ts / faapi.config.{env}.js(环境覆盖,深度合并)\n *\n * 环境由 FAAPI_ENV 或 NODE_ENV 决定,默认 'development'\n *\n * @param rootDir 项目根目录\n * @param configPath 指定的配置文件路径(可选)\n * @returns 合并后的配置,如果无配置文件则返回 null\n */\nexport async function loadConfig(\n rootDir: string,\n configPath?: string,\n): Promise<Partial<FaapiConfig> | null> {\n // 指定了配置文件路径时,直接加载该文件(文件不存在则抛错)\n if (configPath) {\n const resolvedPath = path.resolve(rootDir, configPath);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`Config file not found: ${configPath}`);\n }\n return loadConfigFile(resolvedPath);\n }\n\n // 查找基础配置文件\n let baseConfig: Partial<FaapiConfig> | null = null;\n for (const fileName of BASE_CONFIG_FILES) {\n const filePath = path.join(rootDir, fileName);\n baseConfig = await loadConfigFile(filePath);\n if (baseConfig) break;\n }\n\n if (!baseConfig) {\n return null;\n }\n\n // 查找环境配置文件并合并\n const env = getEnv();\n const envFiles = [`faapi.config.${env}.ts`, `faapi.config.${env}.js`];\n\n for (const envFile of envFiles) {\n const envConfig = await loadConfigFile(path.join(rootDir, envFile));\n if (envConfig) {\n baseConfig = deepMerge(baseConfig, envConfig);\n break;\n }\n }\n\n return baseConfig;\n}\n","import type { FaapiPlugin, PluginDeclaration } from '../config/pluginTypes';\nimport type { RequestHandler, UpgradeHandler } from '../config/pluginTypes';\n\n/** loadPlugins 的输入上下文(不含 wrap 能力,由 loadPlugins 内部注入) */\ntype LoadPluginsContext = Omit<\n import('../config/pluginTypes').PluginContext,\n 'wrapHandler' | 'wrapUpgradeHandler'\n>;\n\n/** loadPlugins 返回的包装器收集结果 */\nexport interface PluginLoadResult {\n /** 插件注册的 HTTP handler 包装器(按注册顺序) */\n handlerWrappers: Array<(original: RequestHandler) => RequestHandler>;\n /** 插件注册的 WS upgrade handler 包装器(按注册顺序) */\n upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler>;\n}\n\n/**\n * 加载并执行插件列表\n *\n * 遍历 config.plugins,动态 import 插件包,调用 setup(ctx)。\n * 插件在 server 创建后、listen 之前按声明顺序执行。\n *\n * 插件可通过 ctx.wrapHandler / ctx.wrapUpgradeHandler 注册包装函数,\n * 本函数收集后返回,由调用方在 listen 之前应用。\n *\n * @param declarations 插件声明列表\n * @param ctx 插件上下文(不含 wrap 能力,由本函数注入)\n * @returns 包装器收集结果\n */\nexport async function loadPlugins(\n declarations: PluginDeclaration[] | undefined,\n ctx: LoadPluginsContext,\n): Promise<PluginLoadResult> {\n const handlerWrappers: Array<(original: RequestHandler) => RequestHandler> = [];\n const upgradeWrappers: Array<(original: UpgradeHandler | undefined) => UpgradeHandler> = [];\n\n if (!declarations || declarations.length === 0) {\n return { handlerWrappers, upgradeWrappers };\n }\n\n // 注入 wrap 能力到 ctx\n const fullCtx = {\n ...ctx,\n wrapHandler: (fn: (original: RequestHandler) => RequestHandler) => {\n handlerWrappers.push(fn);\n },\n wrapUpgradeHandler: (fn: (original: UpgradeHandler | undefined) => UpgradeHandler) => {\n upgradeWrappers.push(fn);\n },\n };\n\n const loaded = new Set<string>();\n\n for (const decl of declarations) {\n const { specifier, options, enable } = resolveDeclaration(decl);\n\n // enable 检查\n if (enable === false) continue;\n\n // 去重\n if (loaded.has(specifier)) {\n console.warn(`! Plugin already loaded: ${specifier}, skipping`);\n continue;\n }\n loaded.add(specifier);\n\n try {\n const mod = await import(specifier);\n const plugin: FaapiPlugin = mod.default ?? mod;\n\n if (typeof plugin.setup !== 'function') {\n console.warn(`! Plugin ${specifier} has no setup function, skipping`);\n continue;\n }\n\n await plugin.setup({ ...fullCtx, options });\n console.log(`- Plugin loaded: ${plugin.name ?? specifier}`);\n } catch (err) {\n console.warn(\n `! Failed to load plugin ${specifier}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return { handlerWrappers, upgradeWrappers };\n}\n\n/**\n * 解析插件声明为统一格式\n */\nfunction resolveDeclaration(decl: PluginDeclaration): {\n specifier: string;\n options?: unknown;\n enable?: boolean;\n} {\n if (typeof decl === 'string') {\n return { specifier: decl };\n }\n\n if (Array.isArray(decl)) {\n const [specifier, options] = decl;\n return { specifier, options };\n }\n\n if ('package' in decl) {\n return { specifier: decl.package, options: decl.options, enable: decl.enable };\n }\n\n if ('path' in decl) {\n return { specifier: decl.path, options: decl.options, enable: decl.enable };\n }\n\n // 不应该到这里\n throw new Error(`Invalid plugin declaration: ${JSON.stringify(decl)}`);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { parseArgs } from './parseArgs';\nimport { scanRoutes } from '../router/scanRoutes';\nimport { sortRoutes } from '../router/sortRoutes';\nimport { detectRouteConflicts } from '../router/detectRouteConflicts';\nimport { startServer, applyPluginWrappers } from '../server/startServer';\nimport { generateTypes } from './generateTypes';\nimport { startWatcher } from './watcher';\nimport { loadConfig } from '../config/loadConfig';\nimport { generateSchemaFile, loadSchemaToRegistry } from './generateSchema';\nimport { hydrateRoutes, type SerializedRouteManifest } from './generateRoutes';\nimport { compileRoutes } from './compileRoutes';\nimport { loadPlugins } from './loadPlugins';\nimport { importWithCacheBust } from '../utils/importWithCacheBust';\nimport type { RouteManifest, WsRouteManifest } from '../router/routeTypes';\n\n/** dev 模式产物目录 */\nconst DEV_OUT_DIR = '.faapi/dev';\n/** build/start 模式产物目录 */\nconst PROD_OUT_DIR = 'dist';\n\n/**\n * CLI 启动命令的完整流程\n *\n * 参考 Next.js 实现:dev 和 start 共用\"加载中间产物\"路径,差异仅在产物来源。\n *\n * dev 模式(`faapi` 或 `faapi dev`):\n * 1. 解析参数\n * 2. 加载配置\n * 3. 编译 src 下所有 .ts → .faapi/dev 下对应 .js(esbuild,含别名重写)\n * 4. 扫描路由(import 产物 .js 拿方法名,filePath 保持源码 .ts)\n * 5. 排序路由 + 检测冲突\n * 6. 预生成 schema 到 `.faapi/dev/faapi-schema.js`,再加载(与 start 统一)\n * 7. 生成类型文件(可选)\n * 8. 启动 server\n * 9. 执行 onReady 生命周期钩子\n * 10. 启动 watch 模式(增量编译 + 重新生成 schema + 热替换路由)\n *\n * start 模式(`faapi start`,生产模式):\n * 1. 解析参数\n * 2. 加载配置\n * 3. 从 `dist/faapi-routes.js` 读取清单,水合(加载中间件)\n * 4. 排序路由 + 检测冲突\n * 5. 从 `dist/faapi-schema.js` 加载 schema\n * 6. 启动 server\n * 7. 执行 onReady 生命周期钩子\n *\n * dev 和 start 共用 createServer / handleRequest / validateInput,\n * 差异仅在产物目录(.faapi/dev vs dist)、是否编译、是否启动 watch。\n *\n * @param argv 原始 CLI 参数(含命令词 dev/start,由 parseArgs 解析)\n */\nexport async function startCommand(argv: string[]): Promise<void> {\n const args = parseArgs(argv);\n const rootDir = process.cwd();\n const isProd = args.mode === 'start';\n const prodDir = isProd ? PROD_OUT_DIR : DEV_OUT_DIR;\n\n // start 模式要求 dist/faapi-routes.js 和 dist/faapi-schema.js 存在(由 faapi build 生成)\n if (isProd) {\n const routesPath = path.resolve(rootDir, PROD_OUT_DIR, 'faapi-routes.js');\n const schemaPath = path.resolve(rootDir, PROD_OUT_DIR, 'faapi-schema.js');\n if (!fs.existsSync(routesPath) || !fs.existsSync(schemaPath)) {\n console.error(\n '[faapi] dist/faapi-routes.js 或 dist/faapi-schema.js 不存在,请先执行 `faapi build` 构建生产产物。',\n );\n process.exit(1);\n }\n }\n\n if (isProd) {\n // 同步 NODE_ENV 给生态(如 Next.js 运行时 20+ 处直接读 process.env.NODE_ENV 做分支)\n // 仅在未显式设置时回退,避免覆盖用户意图\n if (!process.env.NODE_ENV) process.env.NODE_ENV = 'production';\n console.log('- Production mode');\n } else {\n // 标记 dev 模式\n process.env.__FAAPI_DEV__ = '1';\n if (!process.env.NODE_ENV) process.env.NODE_ENV = 'development';\n console.log('- Development mode');\n }\n\n // 加载配置文件\n const config = await loadConfig(rootDir, args.config);\n if (config) {\n console.log('- Config loaded');\n }\n\n // 路由获取:start 读清单+水合,dev 编译+扫描文件系统\n let routes: RouteManifest;\n let wsRoutes: WsRouteManifest;\n if (isProd) {\n // start 模式:从 dist/faapi-routes.js 读取序列化清单,水合(加载中间件)\n const routesPath = path.resolve(rootDir, PROD_OUT_DIR, 'faapi-routes.js');\n const serialized = (await importWithCacheBust(routesPath)) as unknown as SerializedRouteManifest;\n const hydrated = await hydrateRoutes(serialized);\n routes = hydrated.routes;\n wsRoutes = hydrated.wsRoutes;\n console.log(`- Routes loaded: ${routes.length} routes, ${wsRoutes.length} WS routes`);\n } else {\n // dev 模式:先编译 src/**/*.ts → .faapi/dev/**/*.js,再扫描路由(import 产物 .js)\n console.log('- Compiling TypeScript...');\n await compileRoutes({ rootDir, appDir: args.appDir, outDir: DEV_OUT_DIR });\n const scanned = await scanRoutes(rootDir, args.patterns, args.appDir, DEV_OUT_DIR);\n routes = scanned.routes;\n wsRoutes = scanned.wsRoutes;\n console.log(`- Routes scanned: ${routes.length} routes, ${wsRoutes.length} WS routes`);\n }\n const sorted = sortRoutes(routes);\n\n // 检测路由冲突(相同 method + urlPath 的多个文件)\n const conflicts = detectRouteConflicts(sorted);\n if (conflicts.length > 0) {\n for (const conflict of conflicts) {\n console.warn(`! 路由冲突: ${conflict.method} ${conflict.urlPath}`);\n for (const file of conflict.files) {\n console.warn(` - ${file}`);\n }\n }\n }\n\n // 加载 schema:dev 预生成到 .faapi/dev/,start 直接读 dist/\n // dev 模式:route.filePath 是源码路径,schema key 也是源码路径,不需要 remap\n // start 模式:route.filePath 是产物路径,schema key 需 remap 为产物路径\n const schemaPath = path.resolve(rootDir, prodDir, 'faapi-schema.js');\n if (!isProd) {\n // dev 模式:预生成 schema 文件(AST 从源码 .ts,与 build 一致)\n await generateSchemaFile(sorted, rootDir, schemaPath);\n }\n await loadSchemaToRegistry(schemaPath, rootDir, prodDir, isProd);\n console.log(`- Schema loaded: ${schemaPath}`);\n\n // 生成类型文件(仅 dev 启动时)\n if (!isProd && args.types) {\n const typesPath = path.resolve(rootDir, args.types);\n await generateTypes(sorted, rootDir, typesPath);\n console.log(`- Types generated: ${typesPath}`);\n }\n\n // 自定义业务配置(排除 FaapiConfig 内置 key)\n const pluginConfig = config\n ? Object.fromEntries(Object.entries(config).filter(([k]) => !isFaapiConfigKey(k)))\n : {};\n\n const server = await startServer({\n port: args.port,\n routes: sorted,\n rootDir,\n cors: config?.cors ?? args.cors,\n staticDir: config?.staticDir ?? args.staticDir,\n responseFormat: config?.responseFormat,\n errorFormat: config?.errorFormat,\n onError: config?.lifecycle?.onError,\n config: config ?? undefined,\n wsRoutes,\n middlewares: config?.middlewares,\n injectors: config?.injectors,\n // beforeListen:加载插件并应用 handler 包装(在 server.listen 之前)\n beforeListen: async (server) => {\n const { handlerWrappers, upgradeWrappers } = await loadPlugins(config?.plugins, {\n rootDir,\n routes: sorted,\n server,\n config: pluginConfig,\n });\n applyPluginWrappers(server, handlerWrappers, upgradeWrappers);\n },\n });\n\n // 执行 onReady 生命周期钩子\n if (config?.lifecycle?.onReady) {\n await config.lifecycle.onReady({\n rootDir,\n routes: sorted,\n server,\n });\n console.log('- onReady hook executed');\n }\n\n // 注册 onClose 生命周期钩子\n if (config?.lifecycle?.onClose) {\n const onClose = config.lifecycle.onClose;\n const gracefulShutdown = async (signal: string) => {\n console.log(`\\n- Received ${signal}, running onClose hook...`);\n await onClose({ rootDir, routes: sorted, server });\n process.exit(0);\n };\n process.on('SIGTERM', () => void gracefulShutdown('SIGTERM'));\n process.on('SIGINT', () => void gracefulShutdown('SIGINT'));\n }\n\n // 启动 watch 模式(仅 dev)\n if (!isProd) {\n startWatcher({\n rootDir,\n patterns: args.patterns,\n appDir: args.appDir,\n server,\n port: args.port,\n cors: args.cors,\n staticDir: args.staticDir,\n types: args.types,\n });\n }\n}\n\n/** FaapiConfig 的内置 key 集合(排除自定义业务配置) */\nconst FAAPI_CONFIG_KEYS = new Set([\n 'port',\n 'staticDir',\n 'cors',\n 'responseFormat',\n 'errorFormat',\n 'lifecycle',\n 'middlewares',\n 'injectors',\n 'extendContext',\n 'plugins',\n]);\n\nfunction isFaapiConfigKey(key: string): boolean {\n return FAAPI_CONFIG_KEYS.has(key);\n}\n","#!/usr/bin/env node\n\n/**\n * 检测 tsx 是否已通过 `node --import tsx` 预加载\n * 已预加载时跳过 register:register('tsx/esm') 与 --import tsx 同存会触发 Node 24 ERR_REQUIRE_CYCLE_MODULE\n */\nfunction isTsxPreloaded(): boolean {\n return (\n process.execArgv.some((arg) => arg.includes('tsx')) ||\n (process.env.NODE_OPTIONS ?? '').includes('tsx')\n );\n}\n\n/**\n * 注册 tsx(用于加载 faapi.config.ts 等用户 .ts 配置文件)\n *\n * 新架构下路由文件由 esbuild 编译为 .js 产物,不再需要 tsx 即时转译。\n * 但 faapi.config.ts 仍由 loadConfig 直接 import,需要 tsx 处理 .ts。\n *\n * tsx 只影响 .ts 文件的 import,.js 文件不受影响(dev/start 加载的路由产物是 .js)。\n *\n * @returns true 表示 tsx 已就绪(已注册或预加载),false 表示不可用\n */\nasync function ensureTsx(): Promise<boolean> {\n if (isTsxPreloaded()) return true;\n try {\n const { register } = await import('tsx/esm/api');\n register();\n return true;\n } catch {\n // tsx 未安装:faapi.config.ts 无法加载,但 faapi.config.js 仍可用\n console.warn(\n '[faapi] tsx 未安装,无法加载 faapi.config.ts。请安装 tsx 或使用 faapi.config.js。',\n );\n return false;\n }\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n\n // 顶层命令分发:build 独立分支,不进 startCommand\n // dev/start 都走 startCommand,由 mode 区分\n const firstArg = argv.find((a) => !a.startsWith('-'));\n const isBuildMode = firstArg === 'build';\n\n // build 模式不需要 tsx(不加载 faapi.config.ts,路由由 esbuild 编译)\n // dev/start 模式需要 tsx 加载 faapi.config.ts(路由走 esbuild 产物,不需要 tsx)\n if (!isBuildMode) {\n await ensureTsx();\n }\n\n // 命令分发\n if (firstArg === 'build') {\n const { parseBuildArgs, buildCommand } = await import('./buildCommand.js');\n const options = parseBuildArgs(argv.filter((a) => a !== 'build'));\n await buildCommand(options);\n return;\n }\n\n const { startCommand } = await import('./startCommand.js');\n await startCommand(argv);\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","ts","ts","fs","path","ts","path","ts","ts","path","fs","path","fs","path","ts","path","fs","path","fs","fg","path","cors","path","params","url","path","text","headers","body","resolve","path","fs","path","Readable","relative","stat","body","path","resolve","Readable","path","toResponse","cors","resolve","Readable","path","basename","stat","lstat","path","main","rawEmitter","listener","basename","dirname","newStats","closer","resolve","realpath","stats","stat","readdir","EventEmitter","sysPath","relative","normalizePath","path","DOUBLE_SLASH_RE","testString","init_esm","stats","now","path","init_esm","path","fs","pathToFileURL","fs","path","DEV_OUT_DIR","schemaPath","server","parseBuildArgs","buildCommand","startCommand"]}
|