File size: 6,542 Bytes
9bd422a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
181
182
183
184
185
186
187
188
/**
 * 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;