/** * ErrorHandler - Global error handling utility * Classifies errors, creates user-friendly messages, logs to console, * updates StateManager error state, and attempts recovery where possible. * Requirements: 11.1, 11.2, 11.3, 11.4, 11.5 */ const ErrorHandler = (function () { // ─── Error Type Constants ───────────────────────────────────────────────── const ErrorType = { FILE_NOT_FOUND: 'FILE_NOT_FOUND', INVALID_FILE_FORMAT: 'INVALID_FILE_FORMAT', PARSE_ERROR: 'PARSE_ERROR', LIBRARY_LOAD_ERROR: 'LIBRARY_LOAD_ERROR', UPLOAD_ERROR: 'UPLOAD_ERROR', EXPORT_ERROR: 'EXPORT_ERROR', UNKNOWN_ERROR: 'UNKNOWN_ERROR', }; // ─── Private Helpers ────────────────────────────────────────────────────── /** * Classify an error object or message into a known ErrorType. * @param {Error|string} error * @returns {string} One of the ErrorType values */ function _classifyError(error) { const msg = (error && (error.message || String(error))).toLowerCase(); if (msg.includes('not found') || msg.includes('404') || msg.includes('failed to fetch')) { return ErrorType.FILE_NOT_FOUND; } if (msg.includes('invalid') && (msg.includes('format') || msg.includes('onnx'))) { return ErrorType.INVALID_FILE_FORMAT; } if (msg.includes('parse') || msg.includes('protobuf') || msg.includes('corrupt')) { return ErrorType.PARSE_ERROR; } if (msg.includes('library') || msg.includes('cdn') || msg.includes('script') || msg.includes('load error') || msg.includes('protobuf')) { return ErrorType.LIBRARY_LOAD_ERROR; } if (msg.includes('upload')) { return ErrorType.UPLOAD_ERROR; } if (msg.includes('export')) { return ErrorType.EXPORT_ERROR; } return ErrorType.UNKNOWN_ERROR; } /** * Map an ErrorType to a user-friendly message from CONFIG.ERRORS. * @param {string} errorType * @returns {string} */ function _getUserMessage(errorType) { if (typeof CONFIG !== 'undefined' && CONFIG.ERRORS && CONFIG.ERRORS[errorType]) { return CONFIG.ERRORS[errorType]; } // Fallback messages if CONFIG is not available const fallback = { FILE_NOT_FOUND: 'File not found. Please check the file path.', INVALID_FILE_FORMAT: 'Invalid file format. Please upload a valid ONNX file.', PARSE_ERROR: 'Failed to parse the model. The file may be corrupted.', LIBRARY_LOAD_ERROR: 'Failed to load required libraries. Please check your internet connection.', UPLOAD_ERROR: 'Failed to upload the file. Please try again.', EXPORT_ERROR: 'Failed to export the model information.', UNKNOWN_ERROR: 'An unknown error occurred. Please try again.', }; return fallback[errorType] || fallback.UNKNOWN_ERROR; } /** * Attempt recovery based on error type. * @param {string} errorType */ function _attemptRecovery(errorType) { switch (errorType) { case ErrorType.LIBRARY_LOAD_ERROR: // Nothing we can do automatically; user must refresh console.info('[ErrorHandler] Recovery: User should refresh the page to reload libraries.'); break; case ErrorType.FILE_NOT_FOUND: case ErrorType.PARSE_ERROR: case ErrorType.INVALID_FILE_FORMAT: // Clear the current model so the UI returns to a clean state if (typeof StateManager !== 'undefined') { StateManager.setCurrentModel(null); StateManager.setLoading(false); } break; case ErrorType.UPLOAD_ERROR: // Reset loading state so the upload button is usable again if (typeof StateManager !== 'undefined') { StateManager.setLoading(false); } break; case ErrorType.EXPORT_ERROR: // No state change needed; export is a side-effect operation break; default: // Generic recovery: ensure loading spinner is cleared if (typeof StateManager !== 'undefined') { StateManager.setLoading(false); } break; } } // ─── Public API ─────────────────────────────────────────────────────────── return { /** * Handle an error: log it, classify it, show a user-friendly message, * update StateManager, and attempt recovery. * * @param {Error|string} error - The error object or message * @param {string} [context='App'] - Context label for console logging * @param {'error'|'warning'|'info'} [severity='error'] - Display severity */ handleError(error, context = 'App', severity = 'error') { // 1. Log to console console.error(`[ErrorHandler][${context}]`, error); // 2. Classify error type const errorType = _classifyError(error); // 3. Create user-friendly message const userMessage = _getUserMessage(errorType); // 4. Update StateManager error state if (typeof StateManager !== 'undefined') { StateManager.setError(userMessage, severity); } // 5. Attempt recovery _attemptRecovery(errorType); // Return structured info for callers that want it return { errorType, userMessage }; }, /** * Handle a warning (non-critical issue). * @param {string} message * @param {string} [context='App'] */ handleWarning(message, context = 'App') { console.warn(`[ErrorHandler][${context}]`, message); if (typeof StateManager !== 'undefined') { StateManager.setError(message, 'warning'); } }, /** * Handle an informational message. * @param {string} message * @param {string} [context='App'] */ handleInfo(message, context = 'App') { console.info(`[ErrorHandler][${context}]`, message); if (typeof StateManager !== 'undefined') { StateManager.setError(message, 'info'); } }, /** * Clear the current error state. */ clearError() { if (typeof StateManager !== 'undefined') { StateManager.clearError(); } }, // Expose ErrorType constants for external use ErrorType, }; })(); // Export for global access in vanilla JS context window.ErrorHandler = ErrorHandler;