code-to-design 0.2.2 → 0.2.3

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.
@@ -1223,7 +1223,13 @@ function matchMockUrl(requestUrl, requestMethod, mockPattern) {
1223
1223
  return false;
1224
1224
  }
1225
1225
  function isApiUrl(url) {
1226
- return url.includes("/api/") || url.includes(":8000") || url.includes(":3000/api");
1226
+ if (url.includes("/_next/") || url.includes("/__next") || url.includes("/favicon")) return false;
1227
+ try {
1228
+ const parsed = new URL(url);
1229
+ return parsed.pathname.startsWith("/api/");
1230
+ } catch {
1231
+ return url.includes("/api/");
1232
+ }
1227
1233
  }
1228
1234
 
1229
1235
  // ../core/src/render/pre-renderer.ts
@@ -1265,33 +1271,34 @@ async function setupMockInterception(page, devServerUrl, mockConfig, authConfig)
1265
1271
  }));
1266
1272
  await page.context().addCookies(cookies);
1267
1273
  }
1268
- if (authConfig.hasAuth) {
1269
- const mockUser = mockConfig.authMock?.authCheckResponse?.body ?? {
1274
+ const sourceHasLocalStorageAuth = /persist\s*\(|localStorage|auth-storage|useAuthStore/i.test(
1275
+ mockConfig.apiMocks ? JSON.stringify(mockConfig) : ""
1276
+ );
1277
+ const contextHasZustand = /zustand|persist.*auth|auth-storage|useAuthStore/i.test(authConfig.apiBaseUrl ?? "");
1278
+ const usesClientSideAuth = authConfig.hasAuth && authConfig.cookieNames.length === 0;
1279
+ if (usesClientSideAuth) {
1280
+ const mockUser = JSON.stringify(mockConfig.authMock?.authCheckResponse?.body ?? {
1270
1281
  id: "mock_user",
1271
1282
  email: "demo@c2d.dev",
1272
1283
  name: "Demo User"
1273
- };
1274
- const mockToken = "c2d_mock_jwt_token";
1275
- await page.goto(devServerUrl, { waitUntil: "commit", timeout: 1e4 }).catch(() => {
1276
1284
  });
1277
- await page.evaluate(`(() => {
1278
- // Zustand persist pattern (auth-storage)
1279
- const zustandState = {
1280
- state: {
1281
- user: ${JSON.stringify(mockUser)},
1282
- tokens: { access: "${mockToken}", refresh: "${mockToken}" },
1283
- isAuthenticated: true,
1284
- isLoading: false,
1285
- },
1286
- version: 0,
1287
- };
1288
- localStorage.setItem('auth-storage', JSON.stringify(zustandState));
1289
-
1290
- // Common alternatives
1291
- localStorage.setItem('token', '"${mockToken}"');
1292
- localStorage.setItem('access_token', '"${mockToken}"');
1293
- localStorage.setItem('user', JSON.stringify(${JSON.stringify(mockUser)}));
1294
- })()`);
1285
+ const mockToken = "c2d_mock_jwt_token";
1286
+ await page.addInitScript(`
1287
+ try {
1288
+ var zustandState = {
1289
+ state: {
1290
+ user: ${mockUser},
1291
+ tokens: { access: "${mockToken}", refresh: "${mockToken}" },
1292
+ isAuthenticated: true,
1293
+ isLoading: false,
1294
+ },
1295
+ version: 0,
1296
+ };
1297
+ localStorage.setItem('auth-storage', JSON.stringify(zustandState));
1298
+ localStorage.setItem('token', '"${mockToken}"');
1299
+ localStorage.setItem('access_token', '"${mockToken}"');
1300
+ } catch(e) {}
1301
+ `);
1295
1302
  }
1296
1303
  const authMockBody = mockConfig.authMock?.authCheckResponse ? JSON.stringify(mockConfig.authMock.authCheckResponse.body) : JSON.stringify({ id: "mock_user", email: "demo@c2d.dev", name: "Demo User", email_verified: true, avatar_url: null, created_at: "2026-01-01T00:00:00Z" });
1297
1304
  const AUTH_PATTERNS = ["/auth/me", "/auth/session", "/api/auth/me", "/api/user/me", "/api/auth/session"];
@@ -2179,4 +2186,4 @@ export {
2179
2186
  detectNextJsProject,
2180
2187
  runScan
2181
2188
  };
2182
- //# sourceMappingURL=chunk-3CJ7RVFI.js.map
2189
+ //# sourceMappingURL=chunk-EBLAP5DI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/scan.ts","../../core/src/discovery/route-scanner.ts","../../core/src/analysis/code-analyzer.ts","../../core/src/analysis/auth-detector.ts","../../core/src/analysis/endpoint-extractor.ts","../../core/src/mock/llm-client.ts","../../core/src/mock/prompt-templates.ts","../../core/src/mock/mock-generator.ts","../../core/src/render/pre-renderer.ts","../../core/src/render/dev-server.ts","../../core/src/render/style-inliner.ts","../../core/src/render/interaction-capturer.ts","../../core/src/render/url-matcher.ts","../src/server/canvas-server.ts","../src/server/api-routes.ts","../src/config.ts","../src/utils/progress.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { rm, mkdir } from 'node:fs/promises';\nimport { existsSync, watch as fsWatch } from 'node:fs';\nimport {\n scanRoutes,\n analyzePage,\n generateMocks,\n preRenderPages,\n type RenderTask,\n type MockGeneratorOptions,\n} from '@code-to-design/core';\nimport { startCanvasServer } from '../server/canvas-server.js';\nimport { loadConfig, detectProject } from '../config.js';\nimport * as ui from '../utils/progress.js';\n\n/**\n * Main scan command — runs the full Code to Design pipeline.\n *\n * 1. Detect project type\n * 2. Discover routes\n * 3. Analyze code + generate mocks\n * 4. Pre-render pages\n * 5. Start canvas server\n */\nexport async function runScan(options: {\n projectRoot: string;\n skipRender?: boolean;\n open?: boolean;\n watch?: boolean;\n}): Promise<void> {\n const { projectRoot, skipRender = false, open = true, watch = false } = options;\n\n ui.banner();\n\n // Load config\n const config = await loadConfig(projectRoot);\n\n // Step 1: Detect project\n ui.header('Detecting project...');\n const project = await detectProject(projectRoot);\n\n if (!project.isSupported) {\n ui.error('Unsupported project type.');\n ui.log('Code to Design supports Next.js (App Router / Pages Router) and React Router (Vite) projects.');\n process.exit(1);\n }\n\n if (project.projectType !== 'react-router' && !project.appDir) {\n ui.error('No app/ or pages/ directory found.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName} (${project.projectType})`);\n if (project.appDir) {\n ui.success(`App directory: ${project.appDir}`);\n }\n\n const c2dDir = join(projectRoot, '.c2d');\n\n // If --skip-render, just start the server with existing renders\n if (skipRender) {\n if (!existsSync(join(c2dDir, 'manifest.json'))) {\n ui.error('No previous renders found. Run without --skip-render first.');\n process.exit(1);\n }\n ui.log('Skipping render, using existing canvas data...');\n await startServer(c2dDir, config.port, open, projectRoot);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const scanDir = project.projectType === 'react-router' ? project.projectRoot : project.appDir!;\n const routerType = project.projectType === 'react-router' ? 'react-router' as const\n : project.projectType === 'nextjs-pages' ? 'pages-router' as const\n : 'app-router' as const;\n const routes = await scanRoutes({ appDir: scanDir, routerType });\n\n if (routes.length === 0) {\n ui.error('No routes found in app/ directory.');\n process.exit(1);\n }\n\n // Filter excluded routes\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n ui.success(`Found ${filteredRoutes.length} routes`);\n for (const r of filteredRoutes) {\n ui.log(` ${r.urlPath}${r.isDynamic ? ' [dynamic]' : ''}`);\n }\n\n // Step 3: Check API key\n if (!config.apiKey) {\n ui.warn('No API key configured. Mock generation will use fallback data.');\n ui.log('Set C2D_API_KEY env var or add apiKey to c2d.config.js');\n }\n\n // Step 4: Analyze and generate mocks\n ui.header('Analyzing code and generating mocks...');\n\n const renderTasks: RenderTask[] = [];\n let totalTokens = { input: 0, output: 0 };\n\n const mockOptions: MockGeneratorOptions = {\n apiKey: config.apiKey,\n };\n\n for (let i = 0; i < filteredRoutes.length; i++) {\n const route = filteredRoutes[i];\n ui.step(i + 1, filteredRoutes.length, `${route.urlPath}`);\n\n // Analyze page\n const analysis = await analyzePage(route, { projectRoot });\n\n // Generate mocks\n const { configs, tokenUsage } = await generateMocks(analysis, mockOptions);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n\n // Create render tasks\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n if (totalTokens.input > 0) {\n ui.success(`Mock generation complete (${totalTokens.input} input tokens, ${totalTokens.output} output tokens)`);\n } else {\n ui.success('Using fallback mocks (no API key or no API dependencies)');\n }\n\n // Step 5: Pre-render\n ui.header(`Pre-rendering ${renderTasks.length} page states...`);\n\n // Clear previous renders but preserve comments\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n const { results, manifest } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n onProgress: (completed, total, result) => {\n const pct = Math.round((completed / total) * 100);\n const icon = result.success ? '✓' : '✗';\n const label = `${result.route.urlPath} [${result.stateName}]`;\n process.stdout.write(`\\r ${icon} ${completed}/${total} (${pct}%) ${label}${''.padEnd(20)}`);\n if (completed === total) process.stdout.write('\\n');\n },\n });\n\n const successCount = results.filter((r) => r.success).length;\n const failCount = results.filter((r) => !r.success).length;\n\n ui.success(`Rendered ${successCount}/${results.length} pages`);\n if (failCount > 0) {\n ui.warn(`${failCount} pages failed to render`);\n for (const r of results.filter((r) => !r.success)) {\n ui.error(` ${r.route.urlPath} [${r.stateName}]: ${r.error}`);\n }\n }\n\n // Step 6: Start canvas server\n if (watch) {\n // In watch mode, start the server without blocking so we can watch for changes\n const server = await startServerNonBlocking(c2dDir, config.port, open, projectRoot);\n const watchDir = project.projectType === 'react-router'\n ? join(projectRoot, 'src')\n : project.appDir!;\n watchAndRerender(projectRoot, watchDir, c2dDir, config, routerType);\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n } else {\n await startServer(c2dDir, config.port, open, projectRoot);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean, projectRoot?: string): Promise<void> {\n ui.header('Starting canvas server...');\n\n // Resolve canvas app directory: find canvas-dist relative to this package\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Press Ctrl+C to stop\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n}\n\nasync function startServerNonBlocking(\n c2dDir: string,\n port: number,\n open: boolean,\n projectRoot?: string,\n): Promise<{ url: string; close: () => Promise<void> }> {\n ui.header('Starting canvas server...');\n\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir: canvasDir!,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Watching for file changes...\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n return server;\n}\n\n/**\n * Find the canvas-dist directory by walking up from the module's location\n * until we find a directory containing canvas-dist/.\n * Works in both npm-installed and monorepo-dev environments.\n */\nasync function resolveCanvasDir(c2dDir: string): Promise<string> {\n const { fileURLToPath } = await import('node:url');\n const { dirname } = await import('node:path');\n const __filename = fileURLToPath(import.meta.url);\n\n // Walk up from the current file's directory to find canvas-dist/\n let dir = dirname(__filename);\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, 'canvas-dist');\n if (existsSync(candidate) && existsSync(join(candidate, 'index.html'))) {\n return candidate;\n }\n dir = dirname(dir);\n }\n\n // Fallback: try monorepo dev location\n const monorepoDev = join(dirname(__filename), '..', '..', '..', '..', 'apps', 'canvas', 'dist');\n if (existsSync(monorepoDev) && existsSync(join(monorepoDev, 'index.html'))) {\n return monorepoDev;\n }\n\n // Last resort: write placeholder\n const placeholder = join(c2dDir, '_canvas');\n await mkdir(placeholder, { recursive: true });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(join(placeholder, 'index.html'), `<!DOCTYPE html><html><body>\n <h1>Code to Design</h1>\n <p>Canvas app not built. Run: <code>cd apps/canvas && npx vite build</code></p>\n <p><a href=\"/api/manifest\">View Manifest</a></p>\n </body></html>`);\n return placeholder;\n}\n\n/** File extensions to watch for changes. */\nconst WATCH_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.css']);\n\n/** Directories and patterns to ignore during watch. */\nfunction shouldIgnoreFile(filename: string | null): boolean {\n if (!filename) return true;\n const ignored = ['node_modules', '.next', '.c2d', '.git'];\n if (ignored.some((dir) => filename.includes(dir))) return true;\n const ext = filename.slice(filename.lastIndexOf('.'));\n return !WATCH_EXTENSIONS.has(ext);\n}\n\nfunction watchAndRerender(\n projectRoot: string,\n appDir: string,\n c2dDir: string,\n config: Awaited<ReturnType<typeof loadConfig>>,\n routerType?: 'app-router' | 'pages-router' | 'react-router',\n): void {\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n let isRendering = false;\n\n ui.log(`Watching ${appDir} for changes...`);\n\n fsWatch(appDir, { recursive: true }, (_event, filename) => {\n if (shouldIgnoreFile(filename as string | null)) return;\n\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (isRendering) return;\n isRendering = true;\n\n ui.log(`\\nFile changed: ${filename}. Re-rendering...`);\n\n try {\n // Re-discover routes\n const routes = await scanRoutes({ appDir, routerType });\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n // Re-analyze and generate mocks\n const renderTasks: RenderTask[] = [];\n const mockOptions: MockGeneratorOptions = { apiKey: config.apiKey };\n\n for (const route of filteredRoutes) {\n const analysis = await analyzePage(route, { projectRoot });\n const { configs } = await generateMocks(analysis, mockOptions);\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n // Clear previous renders\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n // Pre-render\n const { results } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n });\n\n const successCount = results.filter((r) => r.success).length;\n ui.success(`Re-render complete. ${successCount} pages updated.`);\n } catch (err: any) {\n ui.error(`Re-render failed: ${err.message || err}`);\n } finally {\n isRendering = false;\n }\n }, 500);\n });\n}\n","import { readdir, readFile, stat } from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport { RouteInfo, RouteParam, ScanOptions } from './types.js';\n\nconst PAGE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx']);\nconst PAGE_BASENAMES = new Set(['page']);\n\n/** Files that should be skipped in Pages Router (special Next.js files). */\nconst PAGES_ROUTER_SKIP = new Set(['_app', '_document', '_error']);\n\n/**\n * Check if a filename is an App Router page file (page.tsx, page.js, etc.)\n */\nfunction isPageFile(filename: string): boolean {\n const ext = extname(filename);\n const basename = filename.slice(0, -ext.length);\n return PAGE_EXTENSIONS.has(ext) && PAGE_BASENAMES.has(basename);\n}\n\n/**\n * Check if a filename is a valid Pages Router page file.\n * Skips files starting with `_` and non-page extensions.\n */\nfunction isPagesRouterFile(filename: string): boolean {\n const ext = extname(filename);\n if (!PAGE_EXTENSIONS.has(ext)) return false;\n const basename = filename.slice(0, -ext.length);\n if (basename.startsWith('_')) return false;\n return true;\n}\n\n/**\n * Check if a directory should be skipped entirely.\n */\nfunction shouldSkipDir(name: string): boolean {\n // Private folders\n if (name.startsWith('_')) return true;\n // Parallel route slots\n if (name.startsWith('@')) return true;\n // Intercepting routes\n if (name.startsWith('(.)') || name.startsWith('(..)')) return true;\n // Build artifacts and dependencies\n if (name === 'node_modules' || name === '.next') return true;\n return false;\n}\n\n/**\n * Check if a directory is a route group (parenthesized name like \"(auth)\").\n * Route groups are stripped from the URL but recursed into.\n */\nfunction isRouteGroup(name: string): boolean {\n return name.startsWith('(') && name.endsWith(')') && !name.startsWith('(.');\n}\n\n/**\n * Parse a dynamic route segment and extract parameter info.\n * Returns null if the segment is not dynamic.\n */\nfunction parseDynamicSegment(segment: string): RouteParam | null {\n // Optional catch-all: [[...param]]\n const optionalCatchAll = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n if (optionalCatchAll) {\n return { name: optionalCatchAll[1], isCatchAll: true, isOptional: true };\n }\n\n // Required catch-all: [...param]\n const catchAll = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n if (catchAll) {\n return { name: catchAll[1], isCatchAll: true, isOptional: false };\n }\n\n // Single dynamic: [param]\n const dynamic = segment.match(/^\\[(.+)\\]$/);\n if (dynamic) {\n return { name: dynamic[1], isCatchAll: false, isOptional: false };\n }\n\n return null;\n}\n\n/**\n * Convert a dynamic segment to a URL-friendly representation.\n */\nfunction segmentToUrlPart(segment: string): string {\n const param = parseDynamicSegment(segment);\n if (!param) return segment;\n\n if (param.isCatchAll && param.isOptional) return `:${param.name}*`;\n if (param.isCatchAll) return `:${param.name}+`;\n return `:${param.name}`;\n}\n\n/**\n * Recursively scan a directory for Next.js App Router page files.\n */\nasync function scanDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPageFile(entry)) {\n const urlPath = '/' + urlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...params],\n isDynamic: params.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n if (shouldSkipDir(entry)) continue;\n\n if (isRouteGroup(entry)) {\n // Route groups: recurse but don't add to URL\n const nested = await scanDir(entryPath, urlSegments, params);\n routes.push(...nested);\n } else {\n // Regular or dynamic segment\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n }\n\n return routes;\n}\n\n/**\n * Recursively scan a Pages Router `pages/` directory for page files.\n *\n * Pages Router conventions:\n * - Any .tsx/.ts/.jsx/.js file is a route (not just `page.*`)\n * - `index.tsx` maps to the directory root\n * - `_app`, `_document`, `_error` are skipped\n * - Files starting with `_` are skipped\n * - `api/` directory is skipped (API routes)\n */\nasync function scanPagesDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPagesRouterFile(entry)) {\n const ext = extname(entry);\n const basename = entry.slice(0, -ext.length);\n\n // Convert filename to URL segment\n let fileUrlSegments: string[];\n let fileParams: RouteParam[];\n\n if (basename === 'index') {\n // index.tsx → use current directory path\n fileUrlSegments = urlSegments;\n fileParams = params;\n } else {\n const param = parseDynamicSegment(basename);\n const urlPart = segmentToUrlPart(basename);\n fileUrlSegments = [...urlSegments, urlPart];\n fileParams = param ? [...params, param] : params;\n }\n\n const urlPath = '/' + fileUrlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...fileParams],\n isDynamic: fileParams.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n // Skip api/ directory and hidden/private directories\n if (entry === 'api') continue;\n if (entry.startsWith('_')) continue;\n if (entry === 'node_modules' || entry === '.next') continue;\n\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanPagesDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n\n return routes;\n}\n\n/**\n * Parse a React Router `:param` dynamic segment into a RouteParam.\n */\nfunction parseReactRouterParam(segment: string): RouteParam | null {\n if (!segment.startsWith(':')) return null;\n return { name: segment.slice(1), isCatchAll: false, isOptional: false };\n}\n\n/**\n * Recursively find files under `dir` that have one of the given extensions.\n */\nasync function findFiles(dir: string, extensions: Set<string>): Promise<string[]> {\n const results: string[] = [];\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return results;\n }\n for (const entry of entries) {\n const full = join(dir, entry);\n const s = await stat(full).catch(() => null);\n if (!s) continue;\n if (s.isDirectory()) {\n if (entry === 'node_modules' || entry === '.git' || entry === 'dist' || entry === 'build') continue;\n results.push(...(await findFiles(full, extensions)));\n } else if (extensions.has(extname(entry))) {\n results.push(full);\n }\n }\n return results;\n}\n\n/**\n * Check if a project at the given root uses react-router-dom.\n */\nasync function hasReactRouter(projectRoot: string): Promise<boolean> {\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return 'react-router-dom' in deps || 'react-router' in deps;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract route paths from a source file that uses react-router-dom.\n *\n * This is a best-effort regex-based approach. It handles:\n * - JSX: `<Route path=\"/about\" ...`\n * - Object config: `{ path: \"/about\" ...` or `{ path: '/about' ...`\n * - createBrowserRouter / createRoutesFromElements patterns\n */\nfunction extractRoutePathsFromSource(source: string): string[] {\n const paths: string[] = [];\n const seen = new Set<string>();\n\n // Pattern 1: <Route path=\"...\" or <Route path='...'\n const jsxPattern = /<Route\\s[^>]*?path\\s*=\\s*[\"']([^\"']+)[\"']/g;\n let match: RegExpExecArray | null;\n while ((match = jsxPattern.exec(source)) !== null) {\n const p = match[1];\n if (p !== '*' && !seen.has(p)) {\n seen.add(p);\n paths.push(p);\n }\n }\n\n // Pattern 2: { path: \"...\" } or { path: '...' } in route config objects\n const objPattern = /path\\s*:\\s*[\"']([^\"']+)[\"']/g;\n while ((match = objPattern.exec(source)) !== null) {\n const p = match[1];\n if (p !== '*' && !seen.has(p)) {\n seen.add(p);\n paths.push(p);\n }\n }\n\n return paths;\n}\n\n/**\n * Scan a React Router project and extract route definitions from source code.\n *\n * This is inherently imprecise since React Router uses code-based routing.\n * The scanner finds files that import from `react-router-dom` and contain\n * route definitions, then extracts paths using regex.\n */\nasync function scanReactRouter(projectRoot: string): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n const seen = new Set<string>();\n\n // Find candidate source files under src/ (or project root if no src/)\n const srcDir = join(projectRoot, 'src');\n const scanRoot = await stat(srcDir).then(() => srcDir).catch(() => projectRoot);\n const files = await findFiles(scanRoot, PAGE_EXTENSIONS);\n\n for (const filePath of files) {\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n continue;\n }\n\n // Only process files that import from react-router-dom / react-router\n if (\n !source.includes('react-router-dom') &&\n !source.includes('react-router')\n ) {\n continue;\n }\n\n // Check for Route or createBrowserRouter usage\n if (\n !source.includes('Route') &&\n !source.includes('createBrowserRouter') &&\n !source.includes('createRoutesFromElements') &&\n !source.match(/path\\s*:\\s*[\"']/)\n ) {\n continue;\n }\n\n const extractedPaths = extractRoutePathsFromSource(source);\n\n for (const routePath of extractedPaths) {\n if (seen.has(routePath)) continue;\n seen.add(routePath);\n\n // Parse dynamic segments (:param)\n const segments = routePath.split('/').filter(Boolean);\n const params: RouteParam[] = [];\n for (const seg of segments) {\n const param = parseReactRouterParam(seg);\n if (param) params.push(param);\n }\n\n // Normalize path — ensure leading slash\n const urlPath = routePath.startsWith('/') ? routePath : '/' + routePath;\n\n routes.push({\n urlPath,\n filePath,\n params,\n isDynamic: params.length > 0,\n });\n }\n }\n\n return routes;\n}\n\n/**\n * Scan a project directory and extract all renderable routes.\n *\n * Supports Next.js App Router, Pages Router, and React Router (Vite):\n * - App Router: page.{js,jsx,ts,tsx} files, route groups, parallel routes, etc.\n * - Pages Router: any .tsx/.ts/.jsx/.js file (except _app, _document, _error, api/)\n * - React Router: regex-based extraction from source files importing react-router-dom\n *\n * For Next.js, `appDir` should point to the `app/` or `pages/` directory.\n * For React Router, `appDir` should point to the project root.\n * The scanner auto-detects which router convention to use based on `routerType`\n * (default 'auto' detects from directory name and project structure).\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir, routerType = 'auto' } = options;\n\n // React Router: explicit or auto-detected\n if (routerType === 'react-router') {\n const routes = await scanReactRouter(appDir);\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return routes;\n }\n\n if (routerType === 'auto') {\n // Check if this looks like a React Router project (has package.json with react-router-dom)\n const isReactRouter = await hasReactRouter(appDir);\n if (isReactRouter) {\n const routes = await scanReactRouter(appDir);\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return routes;\n }\n }\n\n const dirStat = await stat(appDir).catch(() => null);\n if (!dirStat || !dirStat.isDirectory()) {\n throw new Error(`App directory not found: ${appDir}`);\n }\n\n // Detect if this is a Pages Router directory\n const dirName = appDir.replace(/\\/$/, '').split('/').pop();\n const isPagesRouter = routerType === 'pages-router' || (routerType === 'auto' && dirName === 'pages');\n\n const routes = isPagesRouter\n ? await scanPagesDir(appDir, [], [])\n : await scanDir(appDir, [], []);\n\n // Sort routes for consistent output\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n\n return routes;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join, dirname, resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type { PageAnalysis, AnalyzeOptions, ExtractedEndpoint } from './types.js';\nimport { detectAuth } from './auth-detector.js';\nimport { extractEndpoints, extractBaseUrl } from './endpoint-extractor.js';\n\nconst DEFAULT_MAX_TOKENS = 8000;\nconst CHARS_PER_TOKEN = 4; // rough approximation\n\n/**\n * Extract import paths from TypeScript/JavaScript source code.\n * Uses regex — does not handle barrel exports or re-exports.\n */\nfunction extractImportPaths(source: string): string[] {\n const paths: string[] = [];\n // Match: import ... from '...' and import '...'\n const regex = /import\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n paths.push(match[1]);\n }\n return paths;\n}\n\n/**\n * Resolve tsconfig path aliases (e.g., @/lib/api → /absolute/path/lib/api).\n * Returns an absolute path when aliases contain absolute base paths.\n */\nfunction resolvePathAlias(\n importPath: string,\n aliases: Record<string, string>,\n): string | null {\n for (const [pattern, replacement] of Object.entries(aliases)) {\n const prefix = pattern.replace(/\\*$/, '');\n if (importPath.startsWith(prefix)) {\n const rest = importPath.slice(prefix.length);\n return replacement.replace(/\\*$/, '') + rest;\n }\n }\n return null;\n}\n\n/**\n * Read tsconfig.json and extract path aliases.\n */\nasync function readPathAliases(projectRoot: string): Promise<Record<string, string>> {\n const aliases: Record<string, string> = {};\n\n for (const filename of ['tsconfig.json', 'jsconfig.json']) {\n const configPath = join(projectRoot, filename);\n if (!existsSync(configPath)) continue;\n\n try {\n const content = await readFile(configPath, 'utf-8');\n // Strip JSON5-style comments while preserving // inside strings.\n // Match strings first (to skip them), then line & block comments.\n const stripped = content.replace(\n /\"(?:[^\"\\\\]|\\\\.)*\"|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm,\n (match) => (match.startsWith('\"') ? match : ''),\n );\n const config = JSON.parse(stripped);\n const paths = config.compilerOptions?.paths;\n const baseUrl = config.compilerOptions?.baseUrl || '.';\n const resolvedBaseUrl = resolve(projectRoot, baseUrl);\n\n if (paths) {\n for (const [key, values] of Object.entries(paths)) {\n const targets = values as string[];\n if (targets.length > 0) {\n // Store as absolute path for reliable resolution\n aliases[key] = join(resolvedBaseUrl, targets[0]);\n }\n }\n }\n } catch {\n // Can't parse tsconfig — skip aliases\n }\n }\n\n return aliases;\n}\n\n/**\n * Try to resolve an import path to an actual file.\n */\nfunction resolveImportToFile(importPath: string, fromDir: string): string | null {\n // Try exact path first, then with extensions\n const extensions = ['.ts', '.tsx', '.js', '.jsx'];\n const candidates: string[] = [];\n\n const resolved = resolve(fromDir, importPath);\n\n // Try exact\n candidates.push(resolved);\n // Try with extensions\n for (const ext of extensions) {\n candidates.push(resolved + ext);\n }\n // Try as directory with index\n for (const ext of extensions) {\n candidates.push(join(resolved, `index${ext}`));\n }\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Trace imports from a source file, up to maxDepth levels deep.\n * Returns a map of filePath → source content.\n */\nasync function traceImports(\n filePath: string,\n projectRoot: string,\n aliases: Record<string, string>,\n maxDepth: number,\n visited: Set<string> = new Set(),\n): Promise<Map<string, string>> {\n const results = new Map<string, string>();\n\n if (visited.has(filePath) || maxDepth < 0) return results;\n visited.add(filePath);\n\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n return results;\n }\n\n results.set(filePath, source);\n\n const importPaths = extractImportPaths(source);\n const fileDir = dirname(filePath);\n\n for (const importPath of importPaths) {\n // Skip node_modules imports\n if (!importPath.startsWith('.') && !importPath.startsWith('@/') && !importPath.startsWith('~/')) {\n // Check if it's a path alias\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (!aliasResolved) continue;\n\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else if (importPath.startsWith('.')) {\n // Relative import\n const resolved = resolveImportToFile(importPath, fileDir);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else {\n // Path alias (e.g., @/lib/api-client)\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (aliasResolved) {\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Estimate token count from a string (rough: ~4 chars per token).\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\n/**\n * Check if source code contains API call patterns.\n */\nfunction hasApiCalls(source: string): boolean {\n return /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\buseQuery\\b/.test(source)\n || /\\buseMutation\\b/.test(source)\n || /\\bapiRequest\\b/.test(source)\n || /\\bgetServerSideProps\\b/.test(source)\n || /\\bgetStaticProps\\b/.test(source)\n || /API_BASE_URL/.test(source)\n || /['\"]\\/api\\//.test(source)\n // Detect imports from api/client modules (common naming patterns)\n || /from\\s+['\"].*api[-_]?client.*['\"]/.test(source)\n || /from\\s+['\"].*\\/api['\"]/.test(source)\n || /from\\s+['\"].*\\/services\\//.test(source);\n}\n\n/**\n * Common API client file locations to scan eagerly.\n */\nconst API_CLIENT_CANDIDATES = [\n 'lib/api.ts', 'lib/api.tsx', 'lib/api.js', 'lib/api.jsx',\n 'lib/api-client.ts', 'lib/api-client.tsx', 'lib/api-client.js', 'lib/api-client.jsx',\n 'src/lib/api.ts', 'src/lib/api.tsx', 'src/lib/api.js', 'src/lib/api.jsx',\n 'src/lib/api-client.ts', 'src/lib/api-client.tsx', 'src/lib/api-client.js', 'src/lib/api-client.jsx',\n 'services/api.ts', 'services/api.js', 'services/api.tsx', 'services/api.jsx',\n 'src/services/api.ts', 'src/services/api.js', 'src/services/api.tsx', 'src/services/api.jsx',\n 'utils/api.ts', 'utils/api.js', 'utils/api.tsx', 'utils/api.jsx',\n 'src/utils/api.ts', 'src/utils/api.js', 'src/utils/api.tsx', 'src/utils/api.jsx',\n];\n\n/**\n * Check if source code contains patterns typical of an API client file.\n */\nfunction hasApiClientPatterns(source: string): boolean {\n return /\\.(get|post|put|delete|patch)\\s*\\(/.test(source)\n || /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\bbaseURL\\b/.test(source)\n || /\\bAPI_URL\\b/.test(source);\n}\n\n/**\n * Eagerly scan common locations for an API client file.\n * Returns the absolute path and content of the first matching file,\n * or null if none found.\n */\nasync function findApiClientEagerly(\n projectRoot: string,\n alreadyIncluded: Set<string>,\n): Promise<{ path: string; content: string } | null> {\n for (const candidate of API_CLIENT_CANDIDATES) {\n const fullPath = join(projectRoot, candidate);\n if (alreadyIncluded.has(fullPath)) continue;\n if (!existsSync(fullPath)) continue;\n\n try {\n const content = await readFile(fullPath, 'utf-8');\n if (hasApiClientPatterns(content)) {\n return { path: fullPath, content };\n }\n } catch {\n // Can't read — skip\n }\n }\n return null;\n}\n\n/**\n * Analyze a single page: read its source, trace imports, detect auth,\n * and produce a context string suitable for LLM mock generation.\n */\nexport async function analyzePage(\n route: RouteInfo,\n options: AnalyzeOptions,\n): Promise<PageAnalysis> {\n const { projectRoot, maxTokensPerPage = DEFAULT_MAX_TOKENS } = options;\n const maxChars = maxTokensPerPage * CHARS_PER_TOKEN;\n\n const aliases = await readPathAliases(projectRoot);\n\n // Trace imports from the page file, up to 2 levels deep\n const tracedFiles = await traceImports(route.filePath, projectRoot, aliases, 2);\n\n const resolvedImports = [...tracedFiles.keys()].filter(p => p !== route.filePath);\n const allSources = [...tracedFiles.values()];\n\n // Build the source context with file headers\n let sourceContext = '';\n for (const [filePath, content] of tracedFiles) {\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length + 1)\n : filePath;\n const section = `\\n// === ${relativePath} ===\\n${content}\\n`;\n\n if (sourceContext.length + section.length > maxChars) {\n // Truncation: include just the page file and skip the rest\n break;\n }\n sourceContext += section;\n }\n\n // Eager scan: find API client files that may not have been imported\n const alreadyIncluded = new Set(tracedFiles.keys());\n let apiClientPath: string | null = null;\n let apiClientSource: string | null = null;\n\n const eagerResult = await findApiClientEagerly(projectRoot, alreadyIncluded);\n if (eagerResult) {\n apiClientPath = eagerResult.path;\n apiClientSource = eagerResult.content;\n\n // Add to source context and resolved imports\n const relativePath = eagerResult.path.startsWith(projectRoot)\n ? eagerResult.path.slice(projectRoot.length + 1)\n : eagerResult.path;\n const section = `\\n// === ${relativePath} ===\\n${eagerResult.content}\\n`;\n\n if (sourceContext.length + section.length <= maxChars) {\n sourceContext += section;\n }\n\n resolvedImports.push(eagerResult.path);\n allSources.push(eagerResult.content);\n } else {\n // Check if an API client was already found via import tracing\n for (const [filePath, content] of tracedFiles) {\n if (filePath === route.filePath) continue;\n if (hasApiClientPatterns(content)) {\n apiClientPath = filePath;\n apiClientSource = content;\n break;\n }\n }\n }\n\n // Extract endpoints from API client if found\n let extractedEndpointsList: ExtractedEndpoint[] = [];\n let apiBaseUrl: string | null = null;\n if (apiClientSource) {\n extractedEndpointsList = extractEndpoints(apiClientSource);\n apiBaseUrl = extractBaseUrl(apiClientSource);\n }\n\n // Detect auth patterns\n const authConfig = await detectAuth(projectRoot, allSources);\n\n // Check for API dependencies — check both the truncated context and all traced sources\n const combinedSource = allSources.join('\\n');\n const hasApi = hasApiCalls(sourceContext) || hasApiCalls(combinedSource);\n\n // Collect unresolved imports\n const allImportPaths = allSources.flatMap(extractImportPaths);\n const resolvedSet = new Set(resolvedImports.map(p => p));\n const unresolvedImports = allImportPaths\n .filter(p => p.startsWith('.') || p.startsWith('@/') || p.startsWith('~/'))\n .filter(p => {\n // Check if this import was resolved to any file\n const aliasResolved = resolvePathAlias(p, aliases);\n const checkPath = aliasResolved\n ? resolveImportToFile(aliasResolved, projectRoot)\n : resolveImportToFile(p, dirname(route.filePath));\n return !checkPath;\n });\n\n return {\n route,\n sourceContext,\n resolvedImports,\n unresolvedImports: [...new Set(unresolvedImports)],\n authConfig,\n hasApiDependencies: hasApi,\n estimatedTokens: estimateTokens(sourceContext),\n apiClientPath,\n extractedEndpoints: extractedEndpointsList,\n apiBaseUrl,\n };\n}\n\n/**\n * Analyze all discovered routes in a project.\n */\nexport async function analyzeRoutes(\n routes: RouteInfo[],\n options: AnalyzeOptions,\n): Promise<PageAnalysis[]> {\n const results: PageAnalysis[] = [];\n for (const route of routes) {\n const analysis = await analyzePage(route, options);\n results.push(analysis);\n }\n return results;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { AuthConfig } from './types.js';\n\nconst MIDDLEWARE_FILES = ['middleware.ts', 'middleware.js', 'middleware.tsx', 'middleware.jsx'];\n\n/**\n * Extract cookie names from middleware source code.\n * Looks for patterns like: request.cookies.get('access_token')\n */\nfunction extractCookieNames(source: string): string[] {\n const cookies: string[] = [];\n const regex = /cookies\\.get\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n cookies.push(match[1]);\n }\n return [...new Set(cookies)];\n}\n\n/**\n * Extract API base URL from environment configuration.\n * Looks for NEXT_PUBLIC_API_URL or similar patterns.\n */\nfunction extractApiBaseUrl(source: string): string | null {\n const regex = /process\\.env\\.(\\w*API_URL\\w*)\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/;\n const match = source.match(regex);\n if (match) return match[2];\n\n const simpleRegex = /['\"]https?:\\/\\/[^'\"]+\\/api['\"]/;\n const simpleMatch = source.match(simpleRegex);\n if (simpleMatch) return simpleMatch[0].replace(/['\"]/g, '');\n\n return null;\n}\n\n/**\n * Extract auth check endpoint from source code.\n * Looks for patterns like: fetch(`${base}/auth/me`)\n */\nfunction extractAuthCheckEndpoint(source: string): string | null {\n const patterns = [\n /[`'\"](\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/auth\\/user)[`'\"]/,\n /[`'\"](\\/api\\/user\\/me)[`'\"]/,\n ];\n\n for (const pattern of patterns) {\n const match = source.match(pattern);\n if (match) return match[1];\n }\n\n return null;\n}\n\n/**\n * Detect authentication patterns in the target project.\n *\n * Scans for:\n * 1. middleware.ts/js with cookie checks\n * 2. Auth context providers with auth-check endpoints\n * 3. API base URL configuration\n */\nexport async function detectAuth(projectRoot: string, allSources: string[]): Promise<AuthConfig> {\n const config: AuthConfig = {\n hasAuth: false,\n cookieNames: [],\n authCheckEndpoint: null,\n apiBaseUrl: null,\n };\n\n // 1. Check for middleware\n for (const filename of MIDDLEWARE_FILES) {\n const middlewarePath = join(projectRoot, filename);\n if (existsSync(middlewarePath)) {\n try {\n const source = await readFile(middlewarePath, 'utf-8');\n const cookies = extractCookieNames(source);\n if (cookies.length > 0) {\n config.hasAuth = true;\n config.cookieNames.push(...cookies);\n }\n } catch {\n // Middleware exists but can't be read — skip\n }\n }\n }\n\n // 2. Scan all collected sources for auth patterns\n const combinedSource = allSources.join('\\n');\n\n const authEndpoint = extractAuthCheckEndpoint(combinedSource);\n if (authEndpoint) {\n config.hasAuth = true;\n config.authCheckEndpoint = authEndpoint;\n }\n\n // Look for auth context patterns\n if (/useAuth|AuthProvider|AuthContext|SessionProvider/i.test(combinedSource)) {\n config.hasAuth = true;\n }\n\n // 3. Extract API base URL\n config.apiBaseUrl = extractApiBaseUrl(combinedSource);\n\n return config;\n}\n","import type { ExtractedEndpoint } from './types.js';\n\n/**\n * Extract the API base URL from an API client source file.\n * Looks for patterns like:\n * baseURL: 'http://localhost:8000'\n * process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api'\n * const API_BASE_URL = 'http://...'\n */\nexport function extractBaseUrl(source: string): string | null {\n // Pattern: process.env.SOMETHING || 'default_url'\n const envFallback = source.match(\n /process\\.env\\.\\w+\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/,\n );\n if (envFallback) return envFallback[1];\n\n // Pattern: baseURL: 'http://...'\n const baseUrlProp = source.match(/baseURL\\s*:\\s*['\"]([^'\"]+)['\"]/);\n if (baseUrlProp) return baseUrlProp[1];\n\n // Pattern: const API_BASE_URL = 'http://...' (or similar names)\n const constAssign = source.match(\n /(?:API_BASE_URL|API_URL|BASE_URL)\\s*=\\s*['\"]([^'\"]+)['\"]/,\n );\n if (constAssign) return constAssign[1];\n\n return null;\n}\n\n/**\n * Extract HTTP endpoint definitions from an API client source file.\n *\n * Recognises patterns like:\n * api.get('/path')\n * axios.post('/path', data)\n * api.delete(`/items/${id}`)\n * fetch('/api/items')\n */\nexport function extractEndpoints(apiClientSource: string): ExtractedEndpoint[] {\n const endpoints: ExtractedEndpoint[] = [];\n const seen = new Set<string>();\n\n const lines = apiClientSource.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Pattern 1: something.get|post|put|delete|patch('/path...')\n // Matches both regular strings and template literals\n const methodCallRegex =\n /\\.\\s*(get|post|put|delete|patch)\\s*\\(\\s*(?:['\"`])([^'\"`$]*)/gi;\n let match: RegExpExecArray | null;\n while ((match = methodCallRegex.exec(line)) !== null) {\n const method = match[1].toUpperCase();\n let path = match[2];\n\n // Clean up path — remove trailing quote chars if any\n path = path.replace(/['\"`)]+$/, '').trim();\n if (!path || path.length === 0) continue;\n\n const key = `${method} ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method, path };\n\n // Try to find a function name from nearby context\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n\n // Pattern 2: fetch('/path') — default GET\n const fetchRegex = /\\bfetch\\s*\\(\\s*['\"`]([^'\"`$]+)/g;\n while ((match = fetchRegex.exec(line)) !== null) {\n const path = match[1].replace(/['\"`)]+$/, '').trim();\n if (!path || path.length === 0) continue;\n\n const key = `GET ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method: 'GET', path };\n\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n\n // Pattern 3: template literal — e.g. api.get(`/items/${id}`)\n // Extract the static prefix before the first ${\n const templateRegex =\n /\\.\\s*(get|post|put|delete|patch)\\s*\\(\\s*`([^`]*?)\\$\\{/gi;\n while ((match = templateRegex.exec(line)) !== null) {\n const method = match[1].toUpperCase();\n const path = match[2].trim();\n if (!path || path.length === 0) continue;\n\n const key = `${method} ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method, path };\n\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n }\n\n return endpoints;\n}\n\n/**\n * Look backwards from the current line to find a function/method name.\n * Matches patterns like:\n * getAll: () =>\n * async function getAll()\n * getAll() {\n */\nfunction findFunctionName(lines: string[], lineIndex: number): string | undefined {\n // Check current line and up to 3 lines above\n for (let i = lineIndex; i >= Math.max(0, lineIndex - 3); i--) {\n const line = lines[i];\n\n // Pattern: export const name = (args) => or const name = (args) =>\n const constArrow = line.match(/(?:export\\s+)?(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:\\([^)]*\\)\\s*=>|\\([^)]*\\)\\s*:\\s*\\w[^=]*=>)/);\n if (constArrow) return constArrow[1];\n\n // Pattern: propertyName: (args) => or propertyName: function\n const propMatch = line.match(/(\\w+)\\s*:\\s*(?:\\([^)]*\\)\\s*=>|function\\b)/);\n if (propMatch) return propMatch[1];\n\n // Pattern: async function name() or function name()\n const fnMatch = line.match(/(?:async\\s+)?function\\s+(\\w+)/);\n if (fnMatch) return fnMatch[1];\n\n // Pattern: name(args) { (method shorthand)\n const methodMatch = line.match(/^\\s*(\\w+)\\s*\\([^)]*\\)\\s*\\{/);\n if (methodMatch) return methodMatch[1];\n }\n\n return undefined;\n}\n","import Anthropic from '@anthropic-ai/sdk';\n\nexport interface LlmResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Simple LLM client wrapper for Anthropic Claude API.\n */\nexport class LlmClient {\n private client: Anthropic;\n private model: string;\n\n constructor(apiKey: string, model: string = 'claude-sonnet-4-20250514') {\n this.client = new Anthropic({ apiKey });\n this.model = model;\n }\n\n async generate(systemPrompt: string, userPrompt: string): Promise<LlmResponse> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n });\n\n const textBlock = response.content.find(block => block.type === 'text');\n const content = textBlock ? textBlock.text : '';\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n }\n}\n","import type { PageAnalysis } from '../analysis/types.js';\n\nexport const SYSTEM_PROMPT = `You are a mock data generator for a UI pre-rendering tool called Code to Design.\nYour job is to analyze a Next.js page's source code and generate realistic mock API responses that will make the page render correctly in different visual states.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces and API response shapes found in the source code.\n3. Generate contextually appropriate data (e.g., real company names for a finance app, realistic usernames for a social app).\n4. Generate MULTIPLE items in success data (at least 3-5 items for list endpoints).\n5. If actual API endpoint URLs are provided, use those EXACT paths in your response.\n6. Analyze the page's conditional rendering (if/else, ternary, switch, state variables) to identify meaningful visual states — not just generic success/error.\n7. Include auth mock data if the page requires authentication.\n8. For dynamic route parameters, generate a realistic sample value.`;\n\n/**\n * Build the user prompt for mock generation from a PageAnalysis.\n */\nexport function buildUserPrompt(analysis: PageAnalysis): string {\n const parts: string[] = [];\n\n parts.push(`## Page Route: ${analysis.route.urlPath}`);\n parts.push(`## Page File: ${analysis.route.filePath}`);\n\n if (analysis.route.isDynamic) {\n parts.push(`## Dynamic Parameters: ${analysis.route.params.map(p => p.name).join(', ')}`);\n }\n\n // Include extracted endpoints if available\n if (analysis.extractedEndpoints.length > 0) {\n parts.push('## Actual API Endpoints (use these EXACT paths)');\n for (const ep of analysis.extractedEndpoints) {\n const name = ep.functionName ? ` (${ep.functionName})` : '';\n parts.push(`- ${ep.method} ${ep.path}${name}`);\n }\n if (analysis.apiBaseUrl) {\n parts.push(`- Base URL: ${analysis.apiBaseUrl}`);\n }\n }\n\n parts.push('## Source Code Context');\n parts.push(analysis.sourceContext);\n\n if (analysis.authConfig.hasAuth) {\n parts.push('## Auth Configuration');\n parts.push(`- Requires authentication: yes`);\n if (analysis.authConfig.cookieNames.length > 0) {\n parts.push(`- Auth cookies: ${analysis.authConfig.cookieNames.join(', ')}`);\n }\n if (analysis.authConfig.authCheckEndpoint) {\n parts.push(`- Auth check endpoint: ${analysis.authConfig.authCheckEndpoint}`);\n }\n if (analysis.authConfig.apiBaseUrl) {\n parts.push(`- API base URL: ${analysis.authConfig.apiBaseUrl}`);\n }\n }\n\n parts.push(`\n## Required Output Format\n\nAnalyze the page code carefully. Look at:\n- Conditional rendering (if/else, ternary operators, switch statements)\n- State variables that control what is displayed\n- URL parameters or search params that affect the view\n- Authentication state checks\n- Data loading patterns\n\nThen generate mock data for **page-specific visual states** — not just generic success/error. For example:\n- A dashboard with tabs might have states: \"overview_tab\", \"readings_tab\", \"settings_tab\"\n- A page checking auth might have: \"authenticated_with_data\", \"authenticated_empty\", \"unauthenticated\"\n- A results page might have: \"results_found\", \"no_results\", \"invalid_id\"\n\nAlways include at least these base states:\n- One state with realistic populated data (the \"happy path\")\n- One state with empty/no data\n- One error state (API returns 500)\n\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" },\n \"stateVariants\": [\n {\n \"name\": \"descriptive_state_name\",\n \"description\": \"What this state represents visually\",\n \"apiMocks\": {\n \"METHOD /endpoint/path\": {\n \"status\": 200,\n \"body\": { ... },\n \"delay\": 0\n }\n }\n }\n ],\n \"authMock\": {\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nIMPORTANT:\n- Use the ACTUAL endpoint paths from the \"Actual API Endpoints\" section above if provided.\n- Each state variant should produce a VISUALLY DIFFERENT page render.\n- Generate at least 3-5 items in list/array responses for the happy path state.\n- Generate ONLY the JSON. No explanation, no markdown fences.`);\n\n return parts.join('\\n\\n');\n}\n","import type { PageAnalysis } from '../analysis/types.js';\nimport type { MockConfig, MockResponse, MockGeneratorOptions } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\n/**\n * New format: LLM returns state variants with per-state API mocks.\n */\ninterface LlmMockOutputV2 {\n routeParams?: Record<string, string>;\n stateVariants?: Array<{\n name: string;\n description?: string;\n apiMocks: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\n/**\n * Legacy format: per-endpoint states.\n */\ninterface LlmMockOutputV1 {\n routeParams?: Record<string, string>;\n apiEndpoints?: Array<{\n urlPattern: string;\n method: string;\n states: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\ntype LlmMockOutput = LlmMockOutputV2 | LlmMockOutputV1;\n\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n let cleaned = content.trim();\n if (cleaned.startsWith('```')) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, '').replace(/\\n?```$/, '');\n }\n\n try {\n return JSON.parse(cleaned);\n } catch {\n const jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n }\n}\n\n/**\n * Check if output uses the new V2 format (stateVariants).\n */\nfunction isV2Output(output: LlmMockOutput): output is LlmMockOutputV2 {\n return 'stateVariants' in output && Array.isArray((output as LlmMockOutputV2).stateVariants);\n}\n\n/**\n * Convert V2 (stateVariants) output to MockConfig[].\n */\nfunction convertV2ToMockConfigs(\n output: LlmMockOutputV2,\n analysis: PageAnalysis,\n): MockConfig[] {\n if (!output.stateVariants || output.stateVariants.length === 0) {\n return [];\n }\n\n return output.stateVariants.map(variant => {\n const apiMocks: Record<string, MockResponse> = {};\n for (const [pattern, mock] of Object.entries(variant.apiMocks)) {\n apiMocks[pattern] = {\n status: mock.status,\n body: mock.body,\n delay: mock.delay,\n };\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n return {\n stateName: variant.name,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n };\n });\n}\n\n/**\n * Convert V1 (per-endpoint states) output to MockConfig[].\n * Legacy format support.\n */\nfunction convertV1ToMockConfigs(\n output: LlmMockOutputV1,\n analysis: PageAnalysis,\n variants: string[],\n): MockConfig[] {\n const configs: MockConfig[] = [];\n\n for (const variant of variants) {\n const apiMocks: Record<string, MockResponse> = {};\n\n if (output.apiEndpoints) {\n for (const endpoint of output.apiEndpoints) {\n const stateData = endpoint.states[variant];\n if (stateData) {\n const key = `${endpoint.method} ${endpoint.urlPattern}`;\n apiMocks[key] = {\n status: stateData.status,\n body: stateData.body,\n delay: stateData.delay,\n };\n }\n }\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n configs.push({\n stateName: variant,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n });\n }\n\n return configs;\n}\n\n/**\n * Generate a fallback MockConfig when LLM fails or page has no API deps.\n */\nfunction generateFallbackConfigs(\n analysis: PageAnalysis,\n variants: string[],\n): MockConfig[] {\n return variants.map(variant => ({\n stateName: variant,\n apiMocks: {},\n authMock: analysis.authConfig.hasAuth\n ? {\n cookies: Object.fromEntries(\n analysis.authConfig.cookieNames.map(name => [name, 'mock_token_c2d']),\n ),\n authCheckResponse: variant === 'error'\n ? { status: 401, body: { detail: 'Unauthorized' } }\n : { status: 200, body: { id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User' } },\n }\n : null,\n routeParams: analysis.route.isDynamic\n ? Object.fromEntries(analysis.route.params.map(p => [p.name, 'sample-1']))\n : undefined,\n }));\n}\n\n/**\n * Generate mock data for a single page using an LLM.\n *\n * Returns one MockConfig per state variant (page-specific or fallback).\n */\nexport async function generateMocks(\n analysis: PageAnalysis,\n options: MockGeneratorOptions,\n): Promise<{ configs: MockConfig[]; tokenUsage: { input: number; output: number } }> {\n const variants = options.variants ?? ['success', 'empty', 'error', 'loading'];\n\n // If no API dependencies, just return fallback configs (no LLM call needed)\n if (!analysis.hasApiDependencies) {\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n\n const client = new LlmClient(options.apiKey, options.model);\n const userPrompt = buildUserPrompt(analysis);\n\n try {\n const response = await client.generate(SYSTEM_PROMPT, userPrompt);\n const parsed = parseLlmJson(response.content);\n\n if (!parsed) {\n console.warn(`[c2d] Failed to parse LLM response for ${analysis.route.urlPath}, using fallback`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n }\n\n let configs: MockConfig[];\n\n if (isV2Output(parsed)) {\n // New format: page-specific state variants\n configs = convertV2ToMockConfigs(parsed, analysis);\n } else {\n // Legacy format: per-endpoint states\n configs = convertV1ToMockConfigs(parsed, analysis, variants);\n }\n\n // Ensure we have at least one config\n if (configs.length === 0) {\n configs = generateFallbackConfigs(analysis, variants);\n }\n\n return {\n configs,\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n } catch (error) {\n console.warn(`[c2d] LLM call failed for ${analysis.route.urlPath}: ${error}`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n}\n\n/**\n * Generate mocks for all analyzed pages.\n */\nexport async function generateAllMocks(\n analyses: PageAnalysis[],\n options: MockGeneratorOptions,\n): Promise<{\n results: Map<string, MockConfig[]>;\n totalTokens: { input: number; output: number };\n}> {\n const results = new Map<string, MockConfig[]>();\n const totalTokens = { input: 0, output: 0 };\n\n for (const analysis of analyses) {\n const { configs, tokenUsage } = await generateMocks(analysis, options);\n results.set(analysis.route.urlPath, configs);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n }\n\n return { results, totalTokens };\n}\n","import { chromium, type Browser, type BrowserContext, type Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { MockConfig, MockResponse } from '../mock/types.js';\nimport type { AuthConfig } from '../analysis/types.js';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type {\n RenderResult,\n RenderTask,\n RenderManifest,\n ManifestRoute,\n PreRenderOptions,\n ViewportConfig,\n} from './types.js';\nimport { startDevServer, type DevServerHandle } from './dev-server.js';\nimport { inlineStylesAndCleanup } from './style-inliner.js';\nimport { captureInteractions, type InteractionResult } from './interaction-capturer.js';\nimport { matchMockUrl, isApiUrl } from './url-matcher.js';\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_PAGE_TIMEOUT = 15000;\nconst DEFAULT_SETTLE_TIME = 1500;\nconst DEFAULT_VIEWPORT = { width: 1440, height: 900 };\n\n/**\n * Build the actual URL path for a route, substituting dynamic params.\n */\nfunction buildUrlPath(route: RouteInfo, mockConfig: MockConfig): string {\n let path = route.urlPath;\n if (route.isDynamic && mockConfig.routeParams) {\n for (const param of route.params) {\n const value = mockConfig.routeParams[param.name] || 'sample-1';\n path = path.replace(`:${param.name}`, value);\n // Also handle catch-all notation\n path = path.replace(`:${param.name}+`, value);\n path = path.replace(`:${param.name}*`, value);\n }\n }\n return path;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n * \"/\" → \"index\", \"/dashboard\" → \"dashboard\", \"/editor/:id\" → \"editor-_id\"\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Set up Playwright route interception for a page with the given mock config.\n */\nasync function setupMockInterception(\n page: Page,\n devServerUrl: string,\n mockConfig: MockConfig,\n authConfig: AuthConfig,\n): Promise<void> {\n // 1. Inject auth cookies if needed\n if (mockConfig.authMock) {\n const cookies = Object.entries(mockConfig.authMock.cookies).map(([name, value]) => ({\n name,\n value,\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n } else if (authConfig.hasAuth && authConfig.cookieNames.length > 0) {\n // Fallback: inject dummy cookies for detected auth\n const cookies = authConfig.cookieNames.map(name => ({\n name,\n value: 'c2d_mock_token',\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n }\n\n // 2. Inject localStorage for client-side auth (Zustand persist, etc.)\n // Only inject if source code contains zustand persist or localStorage auth patterns\n const sourceHasLocalStorageAuth = /persist\\s*\\(|localStorage|auth-storage|useAuthStore/i.test(\n mockConfig.apiMocks ? JSON.stringify(mockConfig) : ''\n );\n const contextHasZustand = /zustand|persist.*auth|auth-storage|useAuthStore/i.test(authConfig.apiBaseUrl ?? '');\n\n // Check the actual source context from the page analysis if available\n // For now, detect by checking if authConfig has no cookie-based auth (suggesting client-side auth)\n const usesClientSideAuth = authConfig.hasAuth && authConfig.cookieNames.length === 0;\n\n if (usesClientSideAuth) {\n const mockUser = JSON.stringify(mockConfig.authMock?.authCheckResponse?.body ?? {\n id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User',\n });\n const mockToken = 'c2d_mock_jwt_token';\n\n await page.addInitScript(`\n try {\n var zustandState = {\n state: {\n user: ${mockUser},\n tokens: { access: \"${mockToken}\", refresh: \"${mockToken}\" },\n isAuthenticated: true,\n isLoading: false,\n },\n version: 0,\n };\n localStorage.setItem('auth-storage', JSON.stringify(zustandState));\n localStorage.setItem('token', '\"${mockToken}\"');\n localStorage.setItem('access_token', '\"${mockToken}\"');\n } catch(e) {}\n `);\n }\n\n // 3. Build auth mock response for interception\n const authMockBody = mockConfig.authMock?.authCheckResponse\n ? JSON.stringify(mockConfig.authMock.authCheckResponse.body)\n : JSON.stringify({ id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User', email_verified: true, avatar_url: null, created_at: '2026-01-01T00:00:00Z' });\n\n // Common auth check URL patterns to always intercept\n const AUTH_PATTERNS = ['/auth/me', '/auth/session', '/api/auth/me', '/api/user/me', '/api/auth/session'];\n\n // 3. Intercept API calls\n await page.route('**/*', async (route) => {\n const request = route.request();\n const url = request.url();\n const method = request.method();\n\n // Always intercept auth check endpoints (common patterns + detected endpoint)\n const isAuthCheck = AUTH_PATTERNS.some(p => url.includes(p))\n || (authConfig.authCheckEndpoint && url.includes(authConfig.authCheckEndpoint));\n\n if (isAuthCheck) {\n const status = mockConfig.authMock?.authCheckResponse?.status ?? 200;\n return route.fulfill({\n status,\n contentType: 'application/json',\n body: authMockBody,\n });\n }\n\n // Check API mocks from AI-generated config\n for (const [pattern, mock] of Object.entries(mockConfig.apiMocks)) {\n if (matchMockUrl(url, method, pattern)) {\n if (mock.delay) await new Promise(r => setTimeout(r, mock.delay));\n return route.fulfill({\n status: mock.status,\n contentType: 'application/json',\n body: JSON.stringify(mock.body),\n });\n }\n }\n\n // If this looks like an API call (contains /api/ or goes to a known backend port),\n // return an empty success response instead of letting it fail against a non-existent backend\n if (isApiUrl(url)) {\n return route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ data: [], message: 'ok' }),\n });\n }\n\n // Pass through all other requests (static assets, etc.)\n return route.continue();\n });\n}\n\n/**\n * Render a single page in a specific state and capture HTML + screenshot.\n */\nasync function renderPage(\n context: BrowserContext,\n devServerUrl: string,\n task: RenderTask,\n outputDir: string,\n options: { pageTimeout: number; settleTime: number; captureInteractionStates?: boolean; maxInteractions?: number },\n viewport?: ViewportConfig,\n): Promise<RenderResult> {\n const { route, mockConfig, authConfig } = task;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Include viewport name in file paths to avoid collisions when rendering multiple viewports\n const filePrefix = viewport ? `${mockConfig.stateName}_${viewport.name}` : mockConfig.stateName;\n const htmlRelPath = join('renders', routeSlug, `${filePrefix}.html`);\n const pngRelPath = join('renders', routeSlug, `${filePrefix}.png`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n const pngAbsPath = join(outputDir, pngRelPath);\n\n const page = await context.newPage();\n\n // Override viewport size for this page if a specific viewport was requested\n if (viewport) {\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n }\n\n try {\n await setupMockInterception(page, devServerUrl, mockConfig, authConfig);\n\n const urlPath = buildUrlPath(route, mockConfig);\n const fullUrl = `${devServerUrl}${urlPath}`;\n\n await page.goto(fullUrl, {\n waitUntil: 'networkidle',\n timeout: options.pageTimeout,\n });\n\n // Extra settle time for React hydration\n await page.waitForTimeout(options.settleTime);\n\n // Inline all external stylesheets so HTML is self-contained\n await inlineStylesAndCleanup(page);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n // Capture screenshot\n await page.screenshot({ path: pngAbsPath, fullPage: true });\n\n // Capture interaction variants (only for success/empty states, not error/loading)\n const interactionStates = ['success', 'empty'];\n const shouldCapture = options.captureInteractionStates !== false\n && interactionStates.includes(mockConfig.stateName);\n\n let interactions: Array<{ description: string; htmlPath: string }> | undefined;\n\n if (shouldCapture) {\n // Reload before interaction capture to get a clean page with scripts intact\n await page.goto(fullUrl, { waitUntil: 'networkidle', timeout: options.pageTimeout });\n await page.waitForTimeout(options.settleTime);\n\n const interactionResults = await captureInteractions(\n page,\n fullUrl,\n route,\n mockConfig.stateName,\n outputDir,\n { maxInteractions: options.maxInteractions, settleTime: 500 },\n );\n\n const successful = interactionResults.filter(r => r.success);\n if (successful.length > 0) {\n interactions = successful.map(r => ({\n description: r.elementDescription,\n htmlPath: r.htmlPath,\n }));\n }\n }\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\n interactions,\n };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n // Write an error placeholder HTML\n const errorHtml = `<!DOCTYPE html><html><body style=\"display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;color:#666;\">\n <div style=\"text-align:center\"><h2>Render Failed</h2><p>${route.urlPath} [${mockConfig.stateName}]</p><pre style=\"color:#c00\">${errorMsg}</pre></div>\n </body></html>`;\n await writeFile(htmlAbsPath, errorHtml, 'utf-8').catch(() => {});\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: false,\n error: errorMsg,\n viewportName: viewport?.name,\n };\n } finally {\n await page.close();\n }\n}\n\n/**\n * Process render tasks with limited concurrency.\n */\nasync function processWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<RenderResult>,\n onProgress?: (completed: number, total: number, result: RenderResult) => void,\n): Promise<RenderResult[]> {\n const results: RenderResult[] = [];\n const queue = [...items];\n const total = items.length;\n let completed = 0;\n\n async function worker() {\n while (queue.length > 0) {\n const item = queue.shift()!;\n const result = await fn(item);\n results.push(result);\n completed++;\n onProgress?.(completed, total, result);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * Build the render manifest from results.\n */\nfunction buildManifest(\n results: RenderResult[],\n projectName: string,\n viewports?: ViewportConfig[],\n): RenderManifest {\n const routeMap = new Map<string, ManifestRoute>();\n\n // Build a lookup for viewport widths by name\n const viewportWidthMap = new Map<string, number>();\n if (viewports) {\n for (const vp of viewports) {\n viewportWidthMap.set(vp.name, vp.width);\n }\n }\n\n for (const result of results) {\n const key = result.route.urlPath;\n if (!routeMap.has(key)) {\n routeMap.set(key, {\n urlPath: result.route.urlPath,\n filePath: result.route.filePath,\n states: [],\n });\n }\n routeMap.get(key)!.states.push({\n name: result.viewportName\n ? `${result.stateName} (${result.viewportName})`\n : result.stateName,\n htmlPath: result.htmlPath,\n screenshotPath: result.screenshotPath,\n status: result.success ? 'ok' : 'error',\n error: result.error,\n viewport: result.viewportName,\n viewportWidth: result.viewportName\n ? viewportWidthMap.get(result.viewportName)\n : undefined,\n interactions: result.interactions,\n });\n }\n\n return {\n generatedAt: new Date().toISOString(),\n projectName,\n routes: [...routeMap.values()].sort((a, b) => a.urlPath.localeCompare(b.urlPath)),\n };\n}\n\n/**\n * Pre-render all pages with their mock configurations.\n *\n * This is the main entry point for the rendering pipeline:\n * 1. Start dev server (or use provided URL)\n * 2. Launch Playwright browser\n * 3. For each (route, state) pair: intercept APIs, navigate, capture\n * 4. Write manifest.json\n * 5. Clean up\n */\nexport async function preRenderPages(\n tasks: RenderTask[],\n options: PreRenderOptions,\n): Promise<{ results: RenderResult[]; manifest: RenderManifest }> {\n const {\n projectRoot,\n outputDir = join(projectRoot, '.c2d'),\n concurrency = DEFAULT_CONCURRENCY,\n pageTimeout = DEFAULT_PAGE_TIMEOUT,\n settleTime = DEFAULT_SETTLE_TIME,\n viewportWidth = DEFAULT_VIEWPORT.width,\n viewportHeight = DEFAULT_VIEWPORT.height,\n captureInteractions: captureInteractionStates = true,\n maxInteractions,\n } = options;\n\n // Resolve viewports: if explicit viewports array is provided use it,\n // otherwise fall back to the single viewport from viewportWidth/Height\n // (which themselves default to 1440x900).\n const viewports: ViewportConfig[] | undefined = options.viewports;\n const useMultiViewport = viewports && viewports.length > 0;\n\n // Create output directory\n await mkdir(outputDir, { recursive: true });\n\n // Start dev server\n let devServer: DevServerHandle | null = null;\n try {\n devServer = await startDevServer(projectRoot, {\n port: options.devServerPort,\n devServerUrl: options.devServerUrl,\n });\n\n // Launch browser\n const browser = await chromium.launch({ headless: true });\n const context = await browser.newContext({\n viewport: { width: viewportWidth, height: viewportHeight },\n });\n\n try {\n let results: RenderResult[];\n\n if (useMultiViewport) {\n // Expand tasks: each original task is rendered at each viewport\n const expandedItems: Array<{ task: RenderTask; viewport: ViewportConfig }> = [];\n for (const task of tasks) {\n for (const vp of viewports) {\n expandedItems.push({ task, viewport: vp });\n }\n }\n\n results = await processWithConcurrency(\n expandedItems,\n concurrency,\n ({ task, viewport: vp }) =>\n renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime, captureInteractionStates, maxInteractions }, vp),\n options.onProgress,\n );\n } else {\n // Single viewport — backward-compatible path (no viewportName in results)\n results = await processWithConcurrency(\n tasks,\n concurrency,\n (task) => renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime, captureInteractionStates, maxInteractions }),\n options.onProgress,\n );\n }\n\n // Read project name from package.json\n let projectName = 'unknown';\n try {\n const pkg = await import(join(projectRoot, 'package.json'), { with: { type: 'json' } });\n projectName = pkg.default?.name || 'unknown';\n } catch {\n // Can't read package.json — use fallback\n }\n\n // Build and write manifest\n const manifest = buildManifest(\n results,\n projectName,\n useMultiViewport ? viewports : undefined,\n );\n await writeFile(\n join(outputDir, 'manifest.json'),\n JSON.stringify(manifest, null, 2),\n 'utf-8',\n );\n\n return { results, manifest };\n } finally {\n await context.close();\n await browser.close();\n }\n } finally {\n if (devServer) {\n await devServer.stop();\n }\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createServer } from 'node:net';\n\n/**\n * Find a free port on the system.\n */\nexport async function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.listen(0, () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not find free port')));\n }\n });\n server.on('error', reject);\n });\n}\n\n/**\n * Wait for a URL to become reachable.\n */\nasync function waitForUrl(url: string, timeoutMs: number = 30000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(2000) });\n // Any response (even redirects) means the server is up\n if (response.status > 0) return;\n } catch {\n // Server not ready yet\n }\n await new Promise(r => setTimeout(r, 500));\n }\n throw new Error(`Dev server did not become ready at ${url} within ${timeoutMs}ms`);\n}\n\n/**\n * Detect the dev command for a project.\n */\nfunction detectDevCommand(projectRoot: string): { cmd: string; args: string[] } {\n if (existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'))) {\n return { cmd: 'npx', args: ['next', 'dev'] };\n }\n // Fallback to npm run dev\n return { cmd: 'npm', args: ['run', 'dev'] };\n}\n\nexport interface DevServerHandle {\n url: string;\n port: number;\n process: ChildProcess | null;\n stop: () => Promise<void>;\n}\n\n/**\n * Start a dev server for the target project.\n *\n * If devServerUrl is provided, uses that instead of starting a new server.\n */\nexport async function startDevServer(\n projectRoot: string,\n options?: { port?: number; devServerUrl?: string },\n): Promise<DevServerHandle> {\n // If a URL is provided, use it directly (user has server running)\n if (options?.devServerUrl) {\n await waitForUrl(options.devServerUrl, 10000);\n return {\n url: options.devServerUrl,\n port: 0,\n process: null,\n stop: async () => {},\n };\n }\n\n const port = options?.port ?? await findFreePort();\n const { cmd, args } = detectDevCommand(projectRoot);\n const fullArgs = [...args, '--port', String(port)];\n\n const child = spawn(cmd, fullArgs, {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, PORT: String(port) },\n });\n\n const url = `http://localhost:${port}`;\n\n // Collect stderr for error reporting\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n // Handle early exit\n const exitPromise = new Promise<never>((_, reject) => {\n child.on('exit', (code) => {\n if (code !== null && code !== 0) {\n reject(new Error(`Dev server exited with code ${code}.\\n${stderr.slice(-500)}`));\n }\n });\n });\n\n // Wait for server to be ready or fail\n try {\n await Promise.race([\n waitForUrl(url, 60000),\n exitPromise,\n ]);\n } catch (err) {\n child.kill('SIGTERM');\n throw err;\n }\n\n return {\n url,\n port,\n process: child,\n stop: async () => {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n resolve();\n }, 5000);\n child.on('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n },\n };\n}\n","import type { Page } from 'playwright';\n\n/**\n * Inline all external stylesheets into <style> tags and remove <script> tags.\n *\n * This makes the captured HTML self-contained so it can be displayed\n * outside the dev server context. Shared by both the main render pipeline\n * and the interaction capturer.\n */\nexport async function inlineStylesAndCleanup(page: Page): Promise<void> {\n await page.evaluate(`(() => {\n const links = document.querySelectorAll('link[rel=\"stylesheet\"]');\n links.forEach(link => {\n try {\n const href = link.getAttribute('href');\n if (!href) return;\n for (const sheet of document.styleSheets) {\n if (sheet.href && sheet.href.includes(href.replace(/^\\\\//, ''))) {\n const rules = Array.from(sheet.cssRules).map(r => r.cssText).join('\\\\n');\n const style = document.createElement('style');\n style.textContent = rules;\n link.parentNode.replaceChild(style, link);\n break;\n }\n }\n } catch (e) {}\n });\n document.querySelectorAll('script').forEach(s => s.remove());\n })()`);\n}\n","import type { Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { RouteInfo } from '../discovery/types.js';\nimport { inlineStylesAndCleanup } from './style-inliner.js';\n\n/**\n * Result of capturing a single interaction variant.\n */\nexport interface InteractionResult {\n /** Human-readable description, e.g. \"Tab: Settings\", \"Button: Open Modal\" */\n elementDescription: string;\n /** Relative path to captured HTML file */\n htmlPath: string;\n /** Whether the interaction capture succeeded */\n success: boolean;\n /** Error message if capture failed */\n error?: string;\n}\n\n/**\n * Serializable info about a clickable element found on the page.\n */\ninterface ClickableElement {\n /** CSS selector path to re-find the element */\n selector: string;\n /** Human-readable description */\n description: string;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Find clickable interactive elements on the current page.\n *\n * Looks for tabs, buttons, and anchor-like elements, excluding\n * already-active, disabled, submit, and external link elements.\n * Uses a string-based evaluate to avoid DOM type issues in Node context.\n */\nasync function findClickableElements(\n page: Page,\n maxElements: number,\n): Promise<ClickableElement[]> {\n return page.evaluate(`((max) => {\n const selectors = [\n '[role=\"tab\"]:not([aria-selected=\"true\"]):not([aria-disabled=\"true\"])',\n '[role=\"button\"]:not([aria-disabled=\"true\"]):not([disabled])',\n 'button:not([disabled]):not([type=\"submit\"])',\n '[data-tab]:not(.active):not(.selected)',\n '.tab:not(.active):not(.selected)',\n 'a[href=\"#\"]:not(.active)',\n 'a[href^=\"#\"]:not([href=\"#\"]):not(.active)',\n ];\n\n const seen = new Set();\n const results = [];\n\n for (const sel of selectors) {\n if (results.length >= max) break;\n const elements = document.querySelectorAll(sel);\n\n for (const el of elements) {\n if (results.length >= max) break;\n if (seen.has(el)) continue;\n seen.add(el);\n\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) continue;\n const style = window.getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden') continue;\n\n if (el.tagName === 'A') {\n const href = el.getAttribute('href') || '';\n if (href.startsWith('http') || href.startsWith('//')) continue;\n }\n\n if (el.tagName === 'BUTTON' && el.type === 'submit') continue;\n\n const text = (el.textContent || '').trim().slice(0, 50);\n const ariaLabel = el.getAttribute('aria-label');\n const role = el.getAttribute('role');\n const tag = el.tagName.toLowerCase();\n\n let desc = '';\n if (role === 'tab') desc = 'Tab: ' + (ariaLabel || text || 'unnamed');\n else if (role === 'button') desc = 'Button: ' + (ariaLabel || text || 'unnamed');\n else if (tag === 'button') desc = 'Button: ' + (ariaLabel || text || 'unnamed');\n else desc = 'Clickable: ' + (ariaLabel || text || 'unnamed');\n\n let uniqueSelector = '';\n const id = el.getAttribute('id');\n if (id) {\n uniqueSelector = '#' + CSS.escape(id);\n } else {\n const dataTestId = el.getAttribute('data-testid');\n if (dataTestId) {\n uniqueSelector = '[data-testid=\"' + CSS.escape(dataTestId) + '\"]';\n } else {\n const allMatching = document.querySelectorAll(sel);\n const idx = Array.from(allMatching).indexOf(el);\n uniqueSelector = '__INDEX__' + sel + '__' + idx;\n }\n }\n\n results.push({ selector: uniqueSelector, description: desc });\n }\n }\n\n return results;\n })(${maxElements})`) as Promise<ClickableElement[]>;\n}\n\n/**\n * Capture interaction variants by clicking interactive elements on a rendered page.\n *\n * This function expects the page to already be rendered and navigated to the target URL.\n * It finds clickable elements, clicks each one, captures the resulting HTML,\n * then reloads the page to reset state before the next interaction.\n *\n * @param page - Already rendered Playwright page\n * @param pageUrl - The full URL to reload between interactions\n * @param route - Route info for file naming\n * @param stateName - State variant name (e.g. \"success\")\n * @param outputDir - Base output directory\n * @param options - Configuration options\n * @returns Array of interaction results\n */\nexport async function captureInteractions(\n page: Page,\n pageUrl: string,\n route: RouteInfo,\n stateName: string,\n outputDir: string,\n options?: { maxInteractions?: number; settleTime?: number },\n): Promise<InteractionResult[]> {\n const maxInteractions = options?.maxInteractions ?? 5;\n const settleTime = options?.settleTime ?? 500;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Find clickable elements\n const clickables = await findClickableElements(page, maxInteractions);\n if (clickables.length === 0) return [];\n\n const results: InteractionResult[] = [];\n\n for (let i = 0; i < clickables.length; i++) {\n const clickable = clickables[i];\n const htmlRelPath = join('renders', routeSlug, `${stateName}_interaction_${i}.html`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n\n try {\n // Re-find and click the element\n let clicked = false;\n\n if (clickable.selector.startsWith('__INDEX__')) {\n // Parse the fallback selector format: __INDEX__{selector}__{index}\n const parts = clickable.selector.slice('__INDEX__'.length);\n const lastUnderscoreIdx = parts.lastIndexOf('__');\n const sel = parts.slice(0, lastUnderscoreIdx);\n const idx = parseInt(parts.slice(lastUnderscoreIdx + 2), 10);\n\n const elements = await page.$$(sel);\n if (elements[idx]) {\n await elements[idx].click();\n clicked = true;\n }\n } else {\n const element = await page.$(clickable.selector);\n if (element) {\n await element.click();\n clicked = true;\n }\n }\n\n if (!clicked) {\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: false,\n error: 'Element not found on re-query',\n });\n continue;\n }\n\n // Wait for state change\n await page.waitForTimeout(settleTime);\n\n // Inline styles and clean up (same as main render pipeline)\n await inlineStylesAndCleanup(page);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: true,\n });\n } catch (err) {\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Reset page state for next interaction by reloading\n try {\n await page.goto(pageUrl, { waitUntil: 'networkidle', timeout: 10000 });\n await page.waitForTimeout(settleTime);\n } catch {\n // If reload fails, remaining interactions will likely fail too\n break;\n }\n }\n\n return results;\n}\n","/**\n * Smart URL matching for API mock interception.\n *\n * Supports:\n * - Full path matching (exact after normalization)\n * - Suffix matching (mock \"/readings\" matches url \"/api/v1/readings\")\n * - Trailing slash normalization\n * - Param placeholders: {id}, :id, and * wildcards\n */\n\n/**\n * Check whether a request URL + method matches a mock pattern string.\n *\n * @param requestUrl - The full URL from the intercepted request (e.g. \"http://localhost:8000/api/v1/readings/\")\n * @param requestMethod - HTTP method of the request (e.g. \"GET\")\n * @param mockPattern - Pattern from the mock config (e.g. \"GET /readings\" or \"DELETE /readings/{id}\")\n * @returns true if the request matches the mock pattern\n */\nexport function matchMockUrl(requestUrl: string, requestMethod: string, mockPattern: string): boolean {\n const [mockMethod, ...pathParts] = mockPattern.split(' ');\n if (requestMethod !== mockMethod) return false;\n\n let mockPath = pathParts.join(' ');\n\n // Normalize: strip trailing slashes for comparison\n mockPath = mockPath.replace(/\\/+$/, '');\n const urlPath = new URL(requestUrl).pathname.replace(/\\/+$/, '');\n\n // Convert param placeholders to regex segments\n const regexStr = mockPath\n .replace(/\\{[^}]+\\}/g, '[^/]+')\n .replace(/\\*/g, '[^/]+')\n .replace(/:[a-zA-Z_]+/g, '[^/]+');\n\n // Strategy 1: Full path match\n const fullRegex = new RegExp('^' + regexStr.replace(/\\//g, '\\\\/') + '$');\n if (fullRegex.test(urlPath)) return true;\n\n // Strategy 2: Suffix match (last N segments)\n // e.g., mock \"/readings\" matches url \"/api/v1/readings\"\n const mockSegments = mockPath.split('/').filter(Boolean);\n const urlSegments = urlPath.split('/').filter(Boolean);\n\n if (mockSegments.length >= 1 && urlSegments.length >= mockSegments.length) {\n const urlSuffix = urlSegments.slice(-mockSegments.length);\n const match = mockSegments.every((seg, i) => {\n if (seg.startsWith('{') || seg.startsWith(':') || seg === '*') return true;\n return seg === urlSuffix[i];\n });\n if (match) return true;\n }\n\n return false;\n}\n\n/**\n * Check whether a URL looks like an API call that should be intercepted\n * even if no specific mock pattern matched.\n */\nexport function isApiUrl(url: string): boolean {\n // Exclude Next.js internal requests\n if (url.includes('/_next/') || url.includes('/__next') || url.includes('/favicon')) return false;\n // Only match explicit API paths, not port-based heuristics\n try {\n const parsed = new URL(url);\n return parsed.pathname.startsWith('/api/');\n } catch {\n return url.includes('/api/');\n }\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport sirv from 'sirv';\nimport { handleApiRequest } from './api-routes.js';\n\n/**\n * Options for starting the canvas server.\n */\nexport interface CanvasServerOptions {\n /** Port to listen on (default: 4800) */\n port: number;\n /** Path to the built canvas app directory */\n canvasDir: string;\n /** Path to the .c2d/ output directory */\n c2dDir: string;\n /** Path to the target project root (for serving public/ assets) */\n projectRoot?: string;\n}\n\nconst MAX_PORT_ATTEMPTS = 10;\n\n/**\n * Try to listen on a port. Returns a promise that resolves on success\n * or rejects with the error.\n */\nfunction tryListen(\n requestHandler: (req: IncomingMessage, res: ServerResponse) => void,\n port: number,\n): Promise<{ url: string; port: number; close: () => Promise<void> }> {\n return new Promise((resolve, reject) => {\n const server = createServer(requestHandler);\n server.once('error', reject);\n server.listen(port, () => {\n const actualPort = (server.address() as { port: number }).port;\n resolve({\n url: `http://localhost:${actualPort}`,\n port: actualPort,\n close: () =>\n new Promise<void>((resolveClose, rejectClose) => {\n server.close((err) => {\n if (err) rejectClose(err);\n else resolveClose();\n });\n }),\n });\n });\n });\n}\n\n/**\n * Start the canvas server that serves:\n * 1. API endpoints under /api/\n * 2. Pre-rendered files from .c2d/renders/ under /renders/\n * 3. Canvas app static assets (SPA fallback) for everything else\n *\n * If the default port is in use, tries up to 10 consecutive ports.\n */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir, projectRoot } = options;\n\n // Static file handlers\n const canvasHandler = sirv(canvasDir, { single: true, dev: true });\n const rendersDir = join(c2dDir, 'renders');\n const rendersHandler = sirv(rendersDir, { dev: true });\n\n // Serve target project's public/ folder for static assets (images, fonts, etc.)\n const publicDir = projectRoot ? join(projectRoot, 'public') : null;\n const publicHandler = publicDir && existsSync(publicDir)\n ? sirv(publicDir, { dev: true })\n : null;\n\n // Request handler\n const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n // CORS headers on all responses\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n // API routes\n if (url.startsWith('/api/')) {\n try {\n const handled = await handleApiRequest(req, res, c2dDir);\n if (!handled) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal server error';\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: message }));\n }\n return;\n }\n\n // Renders (pre-rendered HTML/screenshots)\n if (url.startsWith('/renders/')) {\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\n });\n return;\n }\n\n // Try project's public/ folder (images, fonts, icons, etc.)\n if (publicHandler) {\n publicHandler(req, res, () => {\n // Not found in public/ — fall through to canvas SPA\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n });\n return;\n }\n\n // Canvas app (SPA with fallback to index.html)\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n };\n\n // Try ports starting from the configured port\n for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {\n const tryPort = port + attempt;\n try {\n return await tryListen(requestHandler, tryPort);\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < MAX_PORT_ATTEMPTS - 1) {\n continue;\n }\n throw err;\n }\n }\n\n throw new Error(`Could not find an available port (tried ${port}-${port + MAX_PORT_ATTEMPTS - 1})`);\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/**\n * A single pen stroke on the drawing canvas.\n */\nexport interface DrawingStroke {\n points: { x: number; y: number }[];\n color: string;\n width: number;\n}\n\n/**\n * A comment pinned to a canvas coordinate.\n */\nexport interface Comment {\n id: string;\n x: number;\n y: number;\n text: string;\n author: string;\n timestamp: string;\n}\n\n/**\n * Handle API requests under the /api/ prefix.\n *\n * Returns true if the request was handled, false otherwise.\n */\nexport async function handleApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<boolean> {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n if (url === '/api/manifest' && method === 'GET') {\n await handleGetManifest(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'GET') {\n await handleGetComments(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'POST') {\n await handlePostComment(req, res, c2dDir);\n return true;\n }\n\n const deleteMatch = url.match(/^\\/api\\/comments\\/(.+)$/);\n if (deleteMatch && method === 'DELETE') {\n await handleDeleteComment(res, c2dDir, deleteMatch[1]);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'GET') {\n await handleGetDrawings(res, c2dDir);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'POST') {\n await handlePostDrawings(req, res, c2dDir);\n return true;\n }\n\n return false;\n}\n\n// --- Handlers ---\n\nasync function handleGetManifest(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const manifestPath = join(c2dDir, 'manifest.json');\n if (!existsSync(manifestPath)) {\n sendJson(res, 404, { error: 'manifest.json not found' });\n return;\n }\n const data = await readFile(manifestPath, 'utf-8');\n sendRawJson(res, 200, data);\n}\n\nasync function handleGetComments(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n sendJson(res, 200, comments);\n}\n\nasync function handlePostComment(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!isValidCommentInput(parsed)) {\n sendJson(res, 400, { error: 'Missing required fields: x, y, text, author' });\n return;\n }\n\n const comment: Comment = {\n id: randomUUID(),\n x: parsed.x,\n y: parsed.y,\n text: parsed.text,\n author: parsed.author,\n timestamp: new Date().toISOString(),\n };\n\n const comments = await loadComments(c2dDir);\n comments.push(comment);\n await saveComments(c2dDir, comments);\n sendJson(res, 201, comment);\n}\n\nasync function handleDeleteComment(\n res: ServerResponse,\n c2dDir: string,\n id: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n const index = comments.findIndex(c => c.id === id);\n if (index === -1) {\n sendJson(res, 404, { error: 'Comment not found' });\n return;\n }\n comments.splice(index, 1);\n await saveComments(c2dDir, comments);\n sendJson(res, 200, { ok: true });\n}\n\n// --- Drawing Handlers ---\n\nasync function handleGetDrawings(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const drawings = await loadDrawings(c2dDir);\n sendJson(res, 200, drawings);\n}\n\nasync function handlePostDrawings(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!Array.isArray(parsed)) {\n sendJson(res, 400, { error: 'Body must be an array of strokes' });\n return;\n }\n\n await saveDrawings(c2dDir, parsed as DrawingStroke[]);\n sendJson(res, 200, { ok: true });\n}\n\nasync function loadDrawings(c2dDir: string): Promise<DrawingStroke[]> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n if (!existsSync(drawingsPath)) {\n return [];\n }\n const data = await readFile(drawingsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveDrawings(c2dDir: string, drawings: DrawingStroke[]): Promise<void> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n const dir = dirname(drawingsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(drawingsPath, JSON.stringify(drawings, null, 2), 'utf-8');\n}\n\n// --- Helpers ---\n\nfunction isValidCommentInput(\n value: unknown,\n): value is { x: number; y: number; text: string; author: string } {\n if (typeof value !== 'object' || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.x === 'number' &&\n typeof obj.y === 'number' &&\n typeof obj.text === 'string' &&\n typeof obj.author === 'string'\n );\n}\n\nasync function loadComments(c2dDir: string): Promise<Comment[]> {\n const commentsPath = join(c2dDir, 'comments.json');\n if (!existsSync(commentsPath)) {\n return [];\n }\n const data = await readFile(commentsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveComments(c2dDir: string, comments: Comment[]): Promise<void> {\n const commentsPath = join(c2dDir, 'comments.json');\n const dir = dirname(commentsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(commentsPath, JSON.stringify(comments, null, 2), 'utf-8');\n}\n\nfunction readRequestBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n req.on('error', reject);\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(body);\n}\n\nfunction sendRawJson(res: ServerResponse, status: number, jsonString: string): void {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(jsonString);\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface VibeCanvasConfig {\n apiKey: string;\n port: number;\n excludeRoutes: string[];\n devServerUrl?: string;\n devServerCommand?: string;\n}\n\nconst DEFAULT_PORT = 4800;\n\n/**\n * Load configuration from environment variables and optional config file.\n */\nexport async function loadConfig(projectRoot: string): Promise<VibeCanvasConfig> {\n let fileConfig: Partial<VibeCanvasConfig> = {};\n\n // Try to load c2d.config.js\n const configPath = join(projectRoot, 'c2d.config.js');\n if (existsSync(configPath)) {\n try {\n const mod = await import(configPath);\n fileConfig = mod.default || mod;\n } catch {\n // Config file exists but can't be loaded — use defaults\n }\n }\n\n const apiKey = process.env.C2D_API_KEY || fileConfig.apiKey || '';\n\n return {\n apiKey,\n port: fileConfig.port || Number(process.env.C2D_PORT) || DEFAULT_PORT,\n excludeRoutes: fileConfig.excludeRoutes || [],\n devServerUrl: fileConfig.devServerUrl || process.env.C2D_DEV_SERVER_URL,\n devServerCommand: fileConfig.devServerCommand,\n };\n}\n\nexport interface DetectedProject {\n isSupported: boolean;\n projectType: 'nextjs-app' | 'nextjs-pages' | 'react-router' | 'unknown';\n appDir: string | null;\n projectRoot: string;\n projectName: string;\n}\n\n/**\n * Detect the project type and routing convention.\n *\n * Supports Next.js (App Router & Pages Router) and React Router (Vite).\n */\nexport async function detectProject(projectRoot: string): Promise<DetectedProject> {\n let projectName = 'unknown';\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n projectName = pkg.name || 'unknown';\n } catch {\n // No package.json\n }\n\n // Check for Next.js first\n const hasNextConfig =\n existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'));\n\n if (hasNextConfig) {\n // Check App Router first, then Pages Router as fallback\n // Priority: app/ → src/app/ → pages/ → src/pages/\n let appDir = join(projectRoot, 'app');\n let hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'app');\n hasAppDir = existsSync(appDir);\n }\n\n if (hasAppDir) {\n return { isSupported: true, projectType: 'nextjs-app', appDir, projectRoot, projectName };\n }\n\n appDir = join(projectRoot, 'pages');\n hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'pages');\n hasAppDir = existsSync(appDir);\n }\n\n if (hasAppDir) {\n return { isSupported: true, projectType: 'nextjs-pages', appDir, projectRoot, projectName };\n }\n\n // Has next config but no recognized directory\n return { isSupported: false, projectType: 'unknown', appDir: null, projectRoot, projectName };\n }\n\n // Check for React Router (commonly used with Vite)\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if ('react-router-dom' in deps || 'react-router' in deps) {\n return { isSupported: true, projectType: 'react-router', appDir: null, projectRoot, projectName };\n }\n } catch {\n // No package.json or can't parse\n }\n\n return { isSupported: false, projectType: 'unknown', appDir: null, projectRoot, projectName };\n}\n\n/**\n * Detect if the current directory is a Next.js App Router project.\n * @deprecated Use `detectProject` instead, which also supports React Router.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\n const result = await detectProject(projectRoot);\n return {\n isNextJs: result.projectType === 'nextjs-app' || result.projectType === 'nextjs-pages',\n appDir: result.appDir,\n projectName: result.projectName,\n };\n}\n","/**\n * Simple console progress utilities for the CLI.\n */\n\nconst COLORS = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n};\n\nexport function log(message: string): void {\n console.log(`${COLORS.dim}[c2d]${COLORS.reset} ${message}`);\n}\n\nexport function success(message: string): void {\n console.log(`${COLORS.green} ✓${COLORS.reset} ${message}`);\n}\n\nexport function warn(message: string): void {\n console.log(`${COLORS.yellow} ⚠${COLORS.reset} ${message}`);\n}\n\nexport function error(message: string): void {\n console.error(`${COLORS.red} ✗${COLORS.reset} ${message}`);\n}\n\nexport function header(message: string): void {\n console.log(`\\n${COLORS.bold}${COLORS.cyan}${message}${COLORS.reset}`);\n}\n\nexport function step(current: number, total: number, message: string): void {\n console.log(`${COLORS.dim} [${current}/${total}]${COLORS.reset} ${message}`);\n}\n\nexport function banner(): void {\n console.log(`\n${COLORS.bold}${COLORS.cyan} Code to Design${COLORS.reset} ${COLORS.dim}v0.1.0${COLORS.reset}\n${COLORS.dim} AI-powered UI review canvas${COLORS.reset}\n`);\n}\n"],"mappings":"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","names":["join","mkdir","existsSync","routes","readFile","join","existsSync","readFile","join","join","existsSync","readFile","error","mkdir","writeFile","join","existsSync","join","resolve","join","join","slugifyRoute","join","mkdir","writeFile","createServer","join","existsSync","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","resolve","createServer","join","existsSync","existsSync","readFile","join","join","existsSync","scanDir","mkdir","r","resolve","dirname","writeFile"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runScan
3
- } from "../chunk-3CJ7RVFI.js";
3
+ } from "../chunk-EBLAP5DI.js";
4
4
  export {
5
5
  runScan
6
6
  };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  loadConfig,
5
5
  runScan,
6
6
  startCanvasServer
7
- } from "./chunk-3CJ7RVFI.js";
7
+ } from "./chunk-EBLAP5DI.js";
8
8
 
