@lark-apaas/devtool-kits 1.2.17-alpha.38 → 1.2.17-alpha.39

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.
@@ -178,7 +178,12 @@ try {
178
178
  import_fs.default.writeFileSync(outPath, JSON.stringify(routes, null, 2));
179
179
  console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);
180
180
  } catch (error) {
181
- console.error("[api-routes] Failed to generate api-routes.json:", error);
182
- process.exit(1);
181
+ console.warn("[api-routes] Failed to generate api-routes.json, writing empty fallback:", error);
182
+ if (!import_fs.default.existsSync(outDir)) {
183
+ import_fs.default.mkdirSync(outDir, {
184
+ recursive: true
185
+ });
186
+ }
187
+ import_fs.default.writeFileSync(import_path.default.resolve(outDir, filename), JSON.stringify([], null, 2));
183
188
  }
184
189
  //# sourceMappingURL=generate-api-routes.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/generate-api-routes.ts","../../src/middlewares/openapi/services.ts","../../src/middlewares/openapi/utils.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parseApiRoutes } from '../middlewares/openapi/services';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst serverDir = path.resolve(process.cwd(), getArg('--server-dir', './server'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'api-routes.json');\n\ntry {\n const routes = parseApiRoutes(serverDir);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.error('[api-routes] Failed to generate api-routes.json:', error);\n process.exit(1);\n}\n","import { promises as fs } from 'node:fs';\nimport * as fsSync from 'node:fs';\nimport path from 'node:path';\nimport ts from 'typescript';\nimport type { SourceInfo, EnhanceOptions, EnhanceResult } from './types';\nimport { findControllerFiles, buildSourceMap, enhanceOpenApiPaths } from './utils';\n\n/**\n * Enhances OpenAPI JSON with source file location metadata\n * Can be called programmatically or run as a script\n */\nexport async function enhanceOpenApiWithSourceInfo(options: EnhanceOptions = {}): Promise<EnhanceResult> {\n const startTime = Date.now();\n\n const openapiPath = options.openapiPath || path.resolve(__dirname, '../client/src/api/gen/openapi.json');\n const serverDir = options.serverDir || path.resolve(__dirname, '../server');\n const writeFile = options.writeFile !== false;\n\n let openapi: any;\n if (options.openapiData) {\n // Use provided data (for in-memory enhancement)\n openapi = JSON.parse(JSON.stringify(options.openapiData)); // Deep clone\n } else {\n // Read from file\n const openapiContent = await fs.readFile(openapiPath, 'utf-8');\n openapi = JSON.parse(openapiContent);\n }\n\n const controllerFiles = await findControllerFiles(serverDir);\n const sourceMap = await buildSourceMap(controllerFiles, processControllerFile);\n const enhanced = enhanceOpenApiPaths(openapi, sourceMap);\n\n if (writeFile) {\n await fs.writeFile(openapiPath, JSON.stringify(openapi, null, 2) + '\\n', 'utf-8');\n }\n\n const duration = Date.now() - startTime;\n\n return {\n openapi,\n stats: {\n duration,\n controllersFound: controllerFiles.length,\n endpointsExtracted: sourceMap.size,\n endpointsEnhanced: enhanced,\n },\n };\n}\n\n/**\n * Process a single controller file\n */\nasync function processControllerFile(filePath: string): Promise<Map<string, SourceInfo>> {\n const relativePath = path.relative(process.cwd(), filePath);\n\n // Parse file\n const content = await fs.readFile(filePath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n return extractControllerMetadata(sourceFile, relativePath);\n}\n\n/**\n * Extract controller metadata from TypeScript source file\n */\nfunction extractControllerMetadata(sourceFile: ts.SourceFile, filePath: string): Map<string, SourceInfo> {\n const metadata = new Map<string, SourceInfo>();\n let controllerPath = '';\n let className = '';\n\n // Helper function to get decorators from both old and new TypeScript APIs\n function getDecorators(node: ts.Node): readonly ts.Decorator[] {\n // TypeScript 5.x: decorators are in modifiers array\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n // TypeScript 4.x: decorators are in decorators array\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function visit(node: ts.Node): void {\n // Extract @Controller decorator and its path\n if (ts.isClassDeclaration(node)) {\n const decorators = getDecorators(node);\n\n // Extract class name\n if (node.name) {\n className = node.name.getText(sourceFile);\n }\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const expression = decorator.expression;\n const decoratorName = expression.expression.getText(sourceFile);\n\n if (decoratorName === 'Controller') {\n if (expression.arguments.length > 0) {\n const arg = expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n controllerPath = arg.text;\n }\n }\n }\n }\n }\n }\n\n // Extract methods with HTTP decorators\n if (ts.isMethodDeclaration(node) && node.name) {\n const methodName = node.name.getText(sourceFile);\n let httpMethod = '';\n let routePath = '';\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));\n\n const decorators = getDecorators(node);\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const decoratorName = decorator.expression.expression.getText(sourceFile);\n if (['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'].includes(decoratorName)) {\n httpMethod = decoratorName.toLowerCase();\n if (decorator.expression.arguments.length > 0) {\n const arg = decorator.expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n routePath = arg.text;\n }\n }\n }\n }\n }\n\n if (httpMethod && methodName && className) {\n const operationId = `${className}_${methodName}`;\n metadata.set(operationId, {\n file: filePath,\n line: line + 1,\n method: httpMethod,\n controllerPath,\n routePath,\n });\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return metadata;\n}\n\n// --- API Route Parsing (synchronous, for build-time injection) ---\n\nconst HTTP_DECORATOR_NAMES = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'];\n\nfunction findControllerFilesSync(dir: string): string[] {\n const files: string[] = [];\n function scan(currentDir: string): void {\n let entries: fsSync.Dirent[];\n try {\n entries = fsSync.readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n scan(dir);\n return files;\n}\n\nfunction normalizeApiPath(controllerPath: string, routePath: string): string {\n const combined = routePath ? `${controllerPath}/${routePath}` : controllerPath;\n let normalized = combined.replace(/\\/+/g, '/');\n if (!normalized.startsWith('/')) normalized = `/${normalized}`;\n if (normalized.length > 1 && normalized.endsWith('/')) normalized = normalized.slice(0, -1);\n return normalized;\n}\n\nfunction parseControllerRoutes(filePath: string): Array<{ method: string; path: string }> {\n let content: string;\n try {\n content = fsSync.readFileSync(filePath, 'utf-8');\n } catch {\n return [];\n }\n\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n const routes: Array<{ method: string; path: string }> = [];\n\n function getDecoratorsCompat(node: ts.Node): readonly ts.Decorator[] {\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function getStringArg(expr: ts.CallExpression): string {\n if (expr.arguments.length > 0 && ts.isStringLiteral(expr.arguments[0])) {\n return expr.arguments[0].text;\n }\n return '';\n }\n\n function visit(node: ts.Node): void {\n if (ts.isClassDeclaration(node)) {\n let controllerPath = '';\n for (const dec of getDecoratorsCompat(node)) {\n if (ts.isCallExpression(dec.expression)) {\n const name = dec.expression.expression.getText(sourceFile);\n if (name === 'Controller') {\n controllerPath = getStringArg(dec.expression);\n break;\n }\n }\n }\n\n for (const member of node.members) {\n if (!ts.isMethodDeclaration(member)) continue;\n for (const dec of getDecoratorsCompat(member)) {\n if (!ts.isCallExpression(dec.expression)) continue;\n const decoratorName = dec.expression.expression.getText(sourceFile);\n if (!HTTP_DECORATOR_NAMES.includes(decoratorName)) continue;\n\n const routePath = getStringArg(dec.expression);\n const fullPath = normalizeApiPath(controllerPath, routePath);\n const method = decoratorName === 'All' ? '*' : decoratorName.toUpperCase();\n routes.push({ method, path: fullPath });\n }\n }\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return routes;\n}\n\n/**\n * Scan serverDir for NestJS controller files and extract all parameterized API routes.\n * Synchronous — safe to call at preset config time (before bundling).\n */\nexport function parseApiRoutes(serverDir: string): Array<{ method: string; path: string }> {\n const resolvedDir = path.resolve(serverDir);\n const controllerFiles = findControllerFilesSync(resolvedDir);\n const routes: Array<{ method: string; path: string }> = [];\n for (const filePath of controllerFiles) {\n routes.push(...parseControllerRoutes(filePath));\n }\n return routes;\n}\n","import path from 'node:path';\nimport { promises as fs } from 'node:fs';\nimport type { SourceInfo } from './types';\n\n/**\n * Find all controller files in a directory\n */\nexport async function findControllerFiles(dir: string): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n\n await scan(dir);\n return files;\n}\n\n/**\n * Build source map from controller files\n */\nexport async function buildSourceMap(\n controllerFiles: string[],\n processFile: (filePath: string) => Promise<Map<string, SourceInfo>>,\n): Promise<Map<string, SourceInfo>> {\n const sourceMap = new Map<string, SourceInfo>();\n\n // Process files in parallel with a concurrency limit\n const concurrency = 10;\n const results: Map<string, SourceInfo>[] = [];\n\n for (let i = 0; i < controllerFiles.length; i += concurrency) {\n const batch = controllerFiles.slice(i, i + concurrency);\n const batchResults = await Promise.all(batch.map((filePath) => processFile(filePath)));\n results.push(...batchResults);\n }\n\n // Merge results\n for (const metadata of results) {\n for (const [operationId, info] of metadata.entries()) {\n sourceMap.set(operationId, info);\n }\n }\n\n return sourceMap;\n}\n\n/**\n * Try to match operationId with different formats\n * Supports:\n * - Direct match: ClassName_methodName\n * - Camel case: classNameMethodName\n * - Method only: methodName\n */\nfunction findSourceInfo(operationId: string, sourceMap: Map<string, SourceInfo>): SourceInfo | undefined {\n // Try direct match first\n const directMatch = sourceMap.get(operationId);\n if (directMatch) {\n return directMatch;\n }\n\n // Try matching with different formats\n for (const [key, value] of sourceMap.entries()) {\n // key format: ClassName_methodName\n const [className, methodName] = key.split('_');\n if (!className || !methodName) continue;\n\n // Try camelCase format: classNameMethodName\n const camelCaseId = className.charAt(0).toLowerCase() + className.slice(1) + methodName.charAt(0).toUpperCase() + methodName.slice(1);\n if (operationId === camelCaseId) {\n return value;\n }\n\n // Try method name only\n if (operationId === methodName) {\n return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Enhance OpenAPI paths with source information\n */\nexport function enhanceOpenApiPaths(openapi: any, sourceMap: Map<string, SourceInfo>): number {\n let enhancedCount = 0;\n\n if (!openapi.paths) {\n return enhancedCount;\n }\n\n for (const pathItem of Object.values(openapi.paths)) {\n if (!pathItem || typeof pathItem !== 'object') continue;\n\n for (const operation of Object.values(pathItem)) {\n if (operation && typeof operation === 'object' && 'operationId' in operation) {\n const sourceInfo = findSourceInfo(operation.operationId as string, sourceMap);\n if (sourceInfo) {\n operation['x-source'] = {\n file: sourceInfo.file,\n line: sourceInfo.line,\n };\n enhancedCount++;\n }\n }\n }\n }\n\n return enhancedCount;\n}\n\n/**\n * Transform OpenAPI paths by removing basePath prefix\n */\nexport function transformOpenapiPaths(openapi: any, basePath: string): any {\n if (basePath === '/' || !openapi.paths) {\n return openapi;\n }\n\n const newPaths: any = {};\n Object.keys(openapi.paths).forEach((key) => {\n const staticApiKey = key.startsWith(basePath) ? key.slice(basePath.length) : key;\n newPaths[staticApiKey] = openapi.paths[key];\n });\n\n return {\n ...openapi,\n paths: newPaths,\n basePath,\n };\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","HTTP_DECORATOR_NAMES","findControllerFilesSync","dir","files","scan","currentDir","entries","readdirSync","withFileTypes","entry","fullPath","path","join","name","isDirectory","isFile","endsWith","push","normalizeApiPath","controllerPath","routePath","combined","normalized","replace","startsWith","length","slice","parseControllerRoutes","filePath","content","readFileSync","sourceFile","ts","createSourceFile","ScriptTarget","Latest","routes","getDecoratorsCompat","node","Array","isArray","modifiers","filter","mod","kind","SyntaxKind","Decorator","decorators","getStringArg","expr","arguments","isStringLiteral","text","visit","isClassDeclaration","dec","isCallExpression","expression","getText","member","members","isMethodDeclaration","decoratorName","includes","method","toUpperCase","forEachChild","parseApiRoutes","serverDir","resolvedDir","resolve","controllerFiles","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","serverDir","path","resolve","cwd","outDir","filename","routes","parseApiRoutes","fs","existsSync","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","length","error","exit"]}
