Spaces:
Build error
Build error
File size: 5,000 Bytes
75fefa7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
export interface BuildValidation {
success: boolean;
errors: string[];
isRendering: boolean;
warnings?: string[];
}
/**
* Validates that the sandbox build was successful
* Checks compilation status and verifies app is rendering
*/
export async function validateBuild(sandboxUrl: string, sandboxId: string): Promise<BuildValidation> {
try {
// Step 1: Wait for Vite to process files (give it time to compile)
await new Promise(resolve => setTimeout(resolve, 3000));
// Step 2: Check if the sandbox is actually serving content
const response = await fetch(sandboxUrl, {
headers: {
'User-Agent': 'OpenLovable-Validator',
'Cache-Control': 'no-cache'
}
});
if (!response.ok) {
return {
success: false,
errors: [`Sandbox returned ${response.status}`],
isRendering: false
};
}
const html = await response.text();
// Step 3: Check if it's the default page or actual app
const isDefaultPage =
html.includes('Vercel Sandbox Ready') ||
html.includes('Start building your React app with Vite') ||
html.includes('Vite + React') ||
!html.includes('id="root"');
if (isDefaultPage) {
return {
success: false,
errors: ['Sandbox showing default page, app not rendered'],
isRendering: false
};
}
// Step 4: Check for Vite error overlay in HTML
const hasViteError = html.includes('vite-error-overlay');
if (hasViteError) {
// Try to extract error message
const errorMatch = html.match(/Failed to resolve import "([^"]+)"/);
const error = errorMatch
? `Missing package: ${errorMatch[1]}`
: 'Vite compilation error detected';
return {
success: false,
errors: [error],
isRendering: false
};
}
// Success! App is rendering
return {
success: true,
errors: [],
isRendering: true
};
} catch (error) {
console.error('[validateBuild] Error during validation:', error);
return {
success: false,
errors: [error instanceof Error ? error.message : 'Validation failed'],
isRendering: false
};
}
}
/**
* Extracts missing package names from error messages
*/
export function extractMissingPackages(error: any): string[] {
const message = error?.message || String(error);
const packages: string[] = [];
// Pattern 1: "Failed to resolve import 'package-name'"
const importMatches = message.matchAll(/Failed to resolve import ["']([^"']+)["']/g);
for (const match of importMatches) {
packages.push(match[1]);
}
// Pattern 2: "Cannot find module 'package-name'"
const moduleMatches = message.matchAll(/Cannot find module ["']([^"']+)["']/g);
for (const match of moduleMatches) {
packages.push(match[1]);
}
// Pattern 3: "Package 'package-name' not found"
const packageMatches = message.matchAll(/Package ["']([^"']+)["'] not found/g);
for (const match of packageMatches) {
packages.push(match[1]);
}
return [...new Set(packages)]; // Remove duplicates
}
/**
* Classifies error type for targeted recovery
*/
export type ErrorType = 'missing-package' | 'syntax-error' | 'sandbox-timeout' | 'not-rendered' | 'vite-error' | 'unknown';
export function classifyError(error: any): ErrorType {
const message = (error?.message || String(error)).toLowerCase();
if (message.includes('failed to resolve import') ||
message.includes('cannot find module') ||
message.includes('missing package')) {
return 'missing-package';
}
if (message.includes('syntax error') ||
message.includes('unexpected token') ||
message.includes('parsing error')) {
return 'syntax-error';
}
if (message.includes('timeout') ||
message.includes('not responding') ||
message.includes('timed out')) {
return 'sandbox-timeout';
}
if (message.includes('not rendered') ||
message.includes('sandbox ready') ||
message.includes('default page')) {
return 'not-rendered';
}
if (message.includes('vite') ||
message.includes('compilation')) {
return 'vite-error';
}
return 'unknown';
}
/**
* Calculates retry delay based on attempt number and error type
*/
export function calculateRetryDelay(attempt: number, errorType: ErrorType): number {
const baseDelay = 2000; // 2 seconds
// Different strategies for different errors
switch (errorType) {
case 'missing-package':
// Packages need time to install
return baseDelay * 2 * attempt; // 4s, 8s, 12s
case 'not-rendered':
// Vite needs time to compile
return baseDelay * 3 * attempt; // 6s, 12s, 18s
case 'vite-error':
// Vite restart needed
return baseDelay * 2 * attempt;
case 'sandbox-timeout':
// Sandbox might be slow
return baseDelay * 4 * attempt; // 8s, 16s, 24s
default:
// Standard exponential backoff
return baseDelay * attempt;
}
}
|