9
9
  // src/version.ts
10
10
  var version = "0.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-to-design",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "AI-powered UI review canvas — CLI tool",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/scan.ts","../../core/src/discovery/route-scanner.ts","../../core/src/analysis/code-analyzer.ts","../../core/src/analysis/auth-detector.ts","../../core/src/analysis/endpoint-extractor.ts","../../core/src/mock/llm-client.ts","../../core/src/mock/prompt-templates.ts","../../core/src/mock/mock-generator.ts","../../core/src/render/pre-renderer.ts","../../core/src/render/dev-server.ts","../../core/src/render/style-inliner.ts","../../core/src/render/interaction-capturer.ts","../../core/src/render/url-matcher.ts","../src/server/canvas-server.ts","../src/server/api-routes.ts","../src/config.ts","../src/utils/progress.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { rm, mkdir } from 'node:fs/promises';\nimport { existsSync, watch as fsWatch } from 'node:fs';\nimport {\n scanRoutes,\n analyzePage,\n generateMocks,\n preRenderPages,\n type RenderTask,\n type MockGeneratorOptions,\n} from '@code-to-design/core';\nimport { startCanvasServer } from '../server/canvas-server.js';\nimport { loadConfig, detectProject } from '../config.js';\nimport * as ui from '../utils/progress.js';\n\n/**\n * Main scan command — runs the full Code to Design pipeline.\n *\n * 1. Detect project type\n * 2. Discover routes\n * 3. Analyze code + generate mocks\n * 4. Pre-render pages\n * 5. Start canvas server\n */\nexport async function runScan(options: {\n projectRoot: string;\n skipRender?: boolean;\n open?: boolean;\n watch?: boolean;\n}): Promise<void> {\n const { projectRoot, skipRender = false, open = true, watch = false } = options;\n\n ui.banner();\n\n // Load config\n const config = await loadConfig(projectRoot);\n\n // Step 1: Detect project\n ui.header('Detecting project...');\n const project = await detectProject(projectRoot);\n\n if (!project.isSupported) {\n ui.error('Unsupported project type.');\n ui.log('Code to Design supports Next.js (App Router / Pages Router) and React Router (Vite) projects.');\n process.exit(1);\n }\n\n if (project.projectType !== 'react-router' && !project.appDir) {\n ui.error('No app/ or pages/ directory found.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName} (${project.projectType})`);\n if (project.appDir) {\n ui.success(`App directory: ${project.appDir}`);\n }\n\n const c2dDir = join(projectRoot, '.c2d');\n\n // If --skip-render, just start the server with existing renders\n if (skipRender) {\n if (!existsSync(join(c2dDir, 'manifest.json'))) {\n ui.error('No previous renders found. Run without --skip-render first.');\n process.exit(1);\n }\n ui.log('Skipping render, using existing canvas data...');\n await startServer(c2dDir, config.port, open, projectRoot);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const scanDir = project.projectType === 'react-router' ? project.projectRoot : project.appDir!;\n const routerType = project.projectType === 'react-router' ? 'react-router' as const\n : project.projectType === 'nextjs-pages' ? 'pages-router' as const\n : 'app-router' as const;\n const routes = await scanRoutes({ appDir: scanDir, routerType });\n\n if (routes.length === 0) {\n ui.error('No routes found in app/ directory.');\n process.exit(1);\n }\n\n // Filter excluded routes\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n ui.success(`Found ${filteredRoutes.length} routes`);\n for (const r of filteredRoutes) {\n ui.log(` ${r.urlPath}${r.isDynamic ? ' [dynamic]' : ''}`);\n }\n\n // Step 3: Check API key\n if (!config.apiKey) {\n ui.warn('No API key configured. Mock generation will use fallback data.');\n ui.log('Set C2D_API_KEY env var or add apiKey to c2d.config.js');\n }\n\n // Step 4: Analyze and generate mocks\n ui.header('Analyzing code and generating mocks...');\n\n const renderTasks: RenderTask[] = [];\n let totalTokens = { input: 0, output: 0 };\n\n const mockOptions: MockGeneratorOptions = {\n apiKey: config.apiKey,\n };\n\n for (let i = 0; i < filteredRoutes.length; i++) {\n const route = filteredRoutes[i];\n ui.step(i + 1, filteredRoutes.length, `${route.urlPath}`);\n\n // Analyze page\n const analysis = await analyzePage(route, { projectRoot });\n\n // Generate mocks\n const { configs, tokenUsage } = await generateMocks(analysis, mockOptions);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n\n // Create render tasks\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n if (totalTokens.input > 0) {\n ui.success(`Mock generation complete (${totalTokens.input} input tokens, ${totalTokens.output} output tokens)`);\n } else {\n ui.success('Using fallback mocks (no API key or no API dependencies)');\n }\n\n // Step 5: Pre-render\n ui.header(`Pre-rendering ${renderTasks.length} page states...`);\n\n // Clear previous renders but preserve comments\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n const { results, manifest } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n onProgress: (completed, total, result) => {\n const pct = Math.round((completed / total) * 100);\n const icon = result.success ? '✓' : '✗';\n const label = `${result.route.urlPath} [${result.stateName}]`;\n process.stdout.write(`\\r ${icon} ${completed}/${total} (${pct}%) ${label}${''.padEnd(20)}`);\n if (completed === total) process.stdout.write('\\n');\n },\n });\n\n const successCount = results.filter((r) => r.success).length;\n const failCount = results.filter((r) => !r.success).length;\n\n ui.success(`Rendered ${successCount}/${results.length} pages`);\n if (failCount > 0) {\n ui.warn(`${failCount} pages failed to render`);\n for (const r of results.filter((r) => !r.success)) {\n ui.error(` ${r.route.urlPath} [${r.stateName}]: ${r.error}`);\n }\n }\n\n // Step 6: Start canvas server\n if (watch) {\n // In watch mode, start the server without blocking so we can watch for changes\n const server = await startServerNonBlocking(c2dDir, config.port, open, projectRoot);\n const watchDir = project.projectType === 'react-router'\n ? join(projectRoot, 'src')\n : project.appDir!;\n watchAndRerender(projectRoot, watchDir, c2dDir, config, routerType);\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n } else {\n await startServer(c2dDir, config.port, open, projectRoot);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean, projectRoot?: string): Promise<void> {\n ui.header('Starting canvas server...');\n\n // Resolve canvas app directory: find canvas-dist relative to this package\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Press Ctrl+C to stop\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n // Keep process alive until Ctrl+C\n await new Promise<void>((resolve) => {\n const shutdown = async () => {\n ui.log('\\nShutting down...');\n await server.close();\n resolve();\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n}\n\nasync function startServerNonBlocking(\n c2dDir: string,\n port: number,\n open: boolean,\n projectRoot?: string,\n): Promise<{ url: string; close: () => Promise<void> }> {\n ui.header('Starting canvas server...');\n\n const canvasDir = await resolveCanvasDir(c2dDir);\n if (!canvasDir) {\n ui.warn('Canvas app not bundled. Using placeholder.');\n }\n\n const server = await startCanvasServer({\n port,\n canvasDir: canvasDir!,\n c2dDir,\n projectRoot,\n });\n\n ui.success(`Canvas server running at ${server.url}`);\n ui.log('Share this URL with your team for collaborative review');\n ui.log('Watching for file changes...\\n');\n\n if (open) {\n try {\n const { exec } = await import('node:child_process');\n exec(`open ${server.url}`);\n } catch {\n // Can't open browser — not critical\n }\n }\n\n return server;\n}\n\n/**\n * Find the canvas-dist directory by walking up from the module's location\n * until we find a directory containing canvas-dist/.\n * Works in both npm-installed and monorepo-dev environments.\n */\nasync function resolveCanvasDir(c2dDir: string): Promise<string> {\n const { fileURLToPath } = await import('node:url');\n const { dirname } = await import('node:path');\n const __filename = fileURLToPath(import.meta.url);\n\n // Walk up from the current file's directory to find canvas-dist/\n let dir = dirname(__filename);\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, 'canvas-dist');\n if (existsSync(candidate) && existsSync(join(candidate, 'index.html'))) {\n return candidate;\n }\n dir = dirname(dir);\n }\n\n // Fallback: try monorepo dev location\n const monorepoDev = join(dirname(__filename), '..', '..', '..', '..', 'apps', 'canvas', 'dist');\n if (existsSync(monorepoDev) && existsSync(join(monorepoDev, 'index.html'))) {\n return monorepoDev;\n }\n\n // Last resort: write placeholder\n const placeholder = join(c2dDir, '_canvas');\n await mkdir(placeholder, { recursive: true });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(join(placeholder, 'index.html'), `<!DOCTYPE html><html><body>\n <h1>Code to Design</h1>\n <p>Canvas app not built. Run: <code>cd apps/canvas && npx vite build</code></p>\n <p><a href=\"/api/manifest\">View Manifest</a></p>\n </body></html>`);\n return placeholder;\n}\n\n/** File extensions to watch for changes. */\nconst WATCH_EXTENSIONS = new Set(['.tsx', '.ts', '.jsx', '.js', '.css']);\n\n/** Directories and patterns to ignore during watch. */\nfunction shouldIgnoreFile(filename: string | null): boolean {\n if (!filename) return true;\n const ignored = ['node_modules', '.next', '.c2d', '.git'];\n if (ignored.some((dir) => filename.includes(dir))) return true;\n const ext = filename.slice(filename.lastIndexOf('.'));\n return !WATCH_EXTENSIONS.has(ext);\n}\n\nfunction watchAndRerender(\n projectRoot: string,\n appDir: string,\n c2dDir: string,\n config: Awaited<ReturnType<typeof loadConfig>>,\n routerType?: 'app-router' | 'pages-router' | 'react-router',\n): void {\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n let isRendering = false;\n\n ui.log(`Watching ${appDir} for changes...`);\n\n fsWatch(appDir, { recursive: true }, (_event, filename) => {\n if (shouldIgnoreFile(filename as string | null)) return;\n\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(async () => {\n if (isRendering) return;\n isRendering = true;\n\n ui.log(`\\nFile changed: ${filename}. Re-rendering...`);\n\n try {\n // Re-discover routes\n const routes = await scanRoutes({ appDir, routerType });\n const filteredRoutes = routes.filter(\n (r) => !config.excludeRoutes.some((pattern: string) => r.urlPath.includes(pattern)),\n );\n\n // Re-analyze and generate mocks\n const renderTasks: RenderTask[] = [];\n const mockOptions: MockGeneratorOptions = { apiKey: config.apiKey };\n\n for (const route of filteredRoutes) {\n const analysis = await analyzePage(route, { projectRoot });\n const { configs } = await generateMocks(analysis, mockOptions);\n for (const mockConfig of configs) {\n renderTasks.push({\n route,\n mockConfig,\n authConfig: analysis.authConfig,\n });\n }\n }\n\n // Clear previous renders\n if (existsSync(join(c2dDir, 'renders'))) {\n await rm(join(c2dDir, 'renders'), { recursive: true });\n }\n await mkdir(c2dDir, { recursive: true });\n\n // Pre-render\n const { results } = await preRenderPages(renderTasks, {\n projectRoot,\n outputDir: c2dDir,\n devServerUrl: config.devServerUrl,\n });\n\n const successCount = results.filter((r) => r.success).length;\n ui.success(`Re-render complete. ${successCount} pages updated.`);\n } catch (err: any) {\n ui.error(`Re-render failed: ${err.message || err}`);\n } finally {\n isRendering = false;\n }\n }, 500);\n });\n}\n","import { readdir, readFile, stat } from 'node:fs/promises';\nimport { join, extname } from 'node:path';\nimport { RouteInfo, RouteParam, ScanOptions } from './types.js';\n\nconst PAGE_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx']);\nconst PAGE_BASENAMES = new Set(['page']);\n\n/** Files that should be skipped in Pages Router (special Next.js files). */\nconst PAGES_ROUTER_SKIP = new Set(['_app', '_document', '_error']);\n\n/**\n * Check if a filename is an App Router page file (page.tsx, page.js, etc.)\n */\nfunction isPageFile(filename: string): boolean {\n const ext = extname(filename);\n const basename = filename.slice(0, -ext.length);\n return PAGE_EXTENSIONS.has(ext) && PAGE_BASENAMES.has(basename);\n}\n\n/**\n * Check if a filename is a valid Pages Router page file.\n * Skips files starting with `_` and non-page extensions.\n */\nfunction isPagesRouterFile(filename: string): boolean {\n const ext = extname(filename);\n if (!PAGE_EXTENSIONS.has(ext)) return false;\n const basename = filename.slice(0, -ext.length);\n if (basename.startsWith('_')) return false;\n return true;\n}\n\n/**\n * Check if a directory should be skipped entirely.\n */\nfunction shouldSkipDir(name: string): boolean {\n // Private folders\n if (name.startsWith('_')) return true;\n // Parallel route slots\n if (name.startsWith('@')) return true;\n // Intercepting routes\n if (name.startsWith('(.)') || name.startsWith('(..)')) return true;\n // Build artifacts and dependencies\n if (name === 'node_modules' || name === '.next') return true;\n return false;\n}\n\n/**\n * Check if a directory is a route group (parenthesized name like \"(auth)\").\n * Route groups are stripped from the URL but recursed into.\n */\nfunction isRouteGroup(name: string): boolean {\n return name.startsWith('(') && name.endsWith(')') && !name.startsWith('(.');\n}\n\n/**\n * Parse a dynamic route segment and extract parameter info.\n * Returns null if the segment is not dynamic.\n */\nfunction parseDynamicSegment(segment: string): RouteParam | null {\n // Optional catch-all: [[...param]]\n const optionalCatchAll = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n if (optionalCatchAll) {\n return { name: optionalCatchAll[1], isCatchAll: true, isOptional: true };\n }\n\n // Required catch-all: [...param]\n const catchAll = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n if (catchAll) {\n return { name: catchAll[1], isCatchAll: true, isOptional: false };\n }\n\n // Single dynamic: [param]\n const dynamic = segment.match(/^\\[(.+)\\]$/);\n if (dynamic) {\n return { name: dynamic[1], isCatchAll: false, isOptional: false };\n }\n\n return null;\n}\n\n/**\n * Convert a dynamic segment to a URL-friendly representation.\n */\nfunction segmentToUrlPart(segment: string): string {\n const param = parseDynamicSegment(segment);\n if (!param) return segment;\n\n if (param.isCatchAll && param.isOptional) return `:${param.name}*`;\n if (param.isCatchAll) return `:${param.name}+`;\n return `:${param.name}`;\n}\n\n/**\n * Recursively scan a directory for Next.js App Router page files.\n */\nasync function scanDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPageFile(entry)) {\n const urlPath = '/' + urlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...params],\n isDynamic: params.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n if (shouldSkipDir(entry)) continue;\n\n if (isRouteGroup(entry)) {\n // Route groups: recurse but don't add to URL\n const nested = await scanDir(entryPath, urlSegments, params);\n routes.push(...nested);\n } else {\n // Regular or dynamic segment\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n }\n\n return routes;\n}\n\n/**\n * Recursively scan a Pages Router `pages/` directory for page files.\n *\n * Pages Router conventions:\n * - Any .tsx/.ts/.jsx/.js file is a route (not just `page.*`)\n * - `index.tsx` maps to the directory root\n * - `_app`, `_document`, `_error` are skipped\n * - Files starting with `_` are skipped\n * - `api/` directory is skipped (API routes)\n */\nasync function scanPagesDir(\n dirPath: string,\n urlSegments: string[],\n params: RouteParam[],\n): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n return routes;\n }\n\n for (const entry of entries) {\n const entryPath = join(dirPath, entry);\n const entryStat = await stat(entryPath).catch(() => null);\n if (!entryStat) continue;\n\n if (entryStat.isFile() && isPagesRouterFile(entry)) {\n const ext = extname(entry);\n const basename = entry.slice(0, -ext.length);\n\n // Convert filename to URL segment\n let fileUrlSegments: string[];\n let fileParams: RouteParam[];\n\n if (basename === 'index') {\n // index.tsx → use current directory path\n fileUrlSegments = urlSegments;\n fileParams = params;\n } else {\n const param = parseDynamicSegment(basename);\n const urlPart = segmentToUrlPart(basename);\n fileUrlSegments = [...urlSegments, urlPart];\n fileParams = param ? [...params, param] : params;\n }\n\n const urlPath = '/' + fileUrlSegments.join('/');\n routes.push({\n urlPath: urlPath || '/',\n filePath: entryPath,\n params: [...fileParams],\n isDynamic: fileParams.length > 0,\n });\n }\n\n if (entryStat.isDirectory()) {\n // Skip api/ directory and hidden/private directories\n if (entry === 'api') continue;\n if (entry.startsWith('_')) continue;\n if (entry === 'node_modules' || entry === '.next') continue;\n\n const param = parseDynamicSegment(entry);\n const urlPart = segmentToUrlPart(entry);\n const newParams = param ? [...params, param] : params;\n const nested = await scanPagesDir(entryPath, [...urlSegments, urlPart], newParams);\n routes.push(...nested);\n }\n }\n\n return routes;\n}\n\n/**\n * Parse a React Router `:param` dynamic segment into a RouteParam.\n */\nfunction parseReactRouterParam(segment: string): RouteParam | null {\n if (!segment.startsWith(':')) return null;\n return { name: segment.slice(1), isCatchAll: false, isOptional: false };\n}\n\n/**\n * Recursively find files under `dir` that have one of the given extensions.\n */\nasync function findFiles(dir: string, extensions: Set<string>): Promise<string[]> {\n const results: string[] = [];\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return results;\n }\n for (const entry of entries) {\n const full = join(dir, entry);\n const s = await stat(full).catch(() => null);\n if (!s) continue;\n if (s.isDirectory()) {\n if (entry === 'node_modules' || entry === '.git' || entry === 'dist' || entry === 'build') continue;\n results.push(...(await findFiles(full, extensions)));\n } else if (extensions.has(extname(entry))) {\n results.push(full);\n }\n }\n return results;\n}\n\n/**\n * Check if a project at the given root uses react-router-dom.\n */\nasync function hasReactRouter(projectRoot: string): Promise<boolean> {\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n return 'react-router-dom' in deps || 'react-router' in deps;\n } catch {\n return false;\n }\n}\n\n/**\n * Extract route paths from a source file that uses react-router-dom.\n *\n * This is a best-effort regex-based approach. It handles:\n * - JSX: `<Route path=\"/about\" ...`\n * - Object config: `{ path: \"/about\" ...` or `{ path: '/about' ...`\n * - createBrowserRouter / createRoutesFromElements patterns\n */\nfunction extractRoutePathsFromSource(source: string): string[] {\n const paths: string[] = [];\n const seen = new Set<string>();\n\n // Pattern 1: <Route path=\"...\" or <Route path='...'\n const jsxPattern = /<Route\\s[^>]*?path\\s*=\\s*[\"']([^\"']+)[\"']/g;\n let match: RegExpExecArray | null;\n while ((match = jsxPattern.exec(source)) !== null) {\n const p = match[1];\n if (p !== '*' && !seen.has(p)) {\n seen.add(p);\n paths.push(p);\n }\n }\n\n // Pattern 2: { path: \"...\" } or { path: '...' } in route config objects\n const objPattern = /path\\s*:\\s*[\"']([^\"']+)[\"']/g;\n while ((match = objPattern.exec(source)) !== null) {\n const p = match[1];\n if (p !== '*' && !seen.has(p)) {\n seen.add(p);\n paths.push(p);\n }\n }\n\n return paths;\n}\n\n/**\n * Scan a React Router project and extract route definitions from source code.\n *\n * This is inherently imprecise since React Router uses code-based routing.\n * The scanner finds files that import from `react-router-dom` and contain\n * route definitions, then extracts paths using regex.\n */\nasync function scanReactRouter(projectRoot: string): Promise<RouteInfo[]> {\n const routes: RouteInfo[] = [];\n const seen = new Set<string>();\n\n // Find candidate source files under src/ (or project root if no src/)\n const srcDir = join(projectRoot, 'src');\n const scanRoot = await stat(srcDir).then(() => srcDir).catch(() => projectRoot);\n const files = await findFiles(scanRoot, PAGE_EXTENSIONS);\n\n for (const filePath of files) {\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n continue;\n }\n\n // Only process files that import from react-router-dom / react-router\n if (\n !source.includes('react-router-dom') &&\n !source.includes('react-router')\n ) {\n continue;\n }\n\n // Check for Route or createBrowserRouter usage\n if (\n !source.includes('Route') &&\n !source.includes('createBrowserRouter') &&\n !source.includes('createRoutesFromElements') &&\n !source.match(/path\\s*:\\s*[\"']/)\n ) {\n continue;\n }\n\n const extractedPaths = extractRoutePathsFromSource(source);\n\n for (const routePath of extractedPaths) {\n if (seen.has(routePath)) continue;\n seen.add(routePath);\n\n // Parse dynamic segments (:param)\n const segments = routePath.split('/').filter(Boolean);\n const params: RouteParam[] = [];\n for (const seg of segments) {\n const param = parseReactRouterParam(seg);\n if (param) params.push(param);\n }\n\n // Normalize path — ensure leading slash\n const urlPath = routePath.startsWith('/') ? routePath : '/' + routePath;\n\n routes.push({\n urlPath,\n filePath,\n params,\n isDynamic: params.length > 0,\n });\n }\n }\n\n return routes;\n}\n\n/**\n * Scan a project directory and extract all renderable routes.\n *\n * Supports Next.js App Router, Pages Router, and React Router (Vite):\n * - App Router: page.{js,jsx,ts,tsx} files, route groups, parallel routes, etc.\n * - Pages Router: any .tsx/.ts/.jsx/.js file (except _app, _document, _error, api/)\n * - React Router: regex-based extraction from source files importing react-router-dom\n *\n * For Next.js, `appDir` should point to the `app/` or `pages/` directory.\n * For React Router, `appDir` should point to the project root.\n * The scanner auto-detects which router convention to use based on `routerType`\n * (default 'auto' detects from directory name and project structure).\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir, routerType = 'auto' } = options;\n\n // React Router: explicit or auto-detected\n if (routerType === 'react-router') {\n const routes = await scanReactRouter(appDir);\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return routes;\n }\n\n if (routerType === 'auto') {\n // Check if this looks like a React Router project (has package.json with react-router-dom)\n const isReactRouter = await hasReactRouter(appDir);\n if (isReactRouter) {\n const routes = await scanReactRouter(appDir);\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n return routes;\n }\n }\n\n const dirStat = await stat(appDir).catch(() => null);\n if (!dirStat || !dirStat.isDirectory()) {\n throw new Error(`App directory not found: ${appDir}`);\n }\n\n // Detect if this is a Pages Router directory\n const dirName = appDir.replace(/\\/$/, '').split('/').pop();\n const isPagesRouter = routerType === 'pages-router' || (routerType === 'auto' && dirName === 'pages');\n\n const routes = isPagesRouter\n ? await scanPagesDir(appDir, [], [])\n : await scanDir(appDir, [], []);\n\n // Sort routes for consistent output\n routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));\n\n return routes;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join, dirname, resolve, extname } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type { PageAnalysis, AnalyzeOptions, ExtractedEndpoint } from './types.js';\nimport { detectAuth } from './auth-detector.js';\nimport { extractEndpoints, extractBaseUrl } from './endpoint-extractor.js';\n\nconst DEFAULT_MAX_TOKENS = 8000;\nconst CHARS_PER_TOKEN = 4; // rough approximation\n\n/**\n * Extract import paths from TypeScript/JavaScript source code.\n * Uses regex — does not handle barrel exports or re-exports.\n */\nfunction extractImportPaths(source: string): string[] {\n const paths: string[] = [];\n // Match: import ... from '...' and import '...'\n const regex = /import\\s+(?:[\\s\\S]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n paths.push(match[1]);\n }\n return paths;\n}\n\n/**\n * Resolve tsconfig path aliases (e.g., @/lib/api → /absolute/path/lib/api).\n * Returns an absolute path when aliases contain absolute base paths.\n */\nfunction resolvePathAlias(\n importPath: string,\n aliases: Record<string, string>,\n): string | null {\n for (const [pattern, replacement] of Object.entries(aliases)) {\n const prefix = pattern.replace(/\\*$/, '');\n if (importPath.startsWith(prefix)) {\n const rest = importPath.slice(prefix.length);\n return replacement.replace(/\\*$/, '') + rest;\n }\n }\n return null;\n}\n\n/**\n * Read tsconfig.json and extract path aliases.\n */\nasync function readPathAliases(projectRoot: string): Promise<Record<string, string>> {\n const aliases: Record<string, string> = {};\n\n for (const filename of ['tsconfig.json', 'jsconfig.json']) {\n const configPath = join(projectRoot, filename);\n if (!existsSync(configPath)) continue;\n\n try {\n const content = await readFile(configPath, 'utf-8');\n // Strip JSON5-style comments while preserving // inside strings.\n // Match strings first (to skip them), then line & block comments.\n const stripped = content.replace(\n /\"(?:[^\"\\\\]|\\\\.)*\"|\\/\\/.*$|\\/\\*[\\s\\S]*?\\*\\//gm,\n (match) => (match.startsWith('\"') ? match : ''),\n );\n const config = JSON.parse(stripped);\n const paths = config.compilerOptions?.paths;\n const baseUrl = config.compilerOptions?.baseUrl || '.';\n const resolvedBaseUrl = resolve(projectRoot, baseUrl);\n\n if (paths) {\n for (const [key, values] of Object.entries(paths)) {\n const targets = values as string[];\n if (targets.length > 0) {\n // Store as absolute path for reliable resolution\n aliases[key] = join(resolvedBaseUrl, targets[0]);\n }\n }\n }\n } catch {\n // Can't parse tsconfig — skip aliases\n }\n }\n\n return aliases;\n}\n\n/**\n * Try to resolve an import path to an actual file.\n */\nfunction resolveImportToFile(importPath: string, fromDir: string): string | null {\n // Try exact path first, then with extensions\n const extensions = ['.ts', '.tsx', '.js', '.jsx'];\n const candidates: string[] = [];\n\n const resolved = resolve(fromDir, importPath);\n\n // Try exact\n candidates.push(resolved);\n // Try with extensions\n for (const ext of extensions) {\n candidates.push(resolved + ext);\n }\n // Try as directory with index\n for (const ext of extensions) {\n candidates.push(join(resolved, `index${ext}`));\n }\n\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Trace imports from a source file, up to maxDepth levels deep.\n * Returns a map of filePath → source content.\n */\nasync function traceImports(\n filePath: string,\n projectRoot: string,\n aliases: Record<string, string>,\n maxDepth: number,\n visited: Set<string> = new Set(),\n): Promise<Map<string, string>> {\n const results = new Map<string, string>();\n\n if (visited.has(filePath) || maxDepth < 0) return results;\n visited.add(filePath);\n\n let source: string;\n try {\n source = await readFile(filePath, 'utf-8');\n } catch {\n return results;\n }\n\n results.set(filePath, source);\n\n const importPaths = extractImportPaths(source);\n const fileDir = dirname(filePath);\n\n for (const importPath of importPaths) {\n // Skip node_modules imports\n if (!importPath.startsWith('.') && !importPath.startsWith('@/') && !importPath.startsWith('~/')) {\n // Check if it's a path alias\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (!aliasResolved) continue;\n\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else if (importPath.startsWith('.')) {\n // Relative import\n const resolved = resolveImportToFile(importPath, fileDir);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n } else {\n // Path alias (e.g., @/lib/api-client)\n const aliasResolved = resolvePathAlias(importPath, aliases);\n if (aliasResolved) {\n const resolved = resolveImportToFile(aliasResolved, projectRoot);\n if (resolved && !visited.has(resolved)) {\n const nested = await traceImports(resolved, projectRoot, aliases, maxDepth - 1, visited);\n for (const [path, content] of nested) {\n results.set(path, content);\n }\n }\n }\n }\n }\n\n return results;\n}\n\n/**\n * Estimate token count from a string (rough: ~4 chars per token).\n */\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n\n/**\n * Check if source code contains API call patterns.\n */\nfunction hasApiCalls(source: string): boolean {\n return /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\buseQuery\\b/.test(source)\n || /\\buseMutation\\b/.test(source)\n || /\\bapiRequest\\b/.test(source)\n || /\\bgetServerSideProps\\b/.test(source)\n || /\\bgetStaticProps\\b/.test(source)\n || /API_BASE_URL/.test(source)\n || /['\"]\\/api\\//.test(source)\n // Detect imports from api/client modules (common naming patterns)\n || /from\\s+['\"].*api[-_]?client.*['\"]/.test(source)\n || /from\\s+['\"].*\\/api['\"]/.test(source)\n || /from\\s+['\"].*\\/services\\//.test(source);\n}\n\n/**\n * Common API client file locations to scan eagerly.\n */\nconst API_CLIENT_CANDIDATES = [\n 'lib/api.ts', 'lib/api.tsx', 'lib/api.js', 'lib/api.jsx',\n 'lib/api-client.ts', 'lib/api-client.tsx', 'lib/api-client.js', 'lib/api-client.jsx',\n 'src/lib/api.ts', 'src/lib/api.tsx', 'src/lib/api.js', 'src/lib/api.jsx',\n 'src/lib/api-client.ts', 'src/lib/api-client.tsx', 'src/lib/api-client.js', 'src/lib/api-client.jsx',\n 'services/api.ts', 'services/api.js', 'services/api.tsx', 'services/api.jsx',\n 'src/services/api.ts', 'src/services/api.js', 'src/services/api.tsx', 'src/services/api.jsx',\n 'utils/api.ts', 'utils/api.js', 'utils/api.tsx', 'utils/api.jsx',\n 'src/utils/api.ts', 'src/utils/api.js', 'src/utils/api.tsx', 'src/utils/api.jsx',\n];\n\n/**\n * Check if source code contains patterns typical of an API client file.\n */\nfunction hasApiClientPatterns(source: string): boolean {\n return /\\.(get|post|put|delete|patch)\\s*\\(/.test(source)\n || /\\bfetch\\s*\\(/.test(source)\n || /\\baxios\\b/.test(source)\n || /\\bbaseURL\\b/.test(source)\n || /\\bAPI_URL\\b/.test(source);\n}\n\n/**\n * Eagerly scan common locations for an API client file.\n * Returns the absolute path and content of the first matching file,\n * or null if none found.\n */\nasync function findApiClientEagerly(\n projectRoot: string,\n alreadyIncluded: Set<string>,\n): Promise<{ path: string; content: string } | null> {\n for (const candidate of API_CLIENT_CANDIDATES) {\n const fullPath = join(projectRoot, candidate);\n if (alreadyIncluded.has(fullPath)) continue;\n if (!existsSync(fullPath)) continue;\n\n try {\n const content = await readFile(fullPath, 'utf-8');\n if (hasApiClientPatterns(content)) {\n return { path: fullPath, content };\n }\n } catch {\n // Can't read — skip\n }\n }\n return null;\n}\n\n/**\n * Analyze a single page: read its source, trace imports, detect auth,\n * and produce a context string suitable for LLM mock generation.\n */\nexport async function analyzePage(\n route: RouteInfo,\n options: AnalyzeOptions,\n): Promise<PageAnalysis> {\n const { projectRoot, maxTokensPerPage = DEFAULT_MAX_TOKENS } = options;\n const maxChars = maxTokensPerPage * CHARS_PER_TOKEN;\n\n const aliases = await readPathAliases(projectRoot);\n\n // Trace imports from the page file, up to 2 levels deep\n const tracedFiles = await traceImports(route.filePath, projectRoot, aliases, 2);\n\n const resolvedImports = [...tracedFiles.keys()].filter(p => p !== route.filePath);\n const allSources = [...tracedFiles.values()];\n\n // Build the source context with file headers\n let sourceContext = '';\n for (const [filePath, content] of tracedFiles) {\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length + 1)\n : filePath;\n const section = `\\n// === ${relativePath} ===\\n${content}\\n`;\n\n if (sourceContext.length + section.length > maxChars) {\n // Truncation: include just the page file and skip the rest\n break;\n }\n sourceContext += section;\n }\n\n // Eager scan: find API client files that may not have been imported\n const alreadyIncluded = new Set(tracedFiles.keys());\n let apiClientPath: string | null = null;\n let apiClientSource: string | null = null;\n\n const eagerResult = await findApiClientEagerly(projectRoot, alreadyIncluded);\n if (eagerResult) {\n apiClientPath = eagerResult.path;\n apiClientSource = eagerResult.content;\n\n // Add to source context and resolved imports\n const relativePath = eagerResult.path.startsWith(projectRoot)\n ? eagerResult.path.slice(projectRoot.length + 1)\n : eagerResult.path;\n const section = `\\n// === ${relativePath} ===\\n${eagerResult.content}\\n`;\n\n if (sourceContext.length + section.length <= maxChars) {\n sourceContext += section;\n }\n\n resolvedImports.push(eagerResult.path);\n allSources.push(eagerResult.content);\n } else {\n // Check if an API client was already found via import tracing\n for (const [filePath, content] of tracedFiles) {\n if (filePath === route.filePath) continue;\n if (hasApiClientPatterns(content)) {\n apiClientPath = filePath;\n apiClientSource = content;\n break;\n }\n }\n }\n\n // Extract endpoints from API client if found\n let extractedEndpointsList: ExtractedEndpoint[] = [];\n let apiBaseUrl: string | null = null;\n if (apiClientSource) {\n extractedEndpointsList = extractEndpoints(apiClientSource);\n apiBaseUrl = extractBaseUrl(apiClientSource);\n }\n\n // Detect auth patterns\n const authConfig = await detectAuth(projectRoot, allSources);\n\n // Check for API dependencies — check both the truncated context and all traced sources\n const combinedSource = allSources.join('\\n');\n const hasApi = hasApiCalls(sourceContext) || hasApiCalls(combinedSource);\n\n // Collect unresolved imports\n const allImportPaths = allSources.flatMap(extractImportPaths);\n const resolvedSet = new Set(resolvedImports.map(p => p));\n const unresolvedImports = allImportPaths\n .filter(p => p.startsWith('.') || p.startsWith('@/') || p.startsWith('~/'))\n .filter(p => {\n // Check if this import was resolved to any file\n const aliasResolved = resolvePathAlias(p, aliases);\n const checkPath = aliasResolved\n ? resolveImportToFile(aliasResolved, projectRoot)\n : resolveImportToFile(p, dirname(route.filePath));\n return !checkPath;\n });\n\n return {\n route,\n sourceContext,\n resolvedImports,\n unresolvedImports: [...new Set(unresolvedImports)],\n authConfig,\n hasApiDependencies: hasApi,\n estimatedTokens: estimateTokens(sourceContext),\n apiClientPath,\n extractedEndpoints: extractedEndpointsList,\n apiBaseUrl,\n };\n}\n\n/**\n * Analyze all discovered routes in a project.\n */\nexport async function analyzeRoutes(\n routes: RouteInfo[],\n options: AnalyzeOptions,\n): Promise<PageAnalysis[]> {\n const results: PageAnalysis[] = [];\n for (const route of routes) {\n const analysis = await analyzePage(route, options);\n results.push(analysis);\n }\n return results;\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { AuthConfig } from './types.js';\n\nconst MIDDLEWARE_FILES = ['middleware.ts', 'middleware.js', 'middleware.tsx', 'middleware.jsx'];\n\n/**\n * Extract cookie names from middleware source code.\n * Looks for patterns like: request.cookies.get('access_token')\n */\nfunction extractCookieNames(source: string): string[] {\n const cookies: string[] = [];\n const regex = /cookies\\.get\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(source)) !== null) {\n cookies.push(match[1]);\n }\n return [...new Set(cookies)];\n}\n\n/**\n * Extract API base URL from environment configuration.\n * Looks for NEXT_PUBLIC_API_URL or similar patterns.\n */\nfunction extractApiBaseUrl(source: string): string | null {\n const regex = /process\\.env\\.(\\w*API_URL\\w*)\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/;\n const match = source.match(regex);\n if (match) return match[2];\n\n const simpleRegex = /['\"]https?:\\/\\/[^'\"]+\\/api['\"]/;\n const simpleMatch = source.match(simpleRegex);\n if (simpleMatch) return simpleMatch[0].replace(/['\"]/g, '');\n\n return null;\n}\n\n/**\n * Extract auth check endpoint from source code.\n * Looks for patterns like: fetch(`${base}/auth/me`)\n */\nfunction extractAuthCheckEndpoint(source: string): string | null {\n const patterns = [\n /[`'\"](\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/me)[`'\"]/,\n /[`'\"](\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/api\\/auth\\/session)[`'\"]/,\n /[`'\"](\\/auth\\/user)[`'\"]/,\n /[`'\"](\\/api\\/user\\/me)[`'\"]/,\n ];\n\n for (const pattern of patterns) {\n const match = source.match(pattern);\n if (match) return match[1];\n }\n\n return null;\n}\n\n/**\n * Detect authentication patterns in the target project.\n *\n * Scans for:\n * 1. middleware.ts/js with cookie checks\n * 2. Auth context providers with auth-check endpoints\n * 3. API base URL configuration\n */\nexport async function detectAuth(projectRoot: string, allSources: string[]): Promise<AuthConfig> {\n const config: AuthConfig = {\n hasAuth: false,\n cookieNames: [],\n authCheckEndpoint: null,\n apiBaseUrl: null,\n };\n\n // 1. Check for middleware\n for (const filename of MIDDLEWARE_FILES) {\n const middlewarePath = join(projectRoot, filename);\n if (existsSync(middlewarePath)) {\n try {\n const source = await readFile(middlewarePath, 'utf-8');\n const cookies = extractCookieNames(source);\n if (cookies.length > 0) {\n config.hasAuth = true;\n config.cookieNames.push(...cookies);\n }\n } catch {\n // Middleware exists but can't be read — skip\n }\n }\n }\n\n // 2. Scan all collected sources for auth patterns\n const combinedSource = allSources.join('\\n');\n\n const authEndpoint = extractAuthCheckEndpoint(combinedSource);\n if (authEndpoint) {\n config.hasAuth = true;\n config.authCheckEndpoint = authEndpoint;\n }\n\n // Look for auth context patterns\n if (/useAuth|AuthProvider|AuthContext|SessionProvider/i.test(combinedSource)) {\n config.hasAuth = true;\n }\n\n // 3. Extract API base URL\n config.apiBaseUrl = extractApiBaseUrl(combinedSource);\n\n return config;\n}\n","import type { ExtractedEndpoint } from './types.js';\n\n/**\n * Extract the API base URL from an API client source file.\n * Looks for patterns like:\n * baseURL: 'http://localhost:8000'\n * process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api'\n * const API_BASE_URL = 'http://...'\n */\nexport function extractBaseUrl(source: string): string | null {\n // Pattern: process.env.SOMETHING || 'default_url'\n const envFallback = source.match(\n /process\\.env\\.\\w+\\s*\\|\\|\\s*['\"]([^'\"]+)['\"]/,\n );\n if (envFallback) return envFallback[1];\n\n // Pattern: baseURL: 'http://...'\n const baseUrlProp = source.match(/baseURL\\s*:\\s*['\"]([^'\"]+)['\"]/);\n if (baseUrlProp) return baseUrlProp[1];\n\n // Pattern: const API_BASE_URL = 'http://...' (or similar names)\n const constAssign = source.match(\n /(?:API_BASE_URL|API_URL|BASE_URL)\\s*=\\s*['\"]([^'\"]+)['\"]/,\n );\n if (constAssign) return constAssign[1];\n\n return null;\n}\n\n/**\n * Extract HTTP endpoint definitions from an API client source file.\n *\n * Recognises patterns like:\n * api.get('/path')\n * axios.post('/path', data)\n * api.delete(`/items/${id}`)\n * fetch('/api/items')\n */\nexport function extractEndpoints(apiClientSource: string): ExtractedEndpoint[] {\n const endpoints: ExtractedEndpoint[] = [];\n const seen = new Set<string>();\n\n const lines = apiClientSource.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Pattern 1: something.get|post|put|delete|patch('/path...')\n // Matches both regular strings and template literals\n const methodCallRegex =\n /\\.\\s*(get|post|put|delete|patch)\\s*\\(\\s*(?:['\"`])([^'\"`$]*)/gi;\n let match: RegExpExecArray | null;\n while ((match = methodCallRegex.exec(line)) !== null) {\n const method = match[1].toUpperCase();\n let path = match[2];\n\n // Clean up path — remove trailing quote chars if any\n path = path.replace(/['\"`)]+$/, '').trim();\n if (!path || path.length === 0) continue;\n\n const key = `${method} ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method, path };\n\n // Try to find a function name from nearby context\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n\n // Pattern 2: fetch('/path') — default GET\n const fetchRegex = /\\bfetch\\s*\\(\\s*['\"`]([^'\"`$]+)/g;\n while ((match = fetchRegex.exec(line)) !== null) {\n const path = match[1].replace(/['\"`)]+$/, '').trim();\n if (!path || path.length === 0) continue;\n\n const key = `GET ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method: 'GET', path };\n\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n\n // Pattern 3: template literal — e.g. api.get(`/items/${id}`)\n // Extract the static prefix before the first ${\n const templateRegex =\n /\\.\\s*(get|post|put|delete|patch)\\s*\\(\\s*`([^`]*?)\\$\\{/gi;\n while ((match = templateRegex.exec(line)) !== null) {\n const method = match[1].toUpperCase();\n const path = match[2].trim();\n if (!path || path.length === 0) continue;\n\n const key = `${method} ${path}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const endpoint: ExtractedEndpoint = { method, path };\n\n const fnName = findFunctionName(lines, i);\n if (fnName) endpoint.functionName = fnName;\n\n endpoints.push(endpoint);\n }\n }\n\n return endpoints;\n}\n\n/**\n * Look backwards from the current line to find a function/method name.\n * Matches patterns like:\n * getAll: () =>\n * async function getAll()\n * getAll() {\n */\nfunction findFunctionName(lines: string[], lineIndex: number): string | undefined {\n // Check current line and up to 3 lines above\n for (let i = lineIndex; i >= Math.max(0, lineIndex - 3); i--) {\n const line = lines[i];\n\n // Pattern: export const name = (args) => or const name = (args) =>\n const constArrow = line.match(/(?:export\\s+)?(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:\\([^)]*\\)\\s*=>|\\([^)]*\\)\\s*:\\s*\\w[^=]*=>)/);\n if (constArrow) return constArrow[1];\n\n // Pattern: propertyName: (args) => or propertyName: function\n const propMatch = line.match(/(\\w+)\\s*:\\s*(?:\\([^)]*\\)\\s*=>|function\\b)/);\n if (propMatch) return propMatch[1];\n\n // Pattern: async function name() or function name()\n const fnMatch = line.match(/(?:async\\s+)?function\\s+(\\w+)/);\n if (fnMatch) return fnMatch[1];\n\n // Pattern: name(args) { (method shorthand)\n const methodMatch = line.match(/^\\s*(\\w+)\\s*\\([^)]*\\)\\s*\\{/);\n if (methodMatch) return methodMatch[1];\n }\n\n return undefined;\n}\n","import Anthropic from '@anthropic-ai/sdk';\n\nexport interface LlmResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\n/**\n * Simple LLM client wrapper for Anthropic Claude API.\n */\nexport class LlmClient {\n private client: Anthropic;\n private model: string;\n\n constructor(apiKey: string, model: string = 'claude-sonnet-4-20250514') {\n this.client = new Anthropic({ apiKey });\n this.model = model;\n }\n\n async generate(systemPrompt: string, userPrompt: string): Promise<LlmResponse> {\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: userPrompt }],\n });\n\n const textBlock = response.content.find(block => block.type === 'text');\n const content = textBlock ? textBlock.text : '';\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n }\n}\n","import type { PageAnalysis } from '../analysis/types.js';\n\nexport const SYSTEM_PROMPT = `You are a mock data generator for a UI pre-rendering tool called Code to Design.\nYour job is to analyze a Next.js page's source code and generate realistic mock API responses that will make the page render correctly in different visual states.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces and API response shapes found in the source code.\n3. Generate contextually appropriate data (e.g., real company names for a finance app, realistic usernames for a social app).\n4. Generate MULTIPLE items in success data (at least 3-5 items for list endpoints).\n5. If actual API endpoint URLs are provided, use those EXACT paths in your response.\n6. Analyze the page's conditional rendering (if/else, ternary, switch, state variables) to identify meaningful visual states — not just generic success/error.\n7. Include auth mock data if the page requires authentication.\n8. For dynamic route parameters, generate a realistic sample value.`;\n\n/**\n * Build the user prompt for mock generation from a PageAnalysis.\n */\nexport function buildUserPrompt(analysis: PageAnalysis): string {\n const parts: string[] = [];\n\n parts.push(`## Page Route: ${analysis.route.urlPath}`);\n parts.push(`## Page File: ${analysis.route.filePath}`);\n\n if (analysis.route.isDynamic) {\n parts.push(`## Dynamic Parameters: ${analysis.route.params.map(p => p.name).join(', ')}`);\n }\n\n // Include extracted endpoints if available\n if (analysis.extractedEndpoints.length > 0) {\n parts.push('## Actual API Endpoints (use these EXACT paths)');\n for (const ep of analysis.extractedEndpoints) {\n const name = ep.functionName ? ` (${ep.functionName})` : '';\n parts.push(`- ${ep.method} ${ep.path}${name}`);\n }\n if (analysis.apiBaseUrl) {\n parts.push(`- Base URL: ${analysis.apiBaseUrl}`);\n }\n }\n\n parts.push('## Source Code Context');\n parts.push(analysis.sourceContext);\n\n if (analysis.authConfig.hasAuth) {\n parts.push('## Auth Configuration');\n parts.push(`- Requires authentication: yes`);\n if (analysis.authConfig.cookieNames.length > 0) {\n parts.push(`- Auth cookies: ${analysis.authConfig.cookieNames.join(', ')}`);\n }\n if (analysis.authConfig.authCheckEndpoint) {\n parts.push(`- Auth check endpoint: ${analysis.authConfig.authCheckEndpoint}`);\n }\n if (analysis.authConfig.apiBaseUrl) {\n parts.push(`- API base URL: ${analysis.authConfig.apiBaseUrl}`);\n }\n }\n\n parts.push(`\n## Required Output Format\n\nAnalyze the page code carefully. Look at:\n- Conditional rendering (if/else, ternary operators, switch statements)\n- State variables that control what is displayed\n- URL parameters or search params that affect the view\n- Authentication state checks\n- Data loading patterns\n\nThen generate mock data for **page-specific visual states** — not just generic success/error. For example:\n- A dashboard with tabs might have states: \"overview_tab\", \"readings_tab\", \"settings_tab\"\n- A page checking auth might have: \"authenticated_with_data\", \"authenticated_empty\", \"unauthenticated\"\n- A results page might have: \"results_found\", \"no_results\", \"invalid_id\"\n\nAlways include at least these base states:\n- One state with realistic populated data (the \"happy path\")\n- One state with empty/no data\n- One error state (API returns 500)\n\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" },\n \"stateVariants\": [\n {\n \"name\": \"descriptive_state_name\",\n \"description\": \"What this state represents visually\",\n \"apiMocks\": {\n \"METHOD /endpoint/path\": {\n \"status\": 200,\n \"body\": { ... },\n \"delay\": 0\n }\n }\n }\n ],\n \"authMock\": {\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nIMPORTANT:\n- Use the ACTUAL endpoint paths from the \"Actual API Endpoints\" section above if provided.\n- Each state variant should produce a VISUALLY DIFFERENT page render.\n- Generate at least 3-5 items in list/array responses for the happy path state.\n- Generate ONLY the JSON. No explanation, no markdown fences.`);\n\n return parts.join('\\n\\n');\n}\n","import type { PageAnalysis } from '../analysis/types.js';\nimport type { MockConfig, MockResponse, MockGeneratorOptions } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\n/**\n * New format: LLM returns state variants with per-state API mocks.\n */\ninterface LlmMockOutputV2 {\n routeParams?: Record<string, string>;\n stateVariants?: Array<{\n name: string;\n description?: string;\n apiMocks: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\n/**\n * Legacy format: per-endpoint states.\n */\ninterface LlmMockOutputV1 {\n routeParams?: Record<string, string>;\n apiEndpoints?: Array<{\n urlPattern: string;\n method: string;\n states: Record<string, { status: number; body: unknown; delay?: number }>;\n }>;\n authMock?: {\n cookies: Record<string, string>;\n authCheckEndpoint: string;\n authCheckResponse: { status: number; body: unknown };\n };\n}\n\ntype LlmMockOutput = LlmMockOutputV2 | LlmMockOutputV1;\n\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n let cleaned = content.trim();\n if (cleaned.startsWith('```')) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, '').replace(/\\n?```$/, '');\n }\n\n try {\n return JSON.parse(cleaned);\n } catch {\n const jsonMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n return JSON.parse(jsonMatch[0]);\n } catch {\n return null;\n }\n }\n return null;\n }\n}\n\n/**\n * Check if output uses the new V2 format (stateVariants).\n */\nfunction isV2Output(output: LlmMockOutput): output is LlmMockOutputV2 {\n return 'stateVariants' in output && Array.isArray((output as LlmMockOutputV2).stateVariants);\n}\n\n/**\n * Convert V2 (stateVariants) output to MockConfig[].\n */\nfunction convertV2ToMockConfigs(\n output: LlmMockOutputV2,\n analysis: PageAnalysis,\n): MockConfig[] {\n if (!output.stateVariants || output.stateVariants.length === 0) {\n return [];\n }\n\n return output.stateVariants.map(variant => {\n const apiMocks: Record<string, MockResponse> = {};\n for (const [pattern, mock] of Object.entries(variant.apiMocks)) {\n apiMocks[pattern] = {\n status: mock.status,\n body: mock.body,\n delay: mock.delay,\n };\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n return {\n stateName: variant.name,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n };\n });\n}\n\n/**\n * Convert V1 (per-endpoint states) output to MockConfig[].\n * Legacy format support.\n */\nfunction convertV1ToMockConfigs(\n output: LlmMockOutputV1,\n analysis: PageAnalysis,\n variants: string[],\n): MockConfig[] {\n const configs: MockConfig[] = [];\n\n for (const variant of variants) {\n const apiMocks: Record<string, MockResponse> = {};\n\n if (output.apiEndpoints) {\n for (const endpoint of output.apiEndpoints) {\n const stateData = endpoint.states[variant];\n if (stateData) {\n const key = `${endpoint.method} ${endpoint.urlPattern}`;\n apiMocks[key] = {\n status: stateData.status,\n body: stateData.body,\n delay: stateData.delay,\n };\n }\n }\n }\n\n let authMock: MockConfig['authMock'] = null;\n if (analysis.authConfig.hasAuth && output.authMock) {\n authMock = {\n cookies: output.authMock.cookies,\n authCheckResponse: {\n status: output.authMock.authCheckResponse.status,\n body: output.authMock.authCheckResponse.body,\n },\n };\n }\n\n configs.push({\n stateName: variant,\n apiMocks,\n authMock,\n routeParams: output.routeParams,\n });\n }\n\n return configs;\n}\n\n/**\n * Generate a fallback MockConfig when LLM fails or page has no API deps.\n */\nfunction generateFallbackConfigs(\n analysis: PageAnalysis,\n variants: string[],\n): MockConfig[] {\n return variants.map(variant => ({\n stateName: variant,\n apiMocks: {},\n authMock: analysis.authConfig.hasAuth\n ? {\n cookies: Object.fromEntries(\n analysis.authConfig.cookieNames.map(name => [name, 'mock_token_c2d']),\n ),\n authCheckResponse: variant === 'error'\n ? { status: 401, body: { detail: 'Unauthorized' } }\n : { status: 200, body: { id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User' } },\n }\n : null,\n routeParams: analysis.route.isDynamic\n ? Object.fromEntries(analysis.route.params.map(p => [p.name, 'sample-1']))\n : undefined,\n }));\n}\n\n/**\n * Generate mock data for a single page using an LLM.\n *\n * Returns one MockConfig per state variant (page-specific or fallback).\n */\nexport async function generateMocks(\n analysis: PageAnalysis,\n options: MockGeneratorOptions,\n): Promise<{ configs: MockConfig[]; tokenUsage: { input: number; output: number } }> {\n const variants = options.variants ?? ['success', 'empty', 'error', 'loading'];\n\n // If no API dependencies, just return fallback configs (no LLM call needed)\n if (!analysis.hasApiDependencies) {\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n\n const client = new LlmClient(options.apiKey, options.model);\n const userPrompt = buildUserPrompt(analysis);\n\n try {\n const response = await client.generate(SYSTEM_PROMPT, userPrompt);\n const parsed = parseLlmJson(response.content);\n\n if (!parsed) {\n console.warn(`[c2d] Failed to parse LLM response for ${analysis.route.urlPath}, using fallback`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n }\n\n let configs: MockConfig[];\n\n if (isV2Output(parsed)) {\n // New format: page-specific state variants\n configs = convertV2ToMockConfigs(parsed, analysis);\n } else {\n // Legacy format: per-endpoint states\n configs = convertV1ToMockConfigs(parsed, analysis, variants);\n }\n\n // Ensure we have at least one config\n if (configs.length === 0) {\n configs = generateFallbackConfigs(analysis, variants);\n }\n\n return {\n configs,\n tokenUsage: { input: response.inputTokens, output: response.outputTokens },\n };\n } catch (error) {\n console.warn(`[c2d] LLM call failed for ${analysis.route.urlPath}: ${error}`);\n return {\n configs: generateFallbackConfigs(analysis, variants),\n tokenUsage: { input: 0, output: 0 },\n };\n }\n}\n\n/**\n * Generate mocks for all analyzed pages.\n */\nexport async function generateAllMocks(\n analyses: PageAnalysis[],\n options: MockGeneratorOptions,\n): Promise<{\n results: Map<string, MockConfig[]>;\n totalTokens: { input: number; output: number };\n}> {\n const results = new Map<string, MockConfig[]>();\n const totalTokens = { input: 0, output: 0 };\n\n for (const analysis of analyses) {\n const { configs, tokenUsage } = await generateMocks(analysis, options);\n results.set(analysis.route.urlPath, configs);\n totalTokens.input += tokenUsage.input;\n totalTokens.output += tokenUsage.output;\n }\n\n return { results, totalTokens };\n}\n","import { chromium, type Browser, type BrowserContext, type Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { MockConfig, MockResponse } from '../mock/types.js';\nimport type { AuthConfig } from '../analysis/types.js';\nimport type { RouteInfo } from '../discovery/types.js';\nimport type {\n RenderResult,\n RenderTask,\n RenderManifest,\n ManifestRoute,\n PreRenderOptions,\n ViewportConfig,\n} from './types.js';\nimport { startDevServer, type DevServerHandle } from './dev-server.js';\nimport { inlineStylesAndCleanup } from './style-inliner.js';\nimport { captureInteractions, type InteractionResult } from './interaction-capturer.js';\nimport { matchMockUrl, isApiUrl } from './url-matcher.js';\n\nconst DEFAULT_CONCURRENCY = 3;\nconst DEFAULT_PAGE_TIMEOUT = 15000;\nconst DEFAULT_SETTLE_TIME = 1500;\nconst DEFAULT_VIEWPORT = { width: 1440, height: 900 };\n\n/**\n * Build the actual URL path for a route, substituting dynamic params.\n */\nfunction buildUrlPath(route: RouteInfo, mockConfig: MockConfig): string {\n let path = route.urlPath;\n if (route.isDynamic && mockConfig.routeParams) {\n for (const param of route.params) {\n const value = mockConfig.routeParams[param.name] || 'sample-1';\n path = path.replace(`:${param.name}`, value);\n // Also handle catch-all notation\n path = path.replace(`:${param.name}+`, value);\n path = path.replace(`:${param.name}*`, value);\n }\n }\n return path;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n * \"/\" → \"index\", \"/dashboard\" → \"dashboard\", \"/editor/:id\" → \"editor-_id\"\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Set up Playwright route interception for a page with the given mock config.\n */\nasync function setupMockInterception(\n page: Page,\n devServerUrl: string,\n mockConfig: MockConfig,\n authConfig: AuthConfig,\n): Promise<void> {\n // 1. Inject auth cookies if needed\n if (mockConfig.authMock) {\n const cookies = Object.entries(mockConfig.authMock.cookies).map(([name, value]) => ({\n name,\n value,\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n } else if (authConfig.hasAuth && authConfig.cookieNames.length > 0) {\n // Fallback: inject dummy cookies for detected auth\n const cookies = authConfig.cookieNames.map(name => ({\n name,\n value: 'c2d_mock_token',\n domain: new URL(devServerUrl).hostname,\n path: '/',\n }));\n await page.context().addCookies(cookies);\n }\n\n // 2. Inject localStorage for client-side auth (Zustand persist, etc.)\n if (authConfig.hasAuth) {\n const mockUser = mockConfig.authMock?.authCheckResponse?.body ?? {\n id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User',\n };\n const mockToken = 'c2d_mock_jwt_token';\n\n // Navigate to the page first to set localStorage on the correct origin\n await page.goto(devServerUrl, { waitUntil: 'commit', timeout: 10000 }).catch(() => {});\n\n // Inject common auth storage patterns\n await page.evaluate(`(() => {\n // Zustand persist pattern (auth-storage)\n const zustandState = {\n state: {\n user: ${JSON.stringify(mockUser)},\n tokens: { access: \"${mockToken}\", refresh: \"${mockToken}\" },\n isAuthenticated: true,\n isLoading: false,\n },\n version: 0,\n };\n localStorage.setItem('auth-storage', JSON.stringify(zustandState));\n\n // Common alternatives\n localStorage.setItem('token', '\"${mockToken}\"');\n localStorage.setItem('access_token', '\"${mockToken}\"');\n localStorage.setItem('user', JSON.stringify(${JSON.stringify(mockUser)}));\n })()`);\n }\n\n // 3. Build auth mock response for interception\n const authMockBody = mockConfig.authMock?.authCheckResponse\n ? JSON.stringify(mockConfig.authMock.authCheckResponse.body)\n : JSON.stringify({ id: 'mock_user', email: 'demo@c2d.dev', name: 'Demo User', email_verified: true, avatar_url: null, created_at: '2026-01-01T00:00:00Z' });\n\n // Common auth check URL patterns to always intercept\n const AUTH_PATTERNS = ['/auth/me', '/auth/session', '/api/auth/me', '/api/user/me', '/api/auth/session'];\n\n // 3. Intercept API calls\n await page.route('**/*', async (route) => {\n const request = route.request();\n const url = request.url();\n const method = request.method();\n\n // Always intercept auth check endpoints (common patterns + detected endpoint)\n const isAuthCheck = AUTH_PATTERNS.some(p => url.includes(p))\n || (authConfig.authCheckEndpoint && url.includes(authConfig.authCheckEndpoint));\n\n if (isAuthCheck) {\n const status = mockConfig.authMock?.authCheckResponse?.status ?? 200;\n return route.fulfill({\n status,\n contentType: 'application/json',\n body: authMockBody,\n });\n }\n\n // Check API mocks from AI-generated config\n for (const [pattern, mock] of Object.entries(mockConfig.apiMocks)) {\n if (matchMockUrl(url, method, pattern)) {\n if (mock.delay) await new Promise(r => setTimeout(r, mock.delay));\n return route.fulfill({\n status: mock.status,\n contentType: 'application/json',\n body: JSON.stringify(mock.body),\n });\n }\n }\n\n // If this looks like an API call (contains /api/ or goes to a known backend port),\n // return an empty success response instead of letting it fail against a non-existent backend\n if (isApiUrl(url)) {\n return route.fulfill({\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({ data: [], message: 'ok' }),\n });\n }\n\n // Pass through all other requests (static assets, etc.)\n return route.continue();\n });\n}\n\n/**\n * Render a single page in a specific state and capture HTML + screenshot.\n */\nasync function renderPage(\n context: BrowserContext,\n devServerUrl: string,\n task: RenderTask,\n outputDir: string,\n options: { pageTimeout: number; settleTime: number; captureInteractionStates?: boolean; maxInteractions?: number },\n viewport?: ViewportConfig,\n): Promise<RenderResult> {\n const { route, mockConfig, authConfig } = task;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Include viewport name in file paths to avoid collisions when rendering multiple viewports\n const filePrefix = viewport ? `${mockConfig.stateName}_${viewport.name}` : mockConfig.stateName;\n const htmlRelPath = join('renders', routeSlug, `${filePrefix}.html`);\n const pngRelPath = join('renders', routeSlug, `${filePrefix}.png`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n const pngAbsPath = join(outputDir, pngRelPath);\n\n const page = await context.newPage();\n\n // Override viewport size for this page if a specific viewport was requested\n if (viewport) {\n await page.setViewportSize({ width: viewport.width, height: viewport.height });\n }\n\n try {\n await setupMockInterception(page, devServerUrl, mockConfig, authConfig);\n\n const urlPath = buildUrlPath(route, mockConfig);\n const fullUrl = `${devServerUrl}${urlPath}`;\n\n await page.goto(fullUrl, {\n waitUntil: 'networkidle',\n timeout: options.pageTimeout,\n });\n\n // Extra settle time for React hydration\n await page.waitForTimeout(options.settleTime);\n\n // Inline all external stylesheets so HTML is self-contained\n await inlineStylesAndCleanup(page);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n // Capture screenshot\n await page.screenshot({ path: pngAbsPath, fullPage: true });\n\n // Capture interaction variants (only for success/empty states, not error/loading)\n const interactionStates = ['success', 'empty'];\n const shouldCapture = options.captureInteractionStates !== false\n && interactionStates.includes(mockConfig.stateName);\n\n let interactions: Array<{ description: string; htmlPath: string }> | undefined;\n\n if (shouldCapture) {\n // Reload before interaction capture to get a clean page with scripts intact\n await page.goto(fullUrl, { waitUntil: 'networkidle', timeout: options.pageTimeout });\n await page.waitForTimeout(options.settleTime);\n\n const interactionResults = await captureInteractions(\n page,\n fullUrl,\n route,\n mockConfig.stateName,\n outputDir,\n { maxInteractions: options.maxInteractions, settleTime: 500 },\n );\n\n const successful = interactionResults.filter(r => r.success);\n if (successful.length > 0) {\n interactions = successful.map(r => ({\n description: r.elementDescription,\n htmlPath: r.htmlPath,\n }));\n }\n }\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\n interactions,\n };\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n // Write an error placeholder HTML\n const errorHtml = `<!DOCTYPE html><html><body style=\"display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;color:#666;\">\n <div style=\"text-align:center\"><h2>Render Failed</h2><p>${route.urlPath} [${mockConfig.stateName}]</p><pre style=\"color:#c00\">${errorMsg}</pre></div>\n </body></html>`;\n await writeFile(htmlAbsPath, errorHtml, 'utf-8').catch(() => {});\n\n return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: false,\n error: errorMsg,\n viewportName: viewport?.name,\n };\n } finally {\n await page.close();\n }\n}\n\n/**\n * Process render tasks with limited concurrency.\n */\nasync function processWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T) => Promise<RenderResult>,\n onProgress?: (completed: number, total: number, result: RenderResult) => void,\n): Promise<RenderResult[]> {\n const results: RenderResult[] = [];\n const queue = [...items];\n const total = items.length;\n let completed = 0;\n\n async function worker() {\n while (queue.length > 0) {\n const item = queue.shift()!;\n const result = await fn(item);\n results.push(result);\n completed++;\n onProgress?.(completed, total, result);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n\n return results;\n}\n\n/**\n * Build the render manifest from results.\n */\nfunction buildManifest(\n results: RenderResult[],\n projectName: string,\n viewports?: ViewportConfig[],\n): RenderManifest {\n const routeMap = new Map<string, ManifestRoute>();\n\n // Build a lookup for viewport widths by name\n const viewportWidthMap = new Map<string, number>();\n if (viewports) {\n for (const vp of viewports) {\n viewportWidthMap.set(vp.name, vp.width);\n }\n }\n\n for (const result of results) {\n const key = result.route.urlPath;\n if (!routeMap.has(key)) {\n routeMap.set(key, {\n urlPath: result.route.urlPath,\n filePath: result.route.filePath,\n states: [],\n });\n }\n routeMap.get(key)!.states.push({\n name: result.viewportName\n ? `${result.stateName} (${result.viewportName})`\n : result.stateName,\n htmlPath: result.htmlPath,\n screenshotPath: result.screenshotPath,\n status: result.success ? 'ok' : 'error',\n error: result.error,\n viewport: result.viewportName,\n viewportWidth: result.viewportName\n ? viewportWidthMap.get(result.viewportName)\n : undefined,\n interactions: result.interactions,\n });\n }\n\n return {\n generatedAt: new Date().toISOString(),\n projectName,\n routes: [...routeMap.values()].sort((a, b) => a.urlPath.localeCompare(b.urlPath)),\n };\n}\n\n/**\n * Pre-render all pages with their mock configurations.\n *\n * This is the main entry point for the rendering pipeline:\n * 1. Start dev server (or use provided URL)\n * 2. Launch Playwright browser\n * 3. For each (route, state) pair: intercept APIs, navigate, capture\n * 4. Write manifest.json\n * 5. Clean up\n */\nexport async function preRenderPages(\n tasks: RenderTask[],\n options: PreRenderOptions,\n): Promise<{ results: RenderResult[]; manifest: RenderManifest }> {\n const {\n projectRoot,\n outputDir = join(projectRoot, '.c2d'),\n concurrency = DEFAULT_CONCURRENCY,\n pageTimeout = DEFAULT_PAGE_TIMEOUT,\n settleTime = DEFAULT_SETTLE_TIME,\n viewportWidth = DEFAULT_VIEWPORT.width,\n viewportHeight = DEFAULT_VIEWPORT.height,\n captureInteractions: captureInteractionStates = true,\n maxInteractions,\n } = options;\n\n // Resolve viewports: if explicit viewports array is provided use it,\n // otherwise fall back to the single viewport from viewportWidth/Height\n // (which themselves default to 1440x900).\n const viewports: ViewportConfig[] | undefined = options.viewports;\n const useMultiViewport = viewports && viewports.length > 0;\n\n // Create output directory\n await mkdir(outputDir, { recursive: true });\n\n // Start dev server\n let devServer: DevServerHandle | null = null;\n try {\n devServer = await startDevServer(projectRoot, {\n port: options.devServerPort,\n devServerUrl: options.devServerUrl,\n });\n\n // Launch browser\n const browser = await chromium.launch({ headless: true });\n const context = await browser.newContext({\n viewport: { width: viewportWidth, height: viewportHeight },\n });\n\n try {\n let results: RenderResult[];\n\n if (useMultiViewport) {\n // Expand tasks: each original task is rendered at each viewport\n const expandedItems: Array<{ task: RenderTask; viewport: ViewportConfig }> = [];\n for (const task of tasks) {\n for (const vp of viewports) {\n expandedItems.push({ task, viewport: vp });\n }\n }\n\n results = await processWithConcurrency(\n expandedItems,\n concurrency,\n ({ task, viewport: vp }) =>\n renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime, captureInteractionStates, maxInteractions }, vp),\n options.onProgress,\n );\n } else {\n // Single viewport — backward-compatible path (no viewportName in results)\n results = await processWithConcurrency(\n tasks,\n concurrency,\n (task) => renderPage(context, devServer!.url, task, outputDir, { pageTimeout, settleTime, captureInteractionStates, maxInteractions }),\n options.onProgress,\n );\n }\n\n // Read project name from package.json\n let projectName = 'unknown';\n try {\n const pkg = await import(join(projectRoot, 'package.json'), { with: { type: 'json' } });\n projectName = pkg.default?.name || 'unknown';\n } catch {\n // Can't read package.json — use fallback\n }\n\n // Build and write manifest\n const manifest = buildManifest(\n results,\n projectName,\n useMultiViewport ? viewports : undefined,\n );\n await writeFile(\n join(outputDir, 'manifest.json'),\n JSON.stringify(manifest, null, 2),\n 'utf-8',\n );\n\n return { results, manifest };\n } finally {\n await context.close();\n await browser.close();\n }\n } finally {\n if (devServer) {\n await devServer.stop();\n }\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createServer } from 'node:net';\n\n/**\n * Find a free port on the system.\n */\nexport async function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.listen(0, () => {\n const address = server.address();\n if (address && typeof address === 'object') {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not find free port')));\n }\n });\n server.on('error', reject);\n });\n}\n\n/**\n * Wait for a URL to become reachable.\n */\nasync function waitForUrl(url: string, timeoutMs: number = 30000): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(2000) });\n // Any response (even redirects) means the server is up\n if (response.status > 0) return;\n } catch {\n // Server not ready yet\n }\n await new Promise(r => setTimeout(r, 500));\n }\n throw new Error(`Dev server did not become ready at ${url} within ${timeoutMs}ms`);\n}\n\n/**\n * Detect the dev command for a project.\n */\nfunction detectDevCommand(projectRoot: string): { cmd: string; args: string[] } {\n if (existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'))) {\n return { cmd: 'npx', args: ['next', 'dev'] };\n }\n // Fallback to npm run dev\n return { cmd: 'npm', args: ['run', 'dev'] };\n}\n\nexport interface DevServerHandle {\n url: string;\n port: number;\n process: ChildProcess | null;\n stop: () => Promise<void>;\n}\n\n/**\n * Start a dev server for the target project.\n *\n * If devServerUrl is provided, uses that instead of starting a new server.\n */\nexport async function startDevServer(\n projectRoot: string,\n options?: { port?: number; devServerUrl?: string },\n): Promise<DevServerHandle> {\n // If a URL is provided, use it directly (user has server running)\n if (options?.devServerUrl) {\n await waitForUrl(options.devServerUrl, 10000);\n return {\n url: options.devServerUrl,\n port: 0,\n process: null,\n stop: async () => {},\n };\n }\n\n const port = options?.port ?? await findFreePort();\n const { cmd, args } = detectDevCommand(projectRoot);\n const fullArgs = [...args, '--port', String(port)];\n\n const child = spawn(cmd, fullArgs, {\n cwd: projectRoot,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: { ...process.env, PORT: String(port) },\n });\n\n const url = `http://localhost:${port}`;\n\n // Collect stderr for error reporting\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n // Handle early exit\n const exitPromise = new Promise<never>((_, reject) => {\n child.on('exit', (code) => {\n if (code !== null && code !== 0) {\n reject(new Error(`Dev server exited with code ${code}.\\n${stderr.slice(-500)}`));\n }\n });\n });\n\n // Wait for server to be ready or fail\n try {\n await Promise.race([\n waitForUrl(url, 60000),\n exitPromise,\n ]);\n } catch (err) {\n child.kill('SIGTERM');\n throw err;\n }\n\n return {\n url,\n port,\n process: child,\n stop: async () => {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n await new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n resolve();\n }, 5000);\n child.on('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n },\n };\n}\n","import type { Page } from 'playwright';\n\n/**\n * Inline all external stylesheets into <style> tags and remove <script> tags.\n *\n * This makes the captured HTML self-contained so it can be displayed\n * outside the dev server context. Shared by both the main render pipeline\n * and the interaction capturer.\n */\nexport async function inlineStylesAndCleanup(page: Page): Promise<void> {\n await page.evaluate(`(() => {\n const links = document.querySelectorAll('link[rel=\"stylesheet\"]');\n links.forEach(link => {\n try {\n const href = link.getAttribute('href');\n if (!href) return;\n for (const sheet of document.styleSheets) {\n if (sheet.href && sheet.href.includes(href.replace(/^\\\\//, ''))) {\n const rules = Array.from(sheet.cssRules).map(r => r.cssText).join('\\\\n');\n const style = document.createElement('style');\n style.textContent = rules;\n link.parentNode.replaceChild(style, link);\n break;\n }\n }\n } catch (e) {}\n });\n document.querySelectorAll('script').forEach(s => s.remove());\n })()`);\n}\n","import type { Page } from 'playwright';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { RouteInfo } from '../discovery/types.js';\nimport { inlineStylesAndCleanup } from './style-inliner.js';\n\n/**\n * Result of capturing a single interaction variant.\n */\nexport interface InteractionResult {\n /** Human-readable description, e.g. \"Tab: Settings\", \"Button: Open Modal\" */\n elementDescription: string;\n /** Relative path to captured HTML file */\n htmlPath: string;\n /** Whether the interaction capture succeeded */\n success: boolean;\n /** Error message if capture failed */\n error?: string;\n}\n\n/**\n * Serializable info about a clickable element found on the page.\n */\ninterface ClickableElement {\n /** CSS selector path to re-find the element */\n selector: string;\n /** Human-readable description */\n description: string;\n}\n\n/**\n * Slugify a URL path for use as a directory name.\n */\nfunction slugifyRoute(urlPath: string): string {\n if (urlPath === '/') return 'index';\n return urlPath\n .replace(/^\\//, '')\n .replace(/\\//g, '-')\n .replace(/:/g, '_')\n .replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * Find clickable interactive elements on the current page.\n *\n * Looks for tabs, buttons, and anchor-like elements, excluding\n * already-active, disabled, submit, and external link elements.\n * Uses a string-based evaluate to avoid DOM type issues in Node context.\n */\nasync function findClickableElements(\n page: Page,\n maxElements: number,\n): Promise<ClickableElement[]> {\n return page.evaluate(`((max) => {\n const selectors = [\n '[role=\"tab\"]:not([aria-selected=\"true\"]):not([aria-disabled=\"true\"])',\n '[role=\"button\"]:not([aria-disabled=\"true\"]):not([disabled])',\n 'button:not([disabled]):not([type=\"submit\"])',\n '[data-tab]:not(.active):not(.selected)',\n '.tab:not(.active):not(.selected)',\n 'a[href=\"#\"]:not(.active)',\n 'a[href^=\"#\"]:not([href=\"#\"]):not(.active)',\n ];\n\n const seen = new Set();\n const results = [];\n\n for (const sel of selectors) {\n if (results.length >= max) break;\n const elements = document.querySelectorAll(sel);\n\n for (const el of elements) {\n if (results.length >= max) break;\n if (seen.has(el)) continue;\n seen.add(el);\n\n const rect = el.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) continue;\n const style = window.getComputedStyle(el);\n if (style.display === 'none' || style.visibility === 'hidden') continue;\n\n if (el.tagName === 'A') {\n const href = el.getAttribute('href') || '';\n if (href.startsWith('http') || href.startsWith('//')) continue;\n }\n\n if (el.tagName === 'BUTTON' && el.type === 'submit') continue;\n\n const text = (el.textContent || '').trim().slice(0, 50);\n const ariaLabel = el.getAttribute('aria-label');\n const role = el.getAttribute('role');\n const tag = el.tagName.toLowerCase();\n\n let desc = '';\n if (role === 'tab') desc = 'Tab: ' + (ariaLabel || text || 'unnamed');\n else if (role === 'button') desc = 'Button: ' + (ariaLabel || text || 'unnamed');\n else if (tag === 'button') desc = 'Button: ' + (ariaLabel || text || 'unnamed');\n else desc = 'Clickable: ' + (ariaLabel || text || 'unnamed');\n\n let uniqueSelector = '';\n const id = el.getAttribute('id');\n if (id) {\n uniqueSelector = '#' + CSS.escape(id);\n } else {\n const dataTestId = el.getAttribute('data-testid');\n if (dataTestId) {\n uniqueSelector = '[data-testid=\"' + CSS.escape(dataTestId) + '\"]';\n } else {\n const allMatching = document.querySelectorAll(sel);\n const idx = Array.from(allMatching).indexOf(el);\n uniqueSelector = '__INDEX__' + sel + '__' + idx;\n }\n }\n\n results.push({ selector: uniqueSelector, description: desc });\n }\n }\n\n return results;\n })(${maxElements})`) as Promise<ClickableElement[]>;\n}\n\n/**\n * Capture interaction variants by clicking interactive elements on a rendered page.\n *\n * This function expects the page to already be rendered and navigated to the target URL.\n * It finds clickable elements, clicks each one, captures the resulting HTML,\n * then reloads the page to reset state before the next interaction.\n *\n * @param page - Already rendered Playwright page\n * @param pageUrl - The full URL to reload between interactions\n * @param route - Route info for file naming\n * @param stateName - State variant name (e.g. \"success\")\n * @param outputDir - Base output directory\n * @param options - Configuration options\n * @returns Array of interaction results\n */\nexport async function captureInteractions(\n page: Page,\n pageUrl: string,\n route: RouteInfo,\n stateName: string,\n outputDir: string,\n options?: { maxInteractions?: number; settleTime?: number },\n): Promise<InteractionResult[]> {\n const maxInteractions = options?.maxInteractions ?? 5;\n const settleTime = options?.settleTime ?? 500;\n const routeSlug = slugifyRoute(route.urlPath);\n const stateDir = join(outputDir, 'renders', routeSlug);\n await mkdir(stateDir, { recursive: true });\n\n // Find clickable elements\n const clickables = await findClickableElements(page, maxInteractions);\n if (clickables.length === 0) return [];\n\n const results: InteractionResult[] = [];\n\n for (let i = 0; i < clickables.length; i++) {\n const clickable = clickables[i];\n const htmlRelPath = join('renders', routeSlug, `${stateName}_interaction_${i}.html`);\n const htmlAbsPath = join(outputDir, htmlRelPath);\n\n try {\n // Re-find and click the element\n let clicked = false;\n\n if (clickable.selector.startsWith('__INDEX__')) {\n // Parse the fallback selector format: __INDEX__{selector}__{index}\n const parts = clickable.selector.slice('__INDEX__'.length);\n const lastUnderscoreIdx = parts.lastIndexOf('__');\n const sel = parts.slice(0, lastUnderscoreIdx);\n const idx = parseInt(parts.slice(lastUnderscoreIdx + 2), 10);\n\n const elements = await page.$$(sel);\n if (elements[idx]) {\n await elements[idx].click();\n clicked = true;\n }\n } else {\n const element = await page.$(clickable.selector);\n if (element) {\n await element.click();\n clicked = true;\n }\n }\n\n if (!clicked) {\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: false,\n error: 'Element not found on re-query',\n });\n continue;\n }\n\n // Wait for state change\n await page.waitForTimeout(settleTime);\n\n // Inline styles and clean up (same as main render pipeline)\n await inlineStylesAndCleanup(page);\n\n // Capture HTML\n const html = await page.content();\n await writeFile(htmlAbsPath, html, 'utf-8');\n\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: true,\n });\n } catch (err) {\n results.push({\n elementDescription: clickable.description,\n htmlPath: htmlRelPath,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n\n // Reset page state for next interaction by reloading\n try {\n await page.goto(pageUrl, { waitUntil: 'networkidle', timeout: 10000 });\n await page.waitForTimeout(settleTime);\n } catch {\n // If reload fails, remaining interactions will likely fail too\n break;\n }\n }\n\n return results;\n}\n","/**\n * Smart URL matching for API mock interception.\n *\n * Supports:\n * - Full path matching (exact after normalization)\n * - Suffix matching (mock \"/readings\" matches url \"/api/v1/readings\")\n * - Trailing slash normalization\n * - Param placeholders: {id}, :id, and * wildcards\n */\n\n/**\n * Check whether a request URL + method matches a mock pattern string.\n *\n * @param requestUrl - The full URL from the intercepted request (e.g. \"http://localhost:8000/api/v1/readings/\")\n * @param requestMethod - HTTP method of the request (e.g. \"GET\")\n * @param mockPattern - Pattern from the mock config (e.g. \"GET /readings\" or \"DELETE /readings/{id}\")\n * @returns true if the request matches the mock pattern\n */\nexport function matchMockUrl(requestUrl: string, requestMethod: string, mockPattern: string): boolean {\n const [mockMethod, ...pathParts] = mockPattern.split(' ');\n if (requestMethod !== mockMethod) return false;\n\n let mockPath = pathParts.join(' ');\n\n // Normalize: strip trailing slashes for comparison\n mockPath = mockPath.replace(/\\/+$/, '');\n const urlPath = new URL(requestUrl).pathname.replace(/\\/+$/, '');\n\n // Convert param placeholders to regex segments\n const regexStr = mockPath\n .replace(/\\{[^}]+\\}/g, '[^/]+')\n .replace(/\\*/g, '[^/]+')\n .replace(/:[a-zA-Z_]+/g, '[^/]+');\n\n // Strategy 1: Full path match\n const fullRegex = new RegExp('^' + regexStr.replace(/\\//g, '\\\\/') + '$');\n if (fullRegex.test(urlPath)) return true;\n\n // Strategy 2: Suffix match (last N segments)\n // e.g., mock \"/readings\" matches url \"/api/v1/readings\"\n const mockSegments = mockPath.split('/').filter(Boolean);\n const urlSegments = urlPath.split('/').filter(Boolean);\n\n if (mockSegments.length >= 1 && urlSegments.length >= mockSegments.length) {\n const urlSuffix = urlSegments.slice(-mockSegments.length);\n const match = mockSegments.every((seg, i) => {\n if (seg.startsWith('{') || seg.startsWith(':') || seg === '*') return true;\n return seg === urlSuffix[i];\n });\n if (match) return true;\n }\n\n return false;\n}\n\n/**\n * Check whether a URL looks like an API call that should be intercepted\n * even if no specific mock pattern matched.\n */\nexport function isApiUrl(url: string): boolean {\n return url.includes('/api/') || url.includes(':8000') || url.includes(':3000/api');\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport sirv from 'sirv';\nimport { handleApiRequest } from './api-routes.js';\n\n/**\n * Options for starting the canvas server.\n */\nexport interface CanvasServerOptions {\n /** Port to listen on (default: 4800) */\n port: number;\n /** Path to the built canvas app directory */\n canvasDir: string;\n /** Path to the .c2d/ output directory */\n c2dDir: string;\n /** Path to the target project root (for serving public/ assets) */\n projectRoot?: string;\n}\n\nconst MAX_PORT_ATTEMPTS = 10;\n\n/**\n * Try to listen on a port. Returns a promise that resolves on success\n * or rejects with the error.\n */\nfunction tryListen(\n requestHandler: (req: IncomingMessage, res: ServerResponse) => void,\n port: number,\n): Promise<{ url: string; port: number; close: () => Promise<void> }> {\n return new Promise((resolve, reject) => {\n const server = createServer(requestHandler);\n server.once('error', reject);\n server.listen(port, () => {\n const actualPort = (server.address() as { port: number }).port;\n resolve({\n url: `http://localhost:${actualPort}`,\n port: actualPort,\n close: () =>\n new Promise<void>((resolveClose, rejectClose) => {\n server.close((err) => {\n if (err) rejectClose(err);\n else resolveClose();\n });\n }),\n });\n });\n });\n}\n\n/**\n * Start the canvas server that serves:\n * 1. API endpoints under /api/\n * 2. Pre-rendered files from .c2d/renders/ under /renders/\n * 3. Canvas app static assets (SPA fallback) for everything else\n *\n * If the default port is in use, tries up to 10 consecutive ports.\n */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir, projectRoot } = options;\n\n // Static file handlers\n const canvasHandler = sirv(canvasDir, { single: true, dev: true });\n const rendersDir = join(c2dDir, 'renders');\n const rendersHandler = sirv(rendersDir, { dev: true });\n\n // Serve target project's public/ folder for static assets (images, fonts, etc.)\n const publicDir = projectRoot ? join(projectRoot, 'public') : null;\n const publicHandler = publicDir && existsSync(publicDir)\n ? sirv(publicDir, { dev: true })\n : null;\n\n // Request handler\n const requestHandler = async (req: IncomingMessage, res: ServerResponse) => {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n // CORS headers on all responses\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n // Handle CORS preflight\n if (method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n // API routes\n if (url.startsWith('/api/')) {\n try {\n const handled = await handleApiRequest(req, res, c2dDir);\n if (!handled) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Not found' }));\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Internal server error';\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: message }));\n }\n return;\n }\n\n // Renders (pre-rendered HTML/screenshots)\n if (url.startsWith('/renders/')) {\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\n });\n return;\n }\n\n // Try project's public/ folder (images, fonts, icons, etc.)\n if (publicHandler) {\n publicHandler(req, res, () => {\n // Not found in public/ — fall through to canvas SPA\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n });\n return;\n }\n\n // Canvas app (SPA with fallback to index.html)\n canvasHandler(req, res, () => {\n res.writeHead(404);\n res.end('Not found');\n });\n };\n\n // Try ports starting from the configured port\n for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {\n const tryPort = port + attempt;\n try {\n return await tryListen(requestHandler, tryPort);\n } catch (err: any) {\n if (err.code === 'EADDRINUSE' && attempt < MAX_PORT_ATTEMPTS - 1) {\n continue;\n }\n throw err;\n }\n }\n\n throw new Error(`Could not find an available port (tried ${port}-${port + MAX_PORT_ATTEMPTS - 1})`);\n}\n","import { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/**\n * A single pen stroke on the drawing canvas.\n */\nexport interface DrawingStroke {\n points: { x: number; y: number }[];\n color: string;\n width: number;\n}\n\n/**\n * A comment pinned to a canvas coordinate.\n */\nexport interface Comment {\n id: string;\n x: number;\n y: number;\n text: string;\n author: string;\n timestamp: string;\n}\n\n/**\n * Handle API requests under the /api/ prefix.\n *\n * Returns true if the request was handled, false otherwise.\n */\nexport async function handleApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<boolean> {\n const url = req.url ?? '/';\n const method = req.method ?? 'GET';\n\n if (url === '/api/manifest' && method === 'GET') {\n await handleGetManifest(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'GET') {\n await handleGetComments(res, c2dDir);\n return true;\n }\n\n if (url === '/api/comments' && method === 'POST') {\n await handlePostComment(req, res, c2dDir);\n return true;\n }\n\n const deleteMatch = url.match(/^\\/api\\/comments\\/(.+)$/);\n if (deleteMatch && method === 'DELETE') {\n await handleDeleteComment(res, c2dDir, deleteMatch[1]);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'GET') {\n await handleGetDrawings(res, c2dDir);\n return true;\n }\n\n if (url === '/api/drawings' && method === 'POST') {\n await handlePostDrawings(req, res, c2dDir);\n return true;\n }\n\n return false;\n}\n\n// --- Handlers ---\n\nasync function handleGetManifest(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const manifestPath = join(c2dDir, 'manifest.json');\n if (!existsSync(manifestPath)) {\n sendJson(res, 404, { error: 'manifest.json not found' });\n return;\n }\n const data = await readFile(manifestPath, 'utf-8');\n sendRawJson(res, 200, data);\n}\n\nasync function handleGetComments(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n sendJson(res, 200, comments);\n}\n\nasync function handlePostComment(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!isValidCommentInput(parsed)) {\n sendJson(res, 400, { error: 'Missing required fields: x, y, text, author' });\n return;\n }\n\n const comment: Comment = {\n id: randomUUID(),\n x: parsed.x,\n y: parsed.y,\n text: parsed.text,\n author: parsed.author,\n timestamp: new Date().toISOString(),\n };\n\n const comments = await loadComments(c2dDir);\n comments.push(comment);\n await saveComments(c2dDir, comments);\n sendJson(res, 201, comment);\n}\n\nasync function handleDeleteComment(\n res: ServerResponse,\n c2dDir: string,\n id: string,\n): Promise<void> {\n const comments = await loadComments(c2dDir);\n const index = comments.findIndex(c => c.id === id);\n if (index === -1) {\n sendJson(res, 404, { error: 'Comment not found' });\n return;\n }\n comments.splice(index, 1);\n await saveComments(c2dDir, comments);\n sendJson(res, 200, { ok: true });\n}\n\n// --- Drawing Handlers ---\n\nasync function handleGetDrawings(\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const drawings = await loadDrawings(c2dDir);\n sendJson(res, 200, drawings);\n}\n\nasync function handlePostDrawings(\n req: IncomingMessage,\n res: ServerResponse,\n c2dDir: string,\n): Promise<void> {\n const body = await readRequestBody(req);\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n sendJson(res, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!Array.isArray(parsed)) {\n sendJson(res, 400, { error: 'Body must be an array of strokes' });\n return;\n }\n\n await saveDrawings(c2dDir, parsed as DrawingStroke[]);\n sendJson(res, 200, { ok: true });\n}\n\nasync function loadDrawings(c2dDir: string): Promise<DrawingStroke[]> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n if (!existsSync(drawingsPath)) {\n return [];\n }\n const data = await readFile(drawingsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveDrawings(c2dDir: string, drawings: DrawingStroke[]): Promise<void> {\n const drawingsPath = join(c2dDir, 'drawings.json');\n const dir = dirname(drawingsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(drawingsPath, JSON.stringify(drawings, null, 2), 'utf-8');\n}\n\n// --- Helpers ---\n\nfunction isValidCommentInput(\n value: unknown,\n): value is { x: number; y: number; text: string; author: string } {\n if (typeof value !== 'object' || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.x === 'number' &&\n typeof obj.y === 'number' &&\n typeof obj.text === 'string' &&\n typeof obj.author === 'string'\n );\n}\n\nasync function loadComments(c2dDir: string): Promise<Comment[]> {\n const commentsPath = join(c2dDir, 'comments.json');\n if (!existsSync(commentsPath)) {\n return [];\n }\n const data = await readFile(commentsPath, 'utf-8');\n try {\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\nasync function saveComments(c2dDir: string, comments: Comment[]): Promise<void> {\n const commentsPath = join(c2dDir, 'comments.json');\n const dir = dirname(commentsPath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n await writeFile(commentsPath, JSON.stringify(comments, null, 2), 'utf-8');\n}\n\nfunction readRequestBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\n req.on('error', reject);\n });\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n const body = JSON.stringify(data);\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(body);\n}\n\nfunction sendRawJson(res: ServerResponse, status: number, jsonString: string): void {\n res.writeHead(status, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n });\n res.end(jsonString);\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface VibeCanvasConfig {\n apiKey: string;\n port: number;\n excludeRoutes: string[];\n devServerUrl?: string;\n devServerCommand?: string;\n}\n\nconst DEFAULT_PORT = 4800;\n\n/**\n * Load configuration from environment variables and optional config file.\n */\nexport async function loadConfig(projectRoot: string): Promise<VibeCanvasConfig> {\n let fileConfig: Partial<VibeCanvasConfig> = {};\n\n // Try to load c2d.config.js\n const configPath = join(projectRoot, 'c2d.config.js');\n if (existsSync(configPath)) {\n try {\n const mod = await import(configPath);\n fileConfig = mod.default || mod;\n } catch {\n // Config file exists but can't be loaded — use defaults\n }\n }\n\n const apiKey = process.env.C2D_API_KEY || fileConfig.apiKey || '';\n\n return {\n apiKey,\n port: fileConfig.port || Number(process.env.C2D_PORT) || DEFAULT_PORT,\n excludeRoutes: fileConfig.excludeRoutes || [],\n devServerUrl: fileConfig.devServerUrl || process.env.C2D_DEV_SERVER_URL,\n devServerCommand: fileConfig.devServerCommand,\n };\n}\n\nexport interface DetectedProject {\n isSupported: boolean;\n projectType: 'nextjs-app' | 'nextjs-pages' | 'react-router' | 'unknown';\n appDir: string | null;\n projectRoot: string;\n projectName: string;\n}\n\n/**\n * Detect the project type and routing convention.\n *\n * Supports Next.js (App Router & Pages Router) and React Router (Vite).\n */\nexport async function detectProject(projectRoot: string): Promise<DetectedProject> {\n let projectName = 'unknown';\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n projectName = pkg.name || 'unknown';\n } catch {\n // No package.json\n }\n\n // Check for Next.js first\n const hasNextConfig =\n existsSync(join(projectRoot, 'next.config.ts')) ||\n existsSync(join(projectRoot, 'next.config.js')) ||\n existsSync(join(projectRoot, 'next.config.mjs'));\n\n if (hasNextConfig) {\n // Check App Router first, then Pages Router as fallback\n // Priority: app/ → src/app/ → pages/ → src/pages/\n let appDir = join(projectRoot, 'app');\n let hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'app');\n hasAppDir = existsSync(appDir);\n }\n\n if (hasAppDir) {\n return { isSupported: true, projectType: 'nextjs-app', appDir, projectRoot, projectName };\n }\n\n appDir = join(projectRoot, 'pages');\n hasAppDir = existsSync(appDir);\n if (!hasAppDir) {\n appDir = join(projectRoot, 'src', 'pages');\n hasAppDir = existsSync(appDir);\n }\n\n if (hasAppDir) {\n return { isSupported: true, projectType: 'nextjs-pages', appDir, projectRoot, projectName };\n }\n\n // Has next config but no recognized directory\n return { isSupported: false, projectType: 'unknown', appDir: null, projectRoot, projectName };\n }\n\n // Check for React Router (commonly used with Vite)\n try {\n const pkg = JSON.parse(await readFile(join(projectRoot, 'package.json'), 'utf-8'));\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if ('react-router-dom' in deps || 'react-router' in deps) {\n return { isSupported: true, projectType: 'react-router', appDir: null, projectRoot, projectName };\n }\n } catch {\n // No package.json or can't parse\n }\n\n return { isSupported: false, projectType: 'unknown', appDir: null, projectRoot, projectName };\n}\n\n/**\n * Detect if the current directory is a Next.js App Router project.\n * @deprecated Use `detectProject` instead, which also supports React Router.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\n const result = await detectProject(projectRoot);\n return {\n isNextJs: result.projectType === 'nextjs-app' || result.projectType === 'nextjs-pages',\n appDir: result.appDir,\n projectName: result.projectName,\n };\n}\n","/**\n * Simple console progress utilities for the CLI.\n */\n\nconst COLORS = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n red: '\\x1b[31m',\n cyan: '\\x1b[36m',\n};\n\nexport function log(message: string): void {\n console.log(`${COLORS.dim}[c2d]${COLORS.reset} ${message}`);\n}\n\nexport function success(message: string): void {\n console.log(`${COLORS.green} ✓${COLORS.reset} ${message}`);\n}\n\nexport function warn(message: string): void {\n console.log(`${COLORS.yellow} ⚠${COLORS.reset} ${message}`);\n}\n\nexport function error(message: string): void {\n console.error(`${COLORS.red} ✗${COLORS.reset} ${message}`);\n}\n\nexport function header(message: string): void {\n console.log(`\\n${COLORS.bold}${COLORS.cyan}${message}${COLORS.reset}`);\n}\n\nexport function step(current: number, total: number, message: string): void {\n console.log(`${COLORS.dim} [${current}/${total}]${COLORS.reset} ${message}`);\n}\n\nexport function banner(): void {\n console.log(`\n${COLORS.bold}${COLORS.cyan} Code to Design${COLORS.reset} ${COLORS.dim}v0.1.0${COLORS.reset}\n${COLORS.dim} AI-powered UI review canvas${COLORS.reset}\n`);\n}\n"],"mappings":"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","names":["join","mkdir","existsSync","routes","readFile","join","existsSync","readFile","join","join","existsSync","readFile","error","mkdir","writeFile","join","existsSync","join","resolve","join","join","slugifyRoute","join","mkdir","writeFile","createServer","join","existsSync","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","resolve","createServer","join","existsSync","existsSync","readFile","join","join","existsSync","scanDir","mkdir","r","resolve","dirname","writeFile"]}