1
+ {"version":3,"sources":["../../src/bin/generate-api-routes.ts","../../src/middlewares/openapi/services.ts","../../src/middlewares/openapi/utils.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parseApiRoutes } from '../middlewares/openapi/services';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst serverDir = path.resolve(process.cwd(), getArg('--server-dir', './server'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'api-routes.json');\n\ntry {\n const routes = parseApiRoutes(serverDir);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.warn('[api-routes] Failed to generate api-routes.json, writing empty fallback:', error);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));\n}\n","import { promises as fs } from 'node:fs';\nimport * as fsSync from 'node:fs';\nimport path from 'node:path';\nimport ts from 'typescript';\nimport type { SourceInfo, EnhanceOptions, EnhanceResult } from './types';\nimport { findControllerFiles, buildSourceMap, enhanceOpenApiPaths } from './utils';\n\n/**\n * Enhances OpenAPI JSON with source file location metadata\n * Can be called programmatically or run as a script\n */\nexport async function enhanceOpenApiWithSourceInfo(options: EnhanceOptions = {}): Promise<EnhanceResult> {\n const startTime = Date.now();\n\n const openapiPath = options.openapiPath || path.resolve(__dirname, '../client/src/api/gen/openapi.json');\n const serverDir = options.serverDir || path.resolve(__dirname, '../server');\n const writeFile = options.writeFile !== false;\n\n let openapi: any;\n if (options.openapiData) {\n // Use provided data (for in-memory enhancement)\n openapi = JSON.parse(JSON.stringify(options.openapiData)); // Deep clone\n } else {\n // Read from file\n const openapiContent = await fs.readFile(openapiPath, 'utf-8');\n openapi = JSON.parse(openapiContent);\n }\n\n const controllerFiles = await findControllerFiles(serverDir);\n const sourceMap = await buildSourceMap(controllerFiles, processControllerFile);\n const enhanced = enhanceOpenApiPaths(openapi, sourceMap);\n\n if (writeFile) {\n await fs.writeFile(openapiPath, JSON.stringify(openapi, null, 2) + '\\n', 'utf-8');\n }\n\n const duration = Date.now() - startTime;\n\n return {\n openapi,\n stats: {\n duration,\n controllersFound: controllerFiles.length,\n endpointsExtracted: sourceMap.size,\n endpointsEnhanced: enhanced,\n },\n };\n}\n\n/**\n * Process a single controller file\n */\nasync function processControllerFile(filePath: string): Promise<Map<string, SourceInfo>> {\n const relativePath = path.relative(process.cwd(), filePath);\n\n // Parse file\n const content = await fs.readFile(filePath, 'utf-8');\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n\n return extractControllerMetadata(sourceFile, relativePath);\n}\n\n/**\n * Extract controller metadata from TypeScript source file\n */\nfunction extractControllerMetadata(sourceFile: ts.SourceFile, filePath: string): Map<string, SourceInfo> {\n const metadata = new Map<string, SourceInfo>();\n let controllerPath = '';\n let className = '';\n\n // Helper function to get decorators from both old and new TypeScript APIs\n function getDecorators(node: ts.Node): readonly ts.Decorator[] {\n // TypeScript 5.x: decorators are in modifiers array\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n // TypeScript 4.x: decorators are in decorators array\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function visit(node: ts.Node): void {\n // Extract @Controller decorator and its path\n if (ts.isClassDeclaration(node)) {\n const decorators = getDecorators(node);\n\n // Extract class name\n if (node.name) {\n className = node.name.getText(sourceFile);\n }\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const expression = decorator.expression;\n const decoratorName = expression.expression.getText(sourceFile);\n\n if (decoratorName === 'Controller') {\n if (expression.arguments.length > 0) {\n const arg = expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n controllerPath = arg.text;\n }\n }\n }\n }\n }\n }\n\n // Extract methods with HTTP decorators\n if (ts.isMethodDeclaration(node) && node.name) {\n const methodName = node.name.getText(sourceFile);\n let httpMethod = '';\n let routePath = '';\n const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));\n\n const decorators = getDecorators(node);\n\n for (const decorator of decorators) {\n if (ts.isCallExpression(decorator.expression)) {\n const decoratorName = decorator.expression.expression.getText(sourceFile);\n if (['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'].includes(decoratorName)) {\n httpMethod = decoratorName.toLowerCase();\n if (decorator.expression.arguments.length > 0) {\n const arg = decorator.expression.arguments[0];\n if (ts.isStringLiteral(arg)) {\n routePath = arg.text;\n }\n }\n }\n }\n }\n\n if (httpMethod && methodName && className) {\n const operationId = `${className}_${methodName}`;\n metadata.set(operationId, {\n file: filePath,\n line: line + 1,\n method: httpMethod,\n controllerPath,\n routePath,\n });\n }\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return metadata;\n}\n\n// --- API Route Parsing (synchronous, for build-time injection) ---\n\nconst HTTP_DECORATOR_NAMES = ['Get', 'Post', 'Put', 'Delete', 'Patch', 'Options', 'Head', 'All'];\n\nfunction findControllerFilesSync(dir: string): string[] {\n const files: string[] = [];\n function scan(currentDir: string): void {\n let entries: fsSync.Dirent[];\n try {\n entries = fsSync.readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n if (entry.isDirectory()) {\n scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n scan(dir);\n return files;\n}\n\nfunction normalizeApiPath(controllerPath: string, routePath: string): string {\n const combined = routePath ? `${controllerPath}/${routePath}` : controllerPath;\n let normalized = combined.replace(/\\/+/g, '/');\n if (!normalized.startsWith('/')) normalized = `/${normalized}`;\n if (normalized.length > 1 && normalized.endsWith('/')) normalized = normalized.slice(0, -1);\n return normalized;\n}\n\nfunction parseControllerRoutes(filePath: string): Array<{ method: string; path: string }> {\n let content: string;\n try {\n content = fsSync.readFileSync(filePath, 'utf-8');\n } catch {\n return [];\n }\n\n const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);\n const routes: Array<{ method: string; path: string }> = [];\n\n function getDecoratorsCompat(node: ts.Node): readonly ts.Decorator[] {\n if ('modifiers' in node && Array.isArray(node.modifiers)) {\n return (node.modifiers as ts.ModifierLike[]).filter(\n (mod): mod is ts.Decorator => mod.kind === ts.SyntaxKind.Decorator,\n );\n }\n if ('decorators' in node && Array.isArray(node.decorators)) {\n return node.decorators as readonly ts.Decorator[];\n }\n return [];\n }\n\n function getStringArg(expr: ts.CallExpression): string {\n if (expr.arguments.length > 0 && ts.isStringLiteral(expr.arguments[0])) {\n return expr.arguments[0].text;\n }\n return '';\n }\n\n function visit(node: ts.Node): void {\n if (ts.isClassDeclaration(node)) {\n let controllerPath = '';\n for (const dec of getDecoratorsCompat(node)) {\n if (ts.isCallExpression(dec.expression)) {\n const name = dec.expression.expression.getText(sourceFile);\n if (name === 'Controller') {\n controllerPath = getStringArg(dec.expression);\n break;\n }\n }\n }\n\n for (const member of node.members) {\n if (!ts.isMethodDeclaration(member)) continue;\n for (const dec of getDecoratorsCompat(member)) {\n if (!ts.isCallExpression(dec.expression)) continue;\n const decoratorName = dec.expression.expression.getText(sourceFile);\n if (!HTTP_DECORATOR_NAMES.includes(decoratorName)) continue;\n\n const routePath = getStringArg(dec.expression);\n const fullPath = normalizeApiPath(controllerPath, routePath);\n const method = decoratorName === 'All' ? '*' : decoratorName.toUpperCase();\n routes.push({ method, path: fullPath });\n }\n }\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return routes;\n}\n\n/**\n * Scan serverDir for NestJS controller files and extract all parameterized API routes.\n * Synchronous — safe to call at preset config time (before bundling).\n */\nexport function parseApiRoutes(serverDir: string): Array<{ method: string; path: string }> {\n const resolvedDir = path.resolve(serverDir);\n const controllerFiles = findControllerFilesSync(resolvedDir);\n const routes: Array<{ method: string; path: string }> = [];\n for (const filePath of controllerFiles) {\n routes.push(...parseControllerRoutes(filePath));\n }\n return routes;\n}\n","import path from 'node:path';\nimport { promises as fs } from 'node:fs';\nimport type { SourceInfo } from './types';\n\n/**\n * Find all controller files in a directory\n */\nexport async function findControllerFiles(dir: string): Promise<string[]> {\n const files: string[] = [];\n\n async function scan(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n await scan(fullPath);\n } else if (entry.isFile() && entry.name.endsWith('.controller.ts')) {\n files.push(fullPath);\n }\n }\n }\n\n await scan(dir);\n return files;\n}\n\n/**\n * Build source map from controller files\n */\nexport async function buildSourceMap(\n controllerFiles: string[],\n processFile: (filePath: string) => Promise<Map<string, SourceInfo>>,\n): Promise<Map<string, SourceInfo>> {\n const sourceMap = new Map<string, SourceInfo>();\n\n // Process files in parallel with a concurrency limit\n const concurrency = 10;\n const results: Map<string, SourceInfo>[] = [];\n\n for (let i = 0; i < controllerFiles.length; i += concurrency) {\n const batch = controllerFiles.slice(i, i + concurrency);\n const batchResults = await Promise.all(batch.map((filePath) => processFile(filePath)));\n results.push(...batchResults);\n }\n\n // Merge results\n for (const metadata of results) {\n for (const [operationId, info] of metadata.entries()) {\n sourceMap.set(operationId, info);\n }\n }\n\n return sourceMap;\n}\n\n/**\n * Try to match operationId with different formats\n * Supports:\n * - Direct match: ClassName_methodName\n * - Camel case: classNameMethodName\n * - Method only: methodName\n */\nfunction findSourceInfo(operationId: string, sourceMap: Map<string, SourceInfo>): SourceInfo | undefined {\n // Try direct match first\n const directMatch = sourceMap.get(operationId);\n if (directMatch) {\n return directMatch;\n }\n\n // Try matching with different formats\n for (const [key, value] of sourceMap.entries()) {\n // key format: ClassName_methodName\n const [className, methodName] = key.split('_');\n if (!className || !methodName) continue;\n\n // Try camelCase format: classNameMethodName\n const camelCaseId = className.charAt(0).toLowerCase() + className.slice(1) + methodName.charAt(0).toUpperCase() + methodName.slice(1);\n if (operationId === camelCaseId) {\n return value;\n }\n\n // Try method name only\n if (operationId === methodName) {\n return value;\n }\n }\n\n return undefined;\n}\n\n/**\n * Enhance OpenAPI paths with source information\n */\nexport function enhanceOpenApiPaths(openapi: any, sourceMap: Map<string, SourceInfo>): number {\n let enhancedCount = 0;\n\n if (!openapi.paths) {\n return enhancedCount;\n }\n\n for (const pathItem of Object.values(openapi.paths)) {\n if (!pathItem || typeof pathItem !== 'object') continue;\n\n for (const operation of Object.values(pathItem)) {\n if (operation && typeof operation === 'object' && 'operationId' in operation) {\n const sourceInfo = findSourceInfo(operation.operationId as string, sourceMap);\n if (sourceInfo) {\n operation['x-source'] = {\n file: sourceInfo.file,\n line: sourceInfo.line,\n };\n enhancedCount++;\n }\n }\n }\n }\n\n return enhancedCount;\n}\n\n/**\n * Transform OpenAPI paths by removing basePath prefix\n */\nexport function transformOpenapiPaths(openapi: any, basePath: string): any {\n if (basePath === '/' || !openapi.paths) {\n return openapi;\n }\n\n const newPaths: any = {};\n Object.keys(openapi.paths).forEach((key) => {\n const staticApiKey = key.startsWith(basePath) ? key.slice(basePath.length) : key;\n newPaths[staticApiKey] = openapi.paths[key];\n });\n\n return {\n ...openapi,\n paths: newPaths,\n basePath,\n };\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","HTTP_DECORATOR_NAMES","findControllerFilesSync","dir","files","scan","currentDir","entries","readdirSync","withFileTypes","entry","fullPath","path","join","name","isDirectory","isFile","endsWith","push","normalizeApiPath","controllerPath","routePath","combined","normalized","replace","startsWith","length","slice","parseControllerRoutes","filePath","content","readFileSync","sourceFile","ts","createSourceFile","ScriptTarget","Latest","routes","getDecoratorsCompat","node","Array","isArray","modifiers","filter","mod","kind","SyntaxKind","Decorator","decorators","getStringArg","expr","arguments","isStringLiteral","text","visit","isClassDeclaration","dec","isCallExpression","expression","getText","member","members","isMethodDeclaration","decoratorName","includes","method","toUpperCase","forEachChild","parseApiRoutes","serverDir","resolvedDir","resolve","controllerFiles","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","serverDir","path","resolve","cwd","outDir","filename","routes","parseApiRoutes","fs","existsSync","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","length","error","warn"]}
@@ -32,7 +32,12 @@ try {
32
32
  fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));
