Spaces:
Sleeping
Sleeping
Constrain admin table to plain HTML (no missing shadcn import), fix install-timeout silently passing as success
fdae3ee | import { spawn } from "child_process"; | |
| import fs from "fs"; | |
| import path from "path"; | |
| export interface ValidationResult { | |
| success: boolean; | |
| installLog: string; | |
| buildLog: string; | |
| error?: string; | |
| duration: number; // milliseconds | |
| } | |
| /** | |
| * Run a command with timeout and capture stdout/stderr | |
| */ | |
| function runCommand( | |
| cmd: string, | |
| args: string[], | |
| cwd: string, | |
| timeout: number = 300000 // 5 minutes default | |
| ): Promise<{ stdout: string; stderr: string; code: number | null }> { | |
| return new Promise((resolve) => { | |
| const child = spawn(cmd, args, { cwd, shell: true }); | |
| let stdout = ""; | |
| let stderr = ""; | |
| child.stdout.on("data", (data) => { | |
| stdout += data.toString(); | |
| }); | |
| child.stderr.on("data", (data) => { | |
| stderr += data.toString(); | |
| }); | |
| const timer = setTimeout(() => { | |
| child.kill("SIGTERM"); | |
| resolve({ | |
| stdout, | |
| stderr: stderr + "\n[ERROR] Command timed out after " + timeout + "ms", | |
| code: null, | |
| }); | |
| }, timeout); | |
| child.on("close", (code) => { | |
| clearTimeout(timer); | |
| resolve({ stdout, stderr, code }); | |
| }); | |
| child.on("error", (err) => { | |
| clearTimeout(timer); | |
| resolve({ | |
| stdout, | |
| stderr: stderr + "\n" + err.message, | |
| code: null, | |
| }); | |
| }); | |
| }); | |
| } | |
| export async function validateProject( | |
| projectDir: string, | |
| options: { installTimeout?: number; buildTimeout?: number } = {} | |
| ): Promise<ValidationResult> { | |
| const start = Date.now(); | |
| const installTimeout = options.installTimeout || 300000; | |
| const buildTimeout = options.buildTimeout || 300000; | |
| // Check if project directory exists | |
| if (!fs.existsSync(projectDir)) { | |
| return { | |
| success: false, | |
| installLog: "", | |
| buildLog: "", | |
| error: `Project directory not found: ${projectDir}`, | |
| duration: 0, | |
| }; | |
| } | |
| // Check for package.json | |
| const pkgPath = path.join(projectDir, "package.json"); | |
| if (!fs.existsSync(pkgPath)) { | |
| return { | |
| success: false, | |
| installLog: "", | |
| buildLog: "", | |
| error: "No package.json found in project directory", | |
| duration: 0, | |
| }; | |
| } | |
| // Step 1: npm install | |
| const installResult = await runCommand( | |
| "npm", | |
| ["install", "--no-audit", "--no-fund", "--loglevel=error", "--include=dev"], | |
| projectDir, | |
| installTimeout | |
| ); | |
| const installLog = installResult.stdout + "\n" + installResult.stderr; | |
| if (installResult.code !== 0) { | |
| return { | |
| success: false, | |
| installLog, | |
| buildLog: "", | |
| error: `npm install failed with code ${installResult.code}`, | |
| duration: Date.now() - start, | |
| }; | |
| } | |
| // Step 2: npm run build | |
| const buildResult = await runCommand( | |
| "npm", | |
| ["run", "build"], | |
| projectDir, | |
| buildTimeout | |
| ); | |
| const buildLog = buildResult.stdout + "\n" + buildResult.stderr; | |
| if (buildResult.code !== 0 && buildResult.code !== null) { | |
| return { | |
| success: false, | |
| installLog, | |
| buildLog, | |
| error: `npm run build failed with code ${buildResult.code}`, | |
| duration: Date.now() - start, | |
| }; | |
| } | |
| return { | |
| success: true, | |
| installLog, | |
| buildLog, | |
| duration: Date.now() - start, | |
| }; | |
| } | |
| /** | |
| * Validate the project and write a JSON report inside the project directory | |
| */ | |
| export async function validateAndSave( | |
| projectDir: string, | |
| options?: { installTimeout?: number; buildTimeout?: number } | |
| ): Promise<ValidationResult> { | |
| const result = await validateProject(projectDir, options); | |
| const reportPath = path.join(projectDir, ".validation.json"); | |
| fs.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8"); | |
| return result; | |
| } | |