model-explorer / js /utils /errorHandler.js
mr4's picture
Upload 71 files
9bd422a verified
/**
* 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;