33
33
  console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);
34
34
  } catch (error) {
35
- console.error("[api-routes] Failed to generate api-routes.json:", error);
36
- process.exit(1);
35
+ console.warn("[api-routes] Failed to generate api-routes.json, writing empty fallback:", error);
36
+ if (!fs.existsSync(outDir)) {
37
+ fs.mkdirSync(outDir, {
38
+ recursive: true
39
+ });
40
+ }
41
+ fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));
37
42
  }
38
43
  //# sourceMappingURL=generate-api-routes.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/generate-api-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parseApiRoutes } from '../middlewares/openapi/services';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst serverDir = path.resolve(process.cwd(), getArg('--server-dir', './server'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'api-routes.json');\n\ntry {\n const routes = parseApiRoutes(serverDir);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.error('[api-routes] Failed to generate api-routes.json:', error);\n process.exit(1);\n}\n"],"mappings":";;;;;;;;;AACA,OAAOA,QAAQ;AACf,OAAOC,UAAU;AAGjB,IAAMC,OAAOC,QAAQC,KAAKC,MAAM,CAAA;AAEhC,SAASC,OAAOC,MAAcC,cAAoB;AAChD,QAAMC,QAAQP,KAAKQ,QAAQH,IAAAA;AAC3B,MAAIE,UAAU,MAAMP,KAAKO,QAAQ,CAAA,GAAI;AACnC,WAAOP,KAAKO,QAAQ,CAAA;EACtB;AACA,SAAOD;AACT;AANSF;AAQT,IAAMK,YAAYC,KAAKC,QAAQV,QAAQW,IAAG,GAAIR,OAAO,gBAAgB,UAAA,CAAA;AACrE,IAAMS,SAASH,KAAKC,QAAQV,QAAQW,IAAG,GAAIR,OAAO,aAAa,QAAA,CAAA;AAC/D,IAAMU,WAAWV,OAAO,cAAc,iBAAA;AAEtC,IAAI;AACF,QAAMW,SAASC,eAAeP,SAAAA;AAC9B,MAAI,CAACQ,GAAGC,WAAWL,MAAAA,GAAS;AAC1BI,OAAGE,UAAUN,QAAQ;MAAEO,WAAW;IAAK,CAAA;EACzC;AACA,QAAMC,UAAUX,KAAKC,QAAQE,QAAQC,QAAAA;AACrCG,KAAGK,cAAcD,SAASE,KAAKC,UAAUT,QAAQ,MAAM,CAAA,CAAA;AACvDU,UAAQC,IAAI,0BAA0BL,OAAAA,KAAYN,OAAOY,MAAM,UAAU;AAC3E,SAASC,OAAO;AACdH,UAAQG,MAAM,oDAAoDA,KAAAA;AAClE3B,UAAQ4B,KAAK,CAAA;AACf;","names":["fs","path","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","serverDir","path","resolve","cwd","outDir","filename","routes","parseApiRoutes","fs","existsSync","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","length","error","exit"]}
