code-to-design 0.1.1 → 0.1.2

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.
@@ -778,14 +778,18 @@ async function renderPage(context, devServerUrl, task, outputDir, options, viewp
778
778
  await page.close();
779
779
  }
780
780
  }
781
- async function processWithConcurrency(items, concurrency, fn) {
781
+ async function processWithConcurrency(items, concurrency, fn, onProgress) {
782
782
  const results = [];
783
783
  const queue = [...items];
784
+ const total = items.length;
785
+ let completed = 0;
784
786
  async function worker() {
785
787
  while (queue.length > 0) {
786
788
  const item = queue.shift();
787
789
  const result = await fn(item);
788
790
  results.push(result);
791
+ completed++;
792
+ onProgress?.(completed, total, result);
789
793
  }
790
794
  }
791
795
  const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());
@@ -860,13 +864,15 @@ async function preRenderPages(tasks, options) {
860
864
  results = await processWithConcurrency(
861
865
  expandedItems,
862
866
  concurrency,
863
- ({ task, viewport: vp }) => renderPage(context, devServer.url, task, outputDir, { pageTimeout, settleTime }, vp)
867
+ ({ task, viewport: vp }) => renderPage(context, devServer.url, task, outputDir, { pageTimeout, settleTime }, vp),
868
+ options.onProgress
864
869
  );
865
870
  } else {
866
871
  results = await processWithConcurrency(
867
872
  tasks,
868
873
  concurrency,
869
- (task) => renderPage(context, devServer.url, task, outputDir, { pageTimeout, settleTime })
874
+ (task) => renderPage(context, devServer.url, task, outputDir, { pageTimeout, settleTime }),
875
+ options.onProgress
870
876
  );
871
877
  }
872
878
  let projectName = "unknown";
@@ -1301,7 +1307,14 @@ async function runScan(options) {
1301
1307
  const { results, manifest } = await preRenderPages(renderTasks, {
1302
1308
  projectRoot,
1303
1309
  outputDir: c2dDir,
1304
- devServerUrl: config.devServerUrl
1310
+ devServerUrl: config.devServerUrl,
1311
+ onProgress: (completed, total, result) => {
1312
+ const pct = Math.round(completed / total * 100);
1313
+ const icon = result.success ? "\u2713" : "\u2717";
1314
+ const label = `${result.route.urlPath} [${result.stateName}]`;
1315
+ process.stdout.write(`\r ${icon} ${completed}/${total} (${pct}%) ${label}${"".padEnd(20)}`);
1316
+ if (completed === total) process.stdout.write("\n");
1317
+ }
1305
1318
  });
1306
1319
  const successCount = results.filter((r) => r.success).length;
1307
1320
  const failCount = results.filter((r) => !r.success).length;
@@ -1472,4 +1485,4 @@ export {
1472
1485
  detectNextJsProject,
1473
1486
  runScan
1474
1487
  };
1475
- //# sourceMappingURL=chunk-N3DCNBUN.js.map
1488
+ //# sourceMappingURL=chunk-VOK3YCWT.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/mock/types.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","../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, detectNextJsProject } 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 detectNextJsProject(projectRoot);\n\n if (!project.isNextJs) {\n ui.error('Not a Next.js project (no next.config.ts/js/mjs found).');\n ui.log('Code to Design currently supports Next.js App Router projects only.');\n process.exit(1);\n }\n\n if (!project.appDir) {\n ui.error('No app/ directory found. Code to Design requires Next.js App Router.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName}`);\n ui.success(`App directory: ${project.appDir}`);\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);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const routes = await scanRoutes({ appDir: project.appDir });\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);\n watchAndRerender(projectRoot, project.appDir!, c2dDir, config);\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);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean): 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 });\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): 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 });\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): 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 });\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, 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/**\n * Check if a filename is a 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 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 * Scan a Next.js App Router `app/` directory and extract all renderable routes.\n *\n * Follows Next.js conventions:\n * - page.{js,jsx,ts,tsx} files define renderable routes\n * - Route groups (name) are stripped from URLs\n * - Private folders _name are skipped\n * - Parallel routes @slot are skipped\n * - Intercepting routes (.) are skipped\n * - Dynamic routes [param] are included with parameter metadata\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir } = options;\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 const routes = 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 } from './types.js';\nimport { detectAuth } from './auth-detector.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 * 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 // 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 };\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","/**\n * A single mock response for an API endpoint.\n */\nexport interface MockResponse {\n /** HTTP status code */\n status: number;\n /** Response body as JSON-serializable data */\n body: unknown;\n /** Optional delay in milliseconds before responding */\n delay?: number;\n}\n\n/**\n * A complete mock configuration for rendering a page in a specific state.\n */\nexport interface MockConfig {\n /** State variant name (e.g., \"success\", \"error\", \"empty\", \"loading\") */\n stateName: string;\n /** Map of URL patterns to mock responses */\n apiMocks: Record<string, MockResponse>;\n /** Mock user data for auth, if auth is required */\n authMock: {\n /** Cookies to inject (e.g., { access_token: \"mock_token\" }) */\n cookies: Record<string, string>;\n /** Auth check endpoint mock response */\n authCheckResponse: MockResponse | null;\n } | null;\n /** Sample route parameters for dynamic routes */\n routeParams?: Record<string, string>;\n}\n\n/**\n * State variants to generate for each page.\n */\nexport type StateVariant = 'success' | 'empty' | 'error' | 'loading';\n\nexport const ALL_STATE_VARIANTS: StateVariant[] = ['success', 'empty', 'error', 'loading'];\n\n/**\n * Options for mock generation.\n */\nexport interface MockGeneratorOptions {\n /** Anthropic API key */\n apiKey: string;\n /** Model to use (default: claude-sonnet-4-20250514) */\n model?: string;\n /** State variants to generate (default: all) */\n variants?: StateVariant[];\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 VibeCanvas.\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.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces 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. For each API endpoint, generate mock responses for these state variants:\n - \"success\": realistic data with multiple items\n - \"empty\": empty collections, zero counts\n - \"error\": API returns HTTP 500 with error message\n - \"loading\": same as success but with a 3000ms delay\n5. Include auth mock data if the page requires authentication.\n6. 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 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\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" }, // only if dynamic route\n \"apiEndpoints\": [\n {\n \"urlPattern\": \"/api/endpoint\", // the URL path pattern to intercept\n \"method\": \"GET\", // HTTP method\n \"states\": {\n \"success\": { \"status\": 200, \"body\": { ... } },\n \"empty\": { \"status\": 200, \"body\": { ... } },\n \"error\": { \"status\": 500, \"body\": { \"detail\": \"Internal server error\" } },\n \"loading\": { \"status\": 200, \"body\": { ... }, \"delay\": 3000 }\n }\n }\n ],\n \"authMock\": { // only if auth is required\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nGenerate 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, StateVariant, MockGeneratorOptions } from './types.js';\nimport { ALL_STATE_VARIANTS } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\ninterface LlmMockOutput {\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\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n // Strip markdown code fences if present\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 // Try to find JSON object in the response\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 * Convert LLM output into MockConfig[] (one per state variant).\n */\nfunction convertToMockConfigs(\n output: LlmMockOutput,\n analysis: PageAnalysis,\n variants: StateVariant[],\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: StateVariant[],\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 requested state variant.\n * Falls back to empty mocks if:\n * - The page has no API dependencies\n * - LLM returns invalid data\n * - LLM call fails\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 ?? ALL_STATE_VARIANTS;\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 const configs = convertToMockConfigs(parsed, analysis, variants);\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';\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. 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 // Pattern format: \"GET /api/reports\" or \"DELETE /api/reports/{id}\"\n const [mockMethod, ...pathParts] = pattern.split(' ');\n let mockPath = pathParts.join(' ');\n // Convert {param} placeholders to match any value\n mockPath = mockPath.replace(/\\{[^}]+\\}/g, '[^/]+');\n // Also handle * wildcards\n mockPath = mockPath.replace(/\\*/g, '[^/]+');\n\n const pathRegex = new RegExp(mockPath.replace(/\\//g, '\\\\/'));\n if (method === mockMethod && pathRegex.test(url)) {\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 // Pass through all other requests\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 },\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 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 // 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 return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\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 });\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 } = 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 }, 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 }),\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 { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\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}\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 */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir } = 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 const server = createServer(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 // Strip /renders prefix so sirv serves from the renders directory root\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n // If renders handler doesn't find the file, 404\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\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 return new Promise((resolve, reject) => {\n server.on('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","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\n/**\n * Detect if the current directory is a Next.js App Router project.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\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 // Check both app/ and src/app/ (common Next.js structures)\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 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 return {\n isNextJs: hasNextConfig,\n appDir: hasAppDir ? appDir : null,\n 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","readFile","join","existsSync","join","join","existsSync","readFile","error","join","existsSync","join","resolve","join","createServer","join","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","join","createServer","resolve","existsSync","readFile","join","join","existsSync","mkdir","r","resolve","dirname","writeFile"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runScan
3
- } from "../chunk-N3DCNBUN.js";
3
+ } from "../chunk-VOK3YCWT.js";
4
4
  export {
5
5
  runScan
6
6
  };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  loadConfig,
