deepsite / lib /error-detector.ts
victor's picture
victor HF Staff
feat: add automatic error detection and fixing for preview
473668f
raw
history blame
4.25 kB
export const ERROR_DETECTOR_ID = "deepsite-error-detector";
export const errorDetectorScript = `
(function() {
const errors = [];
let errorTimeout = null;
const MAX_ERRORS = 10;
const BATCH_DELAY = 1000; // Wait 1 second before sending errors
// Create a safe error object that can be serialized
function createSafeError(error, type, context = {}) {
return {
type,
message: error?.message || String(error),
stack: error?.stack,
lineNumber: error?.lineNumber || context.lineNumber,
columnNumber: error?.columnNumber || context.columnNumber,
fileName: error?.fileName || context.fileName,
timestamp: new Date().toISOString(),
...context
};
}
// Send errors to parent window (always send, even if empty)
function sendErrors() {
window.parent.postMessage({
type: 'PREVIEW_ERRORS',
errors: errors.slice(0, MAX_ERRORS), // Limit errors sent
url: window.location.href
}, '*');
errors.length = 0; // Clear sent errors
}
// Batch errors to avoid spamming
function queueError(error) {
errors.push(error);
if (errorTimeout) clearTimeout(errorTimeout);
errorTimeout = setTimeout(sendErrors, BATCH_DELAY);
}
// Global error handler
window.addEventListener('error', function(event) {
const error = createSafeError(event.error || event.message, 'runtime-error', {
lineNumber: event.lineno,
columnNumber: event.colno,
fileName: event.filename,
errorType: 'JavaScript Error'
});
queueError(error);
});
// Unhandled promise rejection handler
window.addEventListener('unhandledrejection', function(event) {
const error = createSafeError(event.reason, 'unhandled-promise', {
promise: event.promise,
errorType: 'Unhandled Promise Rejection'
});
queueError(error);
});
// Override console.error to catch logged errors
const originalConsoleError = console.error;
console.error = function(...args) {
originalConsoleError.apply(console, args);
const error = createSafeError(args.join(' '), 'console-error', {
errorType: 'Console Error',
args: args.map(arg => String(arg))
});
queueError(error);
};
// Monitor failed resource loads (404s, etc)
window.addEventListener('error', function(event) {
if (event.target !== window) {
// This is a resource loading error
const target = event.target;
const error = createSafeError(\`Failed to load resource: \${target.src || target.href}\`, 'resource-error', {
tagName: target.tagName,
src: target.src || target.href,
errorType: 'Resource Loading Error'
});
queueError(error);
}
}, true); // Use capture phase to catch resource errors
// Monitor for common React errors
if (window.React && window.React.version) {
const originalError = console.error;
console.error = function(...args) {
originalError.apply(console, args);
const errorString = args.join(' ');
if (errorString.includes('ReactDOM.render is no longer supported') ||
errorString.includes('Cannot read property') ||
errorString.includes('Cannot access property')) {
const error = createSafeError(errorString, 'react-error', {
errorType: 'React Error',
reactVersion: window.React.version
});
queueError(error);
}
};
}
// Report current state of errors
function reportCurrentState() {
sendErrors();
}
// Send initial ready message and current error state
window.addEventListener('load', reportCurrentState);
// Monitor for DOM changes that might clear errors
const observer = new MutationObserver(() => {
// Small delay to let any new errors register
setTimeout(reportCurrentState, 100);
});
// Start observing once DOM is ready
if (document.body) {
observer.observe(document.body, {
subtree: true,
childList: true
});
} else {
window.addEventListener('DOMContentLoaded', () => {
observer.observe(document.body, {
subtree: true,
childList: true
});
});
}
// Send initial state
reportCurrentState();
})();
`;