1
+ {"version":3,"sources":["../../src/bin/generate-api-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parseApiRoutes } from '../middlewares/openapi/services';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst serverDir = path.resolve(process.cwd(), getArg('--server-dir', './server'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'api-routes.json');\n\ntry {\n const routes = parseApiRoutes(serverDir);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[api-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.warn('[api-routes] Failed to generate api-routes.json, writing empty fallback:', error);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));\n}\n"],"mappings":";;;;;;;;;AACA,OAAOA,QAAQ;AACf,OAAOC,UAAU;AAGjB,IAAMC,OAAOC,QAAQC,KAAKC,MAAM,CAAA;AAEhC,SAASC,OAAOC,MAAcC,cAAoB;AAChD,QAAMC,QAAQP,KAAKQ,QAAQH,IAAAA;AAC3B,MAAIE,UAAU,MAAMP,KAAKO,QAAQ,CAAA,GAAI;AACnC,WAAOP,KAAKO,QAAQ,CAAA;EACtB;AACA,SAAOD;AACT;AANSF;AAQT,IAAMK,YAAYC,KAAKC,QAAQV,QAAQW,IAAG,GAAIR,OAAO,gBAAgB,UAAA,CAAA;AACrE,IAAMS,SAASH,KAAKC,QAAQV,QAAQW,IAAG,GAAIR,OAAO,aAAa,QAAA,CAAA;AAC/D,IAAMU,WAAWV,OAAO,cAAc,iBAAA;AAEtC,IAAI;AACF,QAAMW,SAASC,eAAeP,SAAAA;AAC9B,MAAI,CAACQ,GAAGC,WAAWL,MAAAA,GAAS;AAC1BI,OAAGE,UAAUN,QAAQ;MAAEO,WAAW;IAAK,CAAA;EACzC;AACA,QAAMC,UAAUX,KAAKC,QAAQE,QAAQC,QAAAA;AACrCG,KAAGK,cAAcD,SAASE,KAAKC,UAAUT,QAAQ,MAAM,CAAA,CAAA;AACvDU,UAAQC,IAAI,0BAA0BL,OAAAA,KAAYN,OAAOY,MAAM,UAAU;AAC3E,SAASC,OAAO;AACdH,UAAQI,KAAK,4EAA4ED,KAAAA;AACzF,MAAI,CAACX,GAAGC,WAAWL,MAAAA,GAAS;AAC1BI,OAAGE,UAAUN,QAAQ;MAAEO,WAAW;IAAK,CAAA;EACzC;AACAH,KAAGK,cAAcZ,KAAKC,QAAQE,QAAQC,QAAAA,GAAWS,KAAKC,UAAU,CAAA,GAAI,MAAM,CAAA,CAAA;AAC5E;","names":["fs","path","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","serverDir","path","resolve","cwd","outDir","filename","routes","parseApiRoutes","fs","existsSync","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","length","error","warn"]}
@@ -180,7 +180,12 @@ try {
180
180
  import_fs.default.writeFileSync(outPath, JSON.stringify(routes, null, 2));
181
181
  console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);