4
4
  runScan,
5
5
  startCanvasServer
6
- } from "./chunk-N3DCNBUN.js";
6
+ } from "./chunk-VOK3YCWT.js";
7
7
 
8
8
  // src/version.ts
9
9
  var version = "0.1.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-to-design",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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/mock/types.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","../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, detectNextJsProject } 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 detectNextJsProject(projectRoot);\n\n if (!project.isNextJs) {\n ui.error('Not a Next.js project (no next.config.ts/js/mjs found).');\n ui.log('Code to Design currently supports Next.js App Router projects only.');\n process.exit(1);\n }\n\n if (!project.appDir) {\n ui.error('No app/ directory found. Code to Design requires Next.js App Router.');\n process.exit(1);\n }\n\n ui.success(`Project: ${project.projectName}`);\n ui.success(`App directory: ${project.appDir}`);\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);\n return;\n }\n\n // Step 2: Discover routes\n ui.header('Discovering routes...');\n const routes = await scanRoutes({ appDir: project.appDir });\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 });\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);\n watchAndRerender(projectRoot, project.appDir!, c2dDir, config);\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);\n }\n}\n\nasync function startServer(c2dDir: string, port: number, open: boolean): 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 });\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): 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 });\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): 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 });\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, 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/**\n * Check if a filename is a 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 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 * Scan a Next.js App Router `app/` directory and extract all renderable routes.\n *\n * Follows Next.js conventions:\n * - page.{js,jsx,ts,tsx} files define renderable routes\n * - Route groups (name) are stripped from URLs\n * - Private folders _name are skipped\n * - Parallel routes @slot are skipped\n * - Intercepting routes (.) are skipped\n * - Dynamic routes [param] are included with parameter metadata\n */\nexport async function scanRoutes(options: ScanOptions): Promise<RouteInfo[]> {\n const { appDir } = options;\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 const routes = 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 } from './types.js';\nimport { detectAuth } from './auth-detector.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 * 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 // 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 };\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","/**\n * A single mock response for an API endpoint.\n */\nexport interface MockResponse {\n /** HTTP status code */\n status: number;\n /** Response body as JSON-serializable data */\n body: unknown;\n /** Optional delay in milliseconds before responding */\n delay?: number;\n}\n\n/**\n * A complete mock configuration for rendering a page in a specific state.\n */\nexport interface MockConfig {\n /** State variant name (e.g., \"success\", \"error\", \"empty\", \"loading\") */\n stateName: string;\n /** Map of URL patterns to mock responses */\n apiMocks: Record<string, MockResponse>;\n /** Mock user data for auth, if auth is required */\n authMock: {\n /** Cookies to inject (e.g., { access_token: \"mock_token\" }) */\n cookies: Record<string, string>;\n /** Auth check endpoint mock response */\n authCheckResponse: MockResponse | null;\n } | null;\n /** Sample route parameters for dynamic routes */\n routeParams?: Record<string, string>;\n}\n\n/**\n * State variants to generate for each page.\n */\nexport type StateVariant = 'success' | 'empty' | 'error' | 'loading';\n\nexport const ALL_STATE_VARIANTS: StateVariant[] = ['success', 'empty', 'error', 'loading'];\n\n/**\n * Options for mock generation.\n */\nexport interface MockGeneratorOptions {\n /** Anthropic API key */\n apiKey: string;\n /** Model to use (default: claude-sonnet-4-20250514) */\n model?: string;\n /** State variants to generate (default: all) */\n variants?: StateVariant[];\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 VibeCanvas.\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.\n\nRules:\n1. Output ONLY valid JSON — no markdown, no code fences, no explanation.\n2. Mock data must match the TypeScript interfaces 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. For each API endpoint, generate mock responses for these state variants:\n - \"success\": realistic data with multiple items\n - \"empty\": empty collections, zero counts\n - \"error\": API returns HTTP 500 with error message\n - \"loading\": same as success but with a 3000ms delay\n5. Include auth mock data if the page requires authentication.\n6. 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 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\nReturn a JSON object with this exact structure:\n{\n \"routeParams\": { \"paramName\": \"sampleValue\" }, // only if dynamic route\n \"apiEndpoints\": [\n {\n \"urlPattern\": \"/api/endpoint\", // the URL path pattern to intercept\n \"method\": \"GET\", // HTTP method\n \"states\": {\n \"success\": { \"status\": 200, \"body\": { ... } },\n \"empty\": { \"status\": 200, \"body\": { ... } },\n \"error\": { \"status\": 500, \"body\": { \"detail\": \"Internal server error\" } },\n \"loading\": { \"status\": 200, \"body\": { ... }, \"delay\": 3000 }\n }\n }\n ],\n \"authMock\": { // only if auth is required\n \"cookies\": { \"cookie_name\": \"mock_value\" },\n \"authCheckEndpoint\": \"/auth/me\",\n \"authCheckResponse\": { \"status\": 200, \"body\": { ... } }\n }\n}\n\nGenerate 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, StateVariant, MockGeneratorOptions } from './types.js';\nimport { ALL_STATE_VARIANTS } from './types.js';\nimport { LlmClient } from './llm-client.js';\nimport { SYSTEM_PROMPT, buildUserPrompt } from './prompt-templates.js';\n\ninterface LlmMockOutput {\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\n/**\n * Parse the LLM response as JSON, handling common formatting issues.\n */\nfunction parseLlmJson(content: string): LlmMockOutput | null {\n // Strip markdown code fences if present\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 // Try to find JSON object in the response\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 * Convert LLM output into MockConfig[] (one per state variant).\n */\nfunction convertToMockConfigs(\n output: LlmMockOutput,\n analysis: PageAnalysis,\n variants: StateVariant[],\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: StateVariant[],\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 requested state variant.\n * Falls back to empty mocks if:\n * - The page has no API dependencies\n * - LLM returns invalid data\n * - LLM call fails\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 ?? ALL_STATE_VARIANTS;\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 const configs = convertToMockConfigs(parsed, analysis, variants);\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';\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. 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 // Pattern format: \"GET /api/reports\" or \"DELETE /api/reports/{id}\"\n const [mockMethod, ...pathParts] = pattern.split(' ');\n let mockPath = pathParts.join(' ');\n // Convert {param} placeholders to match any value\n mockPath = mockPath.replace(/\\{[^}]+\\}/g, '[^/]+');\n // Also handle * wildcards\n mockPath = mockPath.replace(/\\*/g, '[^/]+');\n\n const pathRegex = new RegExp(mockPath.replace(/\\//g, '\\\\/'));\n if (method === mockMethod && pathRegex.test(url)) {\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 // Pass through all other requests\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 },\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 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 // 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 return {\n route,\n stateName: mockConfig.stateName,\n htmlPath: htmlRelPath,\n screenshotPath: pngRelPath,\n success: true,\n viewportName: viewport?.name,\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): Promise<RenderResult[]> {\n const results: RenderResult[] = [];\n const queue = [...items];\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 }\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 });\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 } = 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 }, vp),\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 }),\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 { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\nimport { join } from 'node:path';\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}\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 */\nexport async function startCanvasServer(options: CanvasServerOptions): Promise<{\n url: string;\n port: number;\n close: () => Promise<void>;\n}> {\n const { port = 4800, canvasDir, c2dDir } = 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 const server = createServer(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 // Strip /renders prefix so sirv serves from the renders directory root\n req.url = url.slice('/renders'.length) || '/';\n rendersHandler(req, res, () => {\n // If renders handler doesn't find the file, 404\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Render not found' }));\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 return new Promise((resolve, reject) => {\n server.on('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","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\n/**\n * Detect if the current directory is a Next.js App Router project.\n */\nexport async function detectNextJsProject(projectRoot: string): Promise<{\n isNextJs: boolean;\n appDir: string | null;\n projectName: string;\n}> {\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 // Check both app/ and src/app/ (common Next.js structures)\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 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 return {\n isNextJs: hasNextConfig,\n appDir: hasAppDir ? appDir : null,\n 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","readFile","join","existsSync","join","join","existsSync","readFile","error","join","existsSync","join","resolve","join","createServer","join","readFile","writeFile","mkdir","existsSync","join","dirname","resolve","join","createServer","resolve","existsSync","readFile","join","join","existsSync","mkdir","r","resolve","dirname","writeFile"]}