import { NextResponse } from 'next/server'; import { parseJavaScriptFile, buildComponentTree } from '@/lib/file-parser'; import { FileManifest, FileInfo, RouteInfo } from '@/types/file-manifest'; import type { SandboxState } from '@/types/sandbox'; declare global { var activeSandbox: any; } export async function GET() { try { if (!global.activeSandbox) { return NextResponse.json({ success: false, error: 'No active sandbox' }, { status: 404 }); } console.log('[get-sandbox-files] Fetching and analyzing file structure...'); // Get all React/JS/CSS files const result = await global.activeSandbox.runCode(` import os import json def get_files_content(directory='/home/user/app', extensions=['.jsx', '.js', '.tsx', '.ts', '.css', '.json']): files_content = {} for root, dirs, files in os.walk(directory): # Skip node_modules and other unwanted directories dirs[:] = [d for d in dirs if d not in ['node_modules', '.git', 'dist', 'build']] for file in files: if any(file.endswith(ext) for ext in extensions): file_path = os.path.join(root, file) relative_path = os.path.relpath(file_path, '/home/user/app') try: with open(file_path, 'r') as f: content = f.read() # Only include files under 10KB to avoid huge responses if len(content) < 10000: files_content[relative_path] = content except: pass return files_content # Get the files files = get_files_content() # Also get the directory structure structure = [] for root, dirs, files in os.walk('/home/user/app'): level = root.replace('/home/user/app', '').count(os.sep) indent = ' ' * 2 * level structure.append(f"{indent}{os.path.basename(root)}/") sub_indent = ' ' * 2 * (level + 1) for file in files: if not any(skip in root for skip in ['node_modules', '.git', 'dist', 'build']): structure.append(f"{sub_indent}{file}") result = { 'files': files, 'structure': '\\n'.join(structure[:50]) # Limit structure to 50 lines } print(json.dumps(result)) `); const output = result.logs.stdout.join(''); const parsedResult = JSON.parse(output); // Build enhanced file manifest const fileManifest: FileManifest = { files: {}, routes: [], componentTree: {}, entryPoint: '', styleFiles: [], timestamp: Date.now(), }; // Process each file for (const [relativePath, content] of Object.entries(parsedResult.files)) { const fullPath = `/home/user/app/${relativePath}`; // Create base file info const fileInfo: FileInfo = { content: content as string, type: 'utility', path: fullPath, relativePath, lastModified: Date.now(), }; // Parse JavaScript/JSX files if (relativePath.match(/\.(jsx?|tsx?)$/)) { const parseResult = parseJavaScriptFile(content as string, fullPath); Object.assign(fileInfo, parseResult); // Identify entry point if (relativePath === 'src/main.jsx' || relativePath === 'src/index.jsx') { fileManifest.entryPoint = fullPath; } // Identify App.jsx if (relativePath === 'src/App.jsx' || relativePath === 'App.jsx') { fileManifest.entryPoint = fileManifest.entryPoint || fullPath; } } // Track style files if (relativePath.endsWith('.css')) { fileManifest.styleFiles.push(fullPath); fileInfo.type = 'style'; } fileManifest.files[fullPath] = fileInfo; } // Build component tree fileManifest.componentTree = buildComponentTree(fileManifest.files); // Extract routes (simplified - looks for Route components or page pattern) fileManifest.routes = extractRoutes(fileManifest.files); // Update global file cache with manifest if (global.sandboxState?.fileCache) { global.sandboxState.fileCache.manifest = fileManifest; } return NextResponse.json({ success: true, files: parsedResult.files, structure: parsedResult.structure, fileCount: Object.keys(parsedResult.files).length, manifest: fileManifest, }); } catch (error) { console.error('[get-sandbox-files] Error:', error); return NextResponse.json({ success: false, error: (error as Error).message }, { status: 500 }); } } function extractRoutes(files: Record): RouteInfo[] { const routes: RouteInfo[] = []; // Look for React Router usage for (const [path, fileInfo] of Object.entries(files)) { if (fileInfo.content.includes('