182
182
  } catch (error) {
183
- console.error("[page-routes] Failed to generate page-routes.json:", error);
184
- process.exit(1);
183
+ console.warn("[page-routes] Failed to generate page-routes.json, writing empty fallback:", error);
184
+ if (!import_fs.default.existsSync(outDir)) {
185
+ import_fs.default.mkdirSync(outDir, {
186
+ recursive: true
187
+ });
188
+ }
189
+ import_fs.default.writeFileSync(import_path.default.resolve(outDir, filename), JSON.stringify([], null, 2));
185
190
  }
186
191
  //# sourceMappingURL=generate-page-routes.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/generate-page-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\nimport * as t from '@babel/types';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst appPath = path.resolve(process.cwd(), getArg('--app-path', './client/src/app.tsx'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'page-routes.json');\n\ninterface RouteInfo {\n path?: string;\n index?: boolean;\n [key: string]: unknown;\n}\n\nfunction isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n return (\n t.isJSXIdentifier(openingElement.name) &&\n openingElement.name.name === 'Route'\n );\n}\n\nfunction evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n const quasis = templateLiteral.quasis;\n const expressions = templateLiteral.expressions;\n\n if (quasis.length === 1 && expressions.length === 0) {\n return quasis[0].value.raw;\n }\n\n return quasis.map((q) => q.value.raw).join('');\n}\n\nfunction extractRouteInfo(openingElement: t.JSXOpeningElement): RouteInfo {\n const routeInfo: RouteInfo = {};\n\n openingElement.attributes.forEach((attr) => {\n if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n const name = attr.name.name;\n let value: unknown;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n const expression = attr.value.expression;\n if (t.isStringLiteral(expression)) {\n value = expression.value;\n } else if (t.isTemplateLiteral(expression)) {\n value = evaluateTemplateLiteral(expression);\n } else {\n value = true;\n }\n }\n } else {\n value = true;\n }\n\n routeInfo[name] = value;\n }\n });\n\n return routeInfo;\n}\n\nfunction buildFullPath(routeStack: RouteInfo[], currentRoute: RouteInfo): string | null {\n let fullPath = '';\n\n for (let i = 0; i < routeStack.length; i++) {\n if (routeStack[i].path) {\n let parentPath = routeStack[i].path!;\n if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n if (parentPath.endsWith('/') && parentPath !== '/') {\n parentPath = parentPath.slice(0, -1);\n }\n\n fullPath += parentPath === '/' ? '' : parentPath;\n }\n }\n\n if (currentRoute.index) {\n return fullPath || '/';\n } else if (currentRoute.path) {\n const routePath = currentRoute.path;\n\n if (routePath === '*') {\n return null;\n }\n\n if (!routePath.startsWith('/')) {\n fullPath = `${fullPath}/${routePath}`;\n } else {\n fullPath = routePath;\n }\n\n if (fullPath === '') fullPath = '/';\n if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n return fullPath;\n }\n\n return null;\n}\n\nfunction parsePageRoutes(appFilePath: string): Array<{ path: string }> {\n if (!fs.existsSync(appFilePath)) {\n throw new Error(`App file does not exist: ${appFilePath}`);\n }\n\n const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n const ast = parse(sourceCode, {\n sourceType: 'module',\n plugins: [\n 'jsx',\n 'typescript',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n });\n\n const routeSet = new Set<string>();\n const routeStack: RouteInfo[] = [];\n\n traverse(ast, {\n JSXElement: {\n enter(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n routeStack.push(extractRouteInfo(openingElement));\n }\n },\n exit(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n const currentRoute = routeStack.pop();\n if (currentRoute && currentRoute.path === '*') return;\n if (currentRoute && (currentRoute.path || currentRoute.index)) {\n const fullPath = buildFullPath(routeStack, currentRoute);\n if (fullPath) routeSet.add(fullPath);\n }\n }\n },\n },\n });\n\n // page-routes 不带 basePath 前缀,供日志服务消费\n const routes = Array.from(routeSet).map((routePath) => ({ path: routePath }));\n return routes.length > 0 ? routes : [{ path: '/' }];\n}\n\ntry {\n const routes = parsePageRoutes(appPath);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.error('[page-routes] Failed to generate page-routes.json:', error);\n process.exit(1);\n}\n"],"mappings":"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","names":["traverse","_traverse","default","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","appPath","path","resolve","cwd","outDir","filename","isRouteComponent","openingElement","isJSXIdentifier","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","parentPath","startsWith","endsWith","routePath","parsePageRoutes","appFilePath","fs","existsSync","Error","sourceCode","readFileSync","ast","parse","sourceType","plugins","routeSet","Set","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","error"]}
1
+ {"version":3,"sources":["../../src/bin/generate-page-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\nimport * as t from '@babel/types';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst appPath = path.resolve(process.cwd(), getArg('--app-path', './client/src/app.tsx'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'page-routes.json');\n\ninterface RouteInfo {\n path?: string;\n index?: boolean;\n [key: string]: unknown;\n}\n\nfunction isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n return (\n t.isJSXIdentifier(openingElement.name) &&\n openingElement.name.name === 'Route'\n );\n}\n\nfunction evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n const quasis = templateLiteral.quasis;\n const expressions = templateLiteral.expressions;\n\n if (quasis.length === 1 && expressions.length === 0) {\n return quasis[0].value.raw;\n }\n\n return quasis.map((q) => q.value.raw).join('');\n}\n\nfunction extractRouteInfo(openingElement: t.JSXOpeningElement): RouteInfo {\n const routeInfo: RouteInfo = {};\n\n openingElement.attributes.forEach((attr) => {\n if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n const name = attr.name.name;\n let value: unknown;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n const expression = attr.value.expression;\n if (t.isStringLiteral(expression)) {\n value = expression.value;\n } else if (t.isTemplateLiteral(expression)) {\n value = evaluateTemplateLiteral(expression);\n } else {\n value = true;\n }\n }\n } else {\n value = true;\n }\n\n routeInfo[name] = value;\n }\n });\n\n return routeInfo;\n}\n\nfunction buildFullPath(routeStack: RouteInfo[], currentRoute: RouteInfo): string | null {\n let fullPath = '';\n\n for (let i = 0; i < routeStack.length; i++) {\n if (routeStack[i].path) {\n let parentPath = routeStack[i].path!;\n if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n if (parentPath.endsWith('/') && parentPath !== '/') {\n parentPath = parentPath.slice(0, -1);\n }\n\n fullPath += parentPath === '/' ? '' : parentPath;\n }\n }\n\n if (currentRoute.index) {\n return fullPath || '/';\n } else if (currentRoute.path) {\n const routePath = currentRoute.path;\n\n if (routePath === '*') {\n return null;\n }\n\n if (!routePath.startsWith('/')) {\n fullPath = `${fullPath}/${routePath}`;\n } else {\n fullPath = routePath;\n }\n\n if (fullPath === '') fullPath = '/';\n if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n return fullPath;\n }\n\n return null;\n}\n\nfunction parsePageRoutes(appFilePath: string): Array<{ path: string }> {\n if (!fs.existsSync(appFilePath)) {\n throw new Error(`App file does not exist: ${appFilePath}`);\n }\n\n const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n const ast = parse(sourceCode, {\n sourceType: 'module',\n plugins: [\n 'jsx',\n 'typescript',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n });\n\n const routeSet = new Set<string>();\n const routeStack: RouteInfo[] = [];\n\n traverse(ast, {\n JSXElement: {\n enter(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n routeStack.push(extractRouteInfo(openingElement));\n }\n },\n exit(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n const currentRoute = routeStack.pop();\n if (currentRoute && currentRoute.path === '*') return;\n if (currentRoute && (currentRoute.path || currentRoute.index)) {\n const fullPath = buildFullPath(routeStack, currentRoute);\n if (fullPath) routeSet.add(fullPath);\n }\n }\n },\n },\n });\n\n // page-routes 不带 basePath 前缀,供日志服务消费\n const routes = Array.from(routeSet).map((routePath) => ({ path: routePath }));\n return routes.length > 0 ? routes : [{ path: '/' }];\n}\n\ntry {\n const routes = parsePageRoutes(appPath);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.warn('[page-routes] Failed to generate page-routes.json, writing empty fallback:', error);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));\n}\n"],"mappings":"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","names":["traverse","_traverse","default","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","appPath","path","resolve","cwd","outDir","filename","isRouteComponent","openingElement","isJSXIdentifier","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","parentPath","startsWith","endsWith","routePath","parsePageRoutes","appFilePath","fs","existsSync","Error","sourceCode","readFileSync","ast","parse","sourceType","plugins","routeSet","Set","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","error","warn"]}
@@ -159,7 +159,12 @@ try {
159
159
  fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));
160
160
  console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);
161
161
  } catch (error) {
162
- console.error("[page-routes] Failed to generate page-routes.json:", error);
163
- process.exit(1);
162
+ console.warn("[page-routes] Failed to generate page-routes.json, writing empty fallback:", error);
163
+ if (!fs.existsSync(outDir)) {
164
+ fs.mkdirSync(outDir, {
165
+ recursive: true
166
+ });
167
+ }
168
+ fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));
164
169
  }
165
170
  //# sourceMappingURL=generate-page-routes.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/generate-page-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\nimport * as t from '@babel/types';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst appPath = path.resolve(process.cwd(), getArg('--app-path', './client/src/app.tsx'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'page-routes.json');\n\ninterface RouteInfo {\n path?: string;\n index?: boolean;\n [key: string]: unknown;\n}\n\nfunction isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n return (\n t.isJSXIdentifier(openingElement.name) &&\n openingElement.name.name === 'Route'\n );\n}\n\nfunction evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n const quasis = templateLiteral.quasis;\n const expressions = templateLiteral.expressions;\n\n if (quasis.length === 1 && expressions.length === 0) {\n return quasis[0].value.raw;\n }\n\n return quasis.map((q) => q.value.raw).join('');\n}\n\nfunction extractRouteInfo(openingElement: t.JSXOpeningElement): RouteInfo {\n const routeInfo: RouteInfo = {};\n\n openingElement.attributes.forEach((attr) => {\n if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n const name = attr.name.name;\n let value: unknown;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n const expression = attr.value.expression;\n if (t.isStringLiteral(expression)) {\n value = expression.value;\n } else if (t.isTemplateLiteral(expression)) {\n value = evaluateTemplateLiteral(expression);\n } else {\n value = true;\n }\n }\n } else {\n value = true;\n }\n\n routeInfo[name] = value;\n }\n });\n\n return routeInfo;\n}\n\nfunction buildFullPath(routeStack: RouteInfo[], currentRoute: RouteInfo): string | null {\n let fullPath = '';\n\n for (let i = 0; i < routeStack.length; i++) {\n if (routeStack[i].path) {\n let parentPath = routeStack[i].path!;\n if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n if (parentPath.endsWith('/') && parentPath !== '/') {\n parentPath = parentPath.slice(0, -1);\n }\n\n fullPath += parentPath === '/' ? '' : parentPath;\n }\n }\n\n if (currentRoute.index) {\n return fullPath || '/';\n } else if (currentRoute.path) {\n const routePath = currentRoute.path;\n\n if (routePath === '*') {\n return null;\n }\n\n if (!routePath.startsWith('/')) {\n fullPath = `${fullPath}/${routePath}`;\n } else {\n fullPath = routePath;\n }\n\n if (fullPath === '') fullPath = '/';\n if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n return fullPath;\n }\n\n return null;\n}\n\nfunction parsePageRoutes(appFilePath: string): Array<{ path: string }> {\n if (!fs.existsSync(appFilePath)) {\n throw new Error(`App file does not exist: ${appFilePath}`);\n }\n\n const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n const ast = parse(sourceCode, {\n sourceType: 'module',\n plugins: [\n 'jsx',\n 'typescript',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n });\n\n const routeSet = new Set<string>();\n const routeStack: RouteInfo[] = [];\n\n traverse(ast, {\n JSXElement: {\n enter(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n routeStack.push(extractRouteInfo(openingElement));\n }\n },\n exit(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n const currentRoute = routeStack.pop();\n if (currentRoute && currentRoute.path === '*') return;\n if (currentRoute && (currentRoute.path || currentRoute.index)) {\n const fullPath = buildFullPath(routeStack, currentRoute);\n if (fullPath) routeSet.add(fullPath);\n }\n }\n },\n },\n });\n\n // page-routes 不带 basePath 前缀,供日志服务消费\n const routes = Array.from(routeSet).map((routePath) => ({ path: routePath }));\n return routes.length > 0 ? routes : [{ path: '/' }];\n}\n\ntry {\n const routes = parsePageRoutes(appPath);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.error('[page-routes] Failed to generate page-routes.json:', error);\n process.exit(1);\n}\n"],"mappings":"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","names":["fs","path","parse","_traverse","t","traverse","_traverse","default","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","appPath","path","resolve","cwd","outDir","filename","isRouteComponent","openingElement","isJSXIdentifier","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","parentPath","startsWith","endsWith","routePath","parsePageRoutes","appFilePath","fs","existsSync","Error","sourceCode","readFileSync","ast","parse","sourceType","plugins","routeSet","Set","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","error"]}
1
+ {"version":3,"sources":["../../src/bin/generate-page-routes.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\nimport * as t from '@babel/types';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n const index = args.indexOf(name);\n if (index !== -1 && args[index + 1]) {\n return args[index + 1];\n }\n return defaultValue;\n}\n\nconst appPath = path.resolve(process.cwd(), getArg('--app-path', './client/src/app.tsx'));\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'page-routes.json');\n\ninterface RouteInfo {\n path?: string;\n index?: boolean;\n [key: string]: unknown;\n}\n\nfunction isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n return (\n t.isJSXIdentifier(openingElement.name) &&\n openingElement.name.name === 'Route'\n );\n}\n\nfunction evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n const quasis = templateLiteral.quasis;\n const expressions = templateLiteral.expressions;\n\n if (quasis.length === 1 && expressions.length === 0) {\n return quasis[0].value.raw;\n }\n\n return quasis.map((q) => q.value.raw).join('');\n}\n\nfunction extractRouteInfo(openingElement: t.JSXOpeningElement): RouteInfo {\n const routeInfo: RouteInfo = {};\n\n openingElement.attributes.forEach((attr) => {\n if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n const name = attr.name.name;\n let value: unknown;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n const expression = attr.value.expression;\n if (t.isStringLiteral(expression)) {\n value = expression.value;\n } else if (t.isTemplateLiteral(expression)) {\n value = evaluateTemplateLiteral(expression);\n } else {\n value = true;\n }\n }\n } else {\n value = true;\n }\n\n routeInfo[name] = value;\n }\n });\n\n return routeInfo;\n}\n\nfunction buildFullPath(routeStack: RouteInfo[], currentRoute: RouteInfo): string | null {\n let fullPath = '';\n\n for (let i = 0; i < routeStack.length; i++) {\n if (routeStack[i].path) {\n let parentPath = routeStack[i].path!;\n if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n if (parentPath.endsWith('/') && parentPath !== '/') {\n parentPath = parentPath.slice(0, -1);\n }\n\n fullPath += parentPath === '/' ? '' : parentPath;\n }\n }\n\n if (currentRoute.index) {\n return fullPath || '/';\n } else if (currentRoute.path) {\n const routePath = currentRoute.path;\n\n if (routePath === '*') {\n return null;\n }\n\n if (!routePath.startsWith('/')) {\n fullPath = `${fullPath}/${routePath}`;\n } else {\n fullPath = routePath;\n }\n\n if (fullPath === '') fullPath = '/';\n if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n return fullPath;\n }\n\n return null;\n}\n\nfunction parsePageRoutes(appFilePath: string): Array<{ path: string }> {\n if (!fs.existsSync(appFilePath)) {\n throw new Error(`App file does not exist: ${appFilePath}`);\n }\n\n const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n const ast = parse(sourceCode, {\n sourceType: 'module',\n plugins: [\n 'jsx',\n 'typescript',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n });\n\n const routeSet = new Set<string>();\n const routeStack: RouteInfo[] = [];\n\n traverse(ast, {\n JSXElement: {\n enter(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n routeStack.push(extractRouteInfo(openingElement));\n }\n },\n exit(nodePath: any) {\n const { openingElement } = nodePath.node;\n if (isRouteComponent(openingElement)) {\n const currentRoute = routeStack.pop();\n if (currentRoute && currentRoute.path === '*') return;\n if (currentRoute && (currentRoute.path || currentRoute.index)) {\n const fullPath = buildFullPath(routeStack, currentRoute);\n if (fullPath) routeSet.add(fullPath);\n }\n }\n },\n },\n });\n\n // page-routes 不带 basePath 前缀,供日志服务消费\n const routes = Array.from(routeSet).map((routePath) => ({ path: routePath }));\n return routes.length > 0 ? routes : [{ path: '/' }];\n}\n\ntry {\n const routes = parsePageRoutes(appPath);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n const outPath = path.resolve(outDir, filename);\n fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n console.warn('[page-routes] Failed to generate page-routes.json, writing empty fallback:', error);\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));\n}\n"],"mappings":"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","names":["fs","path","parse","_traverse","t","traverse","_traverse","default","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","appPath","path","resolve","cwd","outDir","filename","isRouteComponent","openingElement","isJSXIdentifier","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","parentPath","startsWith","endsWith","routePath","parsePageRoutes","appFilePath","fs","existsSync","Error","sourceCode","readFileSync","ast","parse","sourceType","plugins","routeSet","Set","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","error","warn"]}
package/dist/index.cjs CHANGED
@@ -31,7 +31,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
- apiRoutesPlugin: () => apiRoutesPlugin,
35
34
  createCollectLogsMiddleware: () => createCollectLogsMiddleware,
36
35
  createDevLogsMiddleware: () => createDevLogsMiddleware,
37
36
  createOpenapiMiddleware: () => createOpenapiMiddleware,
@@ -1836,8 +1835,8 @@ function hasSpecialPatterns(pattern) {
1836
1835
  return /[{*]/.test(pattern);
1837
1836
  }
1838
1837
  __name(hasSpecialPatterns, "hasSpecialPatterns");
1839
- function normalizePathForMatching(path8) {
1840
- return path8.replace(/\/+/g, "/").replace(/\/+$/, "");
1838
+ function normalizePathForMatching(path7) {
1839
+ return path7.replace(/\/+/g, "/").replace(/\/+$/, "");
1841
1840
  }
1842
1841
  __name(normalizePathForMatching, "normalizePathForMatching");
1843
1842
 
@@ -2386,7 +2385,7 @@ __name(readLogsBySource, "readLogsBySource");
2386
2385
  // src/middlewares/dev-logs/services/trigger.service.ts
2387
2386
  var import_node_fs9 = require("fs");
2388
2387
  var import_node_readline3 = require("readline");
2389
- async function readTriggerList(filePath, trigger, path8, limit, triggerID) {
2388
+ async function readTriggerList(filePath, trigger, path7, limit, triggerID) {
2390
2389
  if (!await fileExists(filePath)) {
2391
2390
  return void 0;
2392
2391
  }
@@ -2412,7 +2411,7 @@ async function readTriggerList(filePath, trigger, path8, limit, triggerID) {
2412
2411
  if (alreadyAdded) {
2413
2412
  return false;
2414
2413
  }
2415
- const isAutomationTrigger = builder.path?.endsWith(path8);
2414
+ const isAutomationTrigger = builder.path?.endsWith(path7);
2416
2415
  if (!isAutomationTrigger) {
2417
2416
  return false;
2418
2417
  }
@@ -2495,7 +2494,7 @@ async function readTriggerList(filePath, trigger, path8, limit, triggerID) {
2495
2494
  };
2496
2495
  }
2497
2496
  __name(readTriggerList, "readTriggerList");
2498
- async function readTriggerDetail(filePath, path8, instanceID) {
2497
+ async function readTriggerDetail(filePath, path7, instanceID) {
2499
2498
  const exists = await fileExists(filePath);
2500
2499
  if (!exists) {
2501
2500
  return void 0;
@@ -2511,7 +2510,7 @@ async function readTriggerDetail(filePath, path8, instanceID) {
2511
2510
  for await (const line of rl) {
2512
2511
  const entry = parseLogLine(line);
2513
2512
  if (!entry) continue;
2514
- const isAutomationTrigger = entry.path?.endsWith(path8);
2513
+ const isAutomationTrigger = entry.path?.endsWith(path7);
2515
2514
  const hasInstanceID = entry.instance_id === instanceID && entry.trigger;
2516
2515
  if (!isAutomationTrigger || !hasInstanceID) continue;
2517
2516
  matches.push(entry);
@@ -2765,16 +2764,16 @@ function createGetTriggerListHandler(logDir) {
2765
2764
  });
2766
2765
  }
2767
2766
  const triggerID = typeof req.query.triggerID === "string" ? req.query.triggerID.trim() : void 0;
2768
- const path8 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2767
+ const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2769
2768
  const limit = parseLimit(req.query.limit, 10, 200);
2770
2769
  try {
2771
- const result = await readTriggerList(traceLogPath, trigger, path8, limit, triggerID);
2770
+ const result = await readTriggerList(traceLogPath, trigger, path7, limit, triggerID);
2772
2771
  if (!result) {
2773
2772
  return handleNotFound(res, traceLogPath);
2774
2773
  }
2775
2774
  res.json({
2776
2775
  file: getRelativePath(traceLogPath),
2777
- path: path8,
2776
+ path: path7,
2778
2777
  ...result
2779
2778
  });
2780
2779
  } catch (error) {
@@ -2792,9 +2791,9 @@ function createGetTriggerDetailHandler(logDir) {
2792
2791
  message: "instanceID is required"
2793
2792
  });
2794
2793
  }
2795
- const path8 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2794
+ const path7 = typeof req.query.path === "string" ? req.query.path.trim() : "/__innerapi__/automation/invoke";
2796
2795
  try {
2797
- const result = await readTriggerDetail(traceLogPath, path8, instanceID);
2796
+ const result = await readTriggerDetail(traceLogPath, path7, instanceID);
2798
2797
  if (!result) {
2799
2798
  return handleNotFound(res, traceLogPath);
2800
2799
  }
@@ -3420,8 +3419,8 @@ __name(createSSEHandler, "createSSEHandler");
3420
3419
 
3421
3420
  // src/middlewares/dev-logs/api-list-handler.ts
3422
3421
  var SERVER_PORT = process.env.SERVER_PORT || "3000";
3423
- function extractModuleFromPath(path8) {
3424
- const segments = path8.split("/").filter(Boolean);
3422
+ function extractModuleFromPath(path7) {
3423
+ const segments = path7.split("/").filter(Boolean);
3425
3424
  let startIndex = 0;
3426
3425
  if (segments[0] === "api") {
3427
3426
  startIndex = 1;
@@ -3436,8 +3435,8 @@ function extractModuleFromPath(path8) {
3436
3435
  return moduleName;
3437
3436
  }
3438
3437
  __name(extractModuleFromPath, "extractModuleFromPath");
3439
- function generateRouteId(method, path8) {
3440
- const cleanPath = path8.replace(/[/:]/g, "_").replace(/^_+|_+$/g, "");
3438
+ function generateRouteId(method, path7) {
3439
+ const cleanPath = path7.replace(/[/:]/g, "_").replace(/^_+|_+$/g, "");
3441
3440
  return `${method.toLowerCase()}_${cleanPath}`;
3442
3441
  }
3443
3442
  __name(generateRouteId, "generateRouteId");
@@ -3911,38 +3910,8 @@ async function registerMiddlewares(server, middlewares, options) {
3911
3910
  }
3912
3911
  }
3913
3912
  __name(registerMiddlewares, "registerMiddlewares");
3914
-
3915
- // src/tsup-plugin-api-routes.ts
3916
- var import_fs3 = __toESM(require("fs"), 1);
3917
- var import_path3 = __toESM(require("path"), 1);
3918
- function apiRoutesPlugin(options = {}) {
3919
- const { serverDir = "./src", filename = "api-routes.json" } = options;
3920
- return {
3921
- name: "api-routes-generator",
3922
- setup(build) {
3923
- build.onEnd(() => {
3924
- try {
3925
- const resolvedServerDir = import_path3.default.resolve(process.cwd(), serverDir);
3926
- const routes = parseApiRoutes(resolvedServerDir);
3927
- const outdir = import_path3.default.resolve(process.cwd(), "dist");
3928
- const outPath = import_path3.default.resolve(outdir, filename);
3929
- if (!import_fs3.default.existsSync(outdir)) {
3930
- import_fs3.default.mkdirSync(outdir, {
3931
- recursive: true
3932
- });
3933
- }
3934
- import_fs3.default.writeFileSync(outPath, JSON.stringify(routes, null, 2));
3935
- } catch (error) {
3936
- console.warn("[api-routes-plugin] Failed to generate api-routes.json:", error);
3937
- }
3938
- });
3939
- }
3940
- };
3941
- }
3942
- __name(apiRoutesPlugin, "apiRoutesPlugin");
3943
3913
  // Annotate the CommonJS export names for ESM import in node:
3944
3914
  0 && (module.exports = {
3945
- apiRoutesPlugin,
3946
3915
  createCollectLogsMiddleware,
3947
3916
  createDevLogsMiddleware,
3948
3917
  createOpenapiMiddleware,