-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror-handler.js
More file actions
331 lines (286 loc) · 11.8 KB
/
error-handler.js
File metadata and controls
331 lines (286 loc) · 11.8 KB
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// Error handling module for Resume Matcher extension
// Provides centralized error handling and user-friendly error messages
class ErrorHandler {
constructor() {
this.errorTypes = {
PDF_PROCESSING: 'pdf_processing',
JOB_EXTRACTION: 'job_extraction',
STORAGE: 'storage',
NETWORK: 'network',
PERMISSION: 'permission',
VALIDATION: 'validation',
UNKNOWN: 'unknown'
};
}
// Handle and categorize errors
handleError(error, context = '') {
console.error(`Error in ${context}:`, error);
const errorInfo = this.categorizeError(error);
const userMessage = this.getUserFriendlyMessage(errorInfo);
return {
type: errorInfo.type,
message: userMessage,
originalError: error,
context: context,
timestamp: new Date().toISOString()
};
}
// Categorize error based on type and message
categorizeError(error) {
const message = error.message || error.toString();
const lowerMessage = message.toLowerCase();
// PDF processing errors
if (lowerMessage.includes('pdf') ||
lowerMessage.includes('invalid pdf') ||
lowerMessage.includes('corrupted') ||
error.name === 'InvalidPDFException' ||
error.name === 'MissingPDFException') {
return { type: this.errorTypes.PDF_PROCESSING, severity: 'high' };
}
// Job extraction errors
if (lowerMessage.includes('job description') ||
lowerMessage.includes('extract') ||
lowerMessage.includes('content script')) {
return { type: this.errorTypes.JOB_EXTRACTION, severity: 'medium' };
}
// Storage errors
if (lowerMessage.includes('storage') ||
lowerMessage.includes('quota') ||
lowerMessage.includes('store') ||
lowerMessage.includes('save')) {
return { type: this.errorTypes.STORAGE, severity: 'medium' };
}
// Network errors
if (lowerMessage.includes('network') ||
lowerMessage.includes('fetch') ||
lowerMessage.includes('connection') ||
error.name === 'NetworkError') {
return { type: this.errorTypes.NETWORK, severity: 'low' };
}
// Permission errors
if (lowerMessage.includes('permission') ||
lowerMessage.includes('access') ||
lowerMessage.includes('denied') ||
lowerMessage.includes('tab')) {
return { type: this.errorTypes.PERMISSION, severity: 'high' };
}
// Validation errors
if (lowerMessage.includes('invalid') ||
lowerMessage.includes('required') ||
lowerMessage.includes('format') ||
lowerMessage.includes('size')) {
return { type: this.errorTypes.VALIDATION, severity: 'medium' };
}
return { type: this.errorTypes.UNKNOWN, severity: 'medium' };
}
// Get user-friendly error messages
getUserFriendlyMessage(errorInfo) {
const messages = {
[this.errorTypes.PDF_PROCESSING]: {
title: 'PDF Processing Error',
message: 'Unable to read your resume PDF. Please ensure it\'s a valid, text-based PDF file (not a scanned image) and try again.',
suggestions: [
'Make sure the PDF is not password-protected',
'Try saving your resume as a new PDF',
'Ensure the PDF contains selectable text, not just images'
]
},
[this.errorTypes.JOB_EXTRACTION]: {
title: 'Job Description Not Found',
message: 'Could not find a job description on this page. Please make sure you\'re on a job posting page.',
suggestions: [
'Navigate to a job posting page (LinkedIn, Indeed, etc.)',
'Make sure the page has fully loaded',
'Try refreshing the page and try again'
]
},
[this.errorTypes.STORAGE]: {
title: 'Storage Error',
message: 'Unable to save your resume data. Your browser storage might be full.',
suggestions: [
'Clear some browser data to free up space',
'Try uploading a smaller resume file',
'Restart your browser and try again'
]
},
[this.errorTypes.NETWORK]: {
title: 'Connection Error',
message: 'Network connection issue. Please check your internet connection and try again.',
suggestions: [
'Check your internet connection',
'Try refreshing the page',
'Disable other extensions temporarily'
]
},
[this.errorTypes.PERMISSION]: {
title: 'Permission Error',
message: 'The extension doesn\'t have permission to access this page. Please refresh the page and try again.',
suggestions: [
'Refresh the current page',
'Make sure the extension is enabled',
'Try on a different job posting site'
]
},
[this.errorTypes.VALIDATION]: {
title: 'Invalid Input',
message: 'The file or data provided is not valid. Please check your input and try again.',
suggestions: [
'Make sure you\'re uploading a PDF file',
'Check that the file size is under 10MB',
'Ensure the file is not corrupted'
]
},
[this.errorTypes.UNKNOWN]: {
title: 'Unexpected Error',
message: 'An unexpected error occurred. Please try again or contact support if the problem persists.',
suggestions: [
'Try refreshing the page',
'Restart your browser',
'Disable other extensions temporarily'
]
}
};
return messages[errorInfo.type] || messages[this.errorTypes.UNKNOWN];
}
// Validate file input
validateFile(file) {
const errors = [];
const maxSize = 10 * 1024 * 1024; // 10MB
if (!file) {
errors.push("No file selected");
} else {
if (file.type !== "application/pdf") {
errors.push("File must be a PDF (.pdf)");
}
if (file.size === 0) {
errors.push("File appears to be empty");
}
if (file.size > maxSize) {
errors.push(`File size (${this.formatFileSize(file.size)}) exceeds the 10MB limit`);
}
// Basic file name validation: only check for .pdf extension and prevent path traversal
if (!file.name.toLowerCase().endsWith(".pdf")) {
errors.push("File must have a .pdf extension");
}
if (file.name.includes("/") || file.name.includes("\\")) {
errors.push("File name cannot contain path separators");
}
}
return {
isValid: errors.length === 0,
errors: errors
};
}
// Validate job description text
validateJobDescription(text) {
const errors = [];
const minLength = 100;
const maxLength = 50000;
if (!text || typeof text !== 'string') {
errors.push('No job description text provided');
} else {
const trimmedText = text.trim();
if (trimmedText.length < minLength) {
errors.push(`Job description is too short (minimum ${minLength} characters)`);
}
if (trimmedText.length > maxLength) {
errors.push(`Job description is too long (maximum ${maxLength} characters)`);
}
// Check if it looks like a job description
const jobKeywords = ['job', 'position', 'role', 'responsibilities', 'requirements', 'qualifications', 'experience', 'skills'];
const hasJobKeywords = jobKeywords.some(keyword =>
trimmedText.toLowerCase().includes(keyword)
);
if (!hasJobKeywords) {
errors.push('Text doesn\'t appear to be a job description');
}
}
return {
isValid: errors.length === 0,
errors: errors
};
}
// Format file size for display
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// Log error for debugging
logError(error, context) {
const errorData = {
timestamp: new Date().toISOString(),
context: context,
message: error.message,
stack: error.stack,
userAgent: navigator.userAgent,
url: window.location?.href
};
console.error('Resume Matcher Error:', errorData);
// In a production environment, you might want to send this to an error tracking service
// this.sendToErrorTracking(errorData);
}
// Check browser compatibility
checkBrowserCompatibility() {
const issues = [];
// Check for required APIs
if (!window.chrome || !chrome.runtime) {
issues.push('Chrome extension APIs not available');
}
if (!window.FileReader) {
issues.push('FileReader API not supported');
}
if (!window.ArrayBuffer) {
issues.push('ArrayBuffer not supported');
}
// Check for PDF.js requirements
if (!window.Worker) {
issues.push('Web Workers not supported (required for PDF processing)');
}
return {
isCompatible: issues.length === 0,
issues: issues
};
}
// Recovery suggestions based on error type
getRecoverySuggestions(errorType) {
const suggestions = {
[this.errorTypes.PDF_PROCESSING]: [
'Try converting your resume to a different PDF format',
'Use a PDF that contains selectable text (not scanned images)',
'Reduce the file size if it\'s very large'
],
[this.errorTypes.JOB_EXTRACTION]: [
'Make sure you\'re on a job posting page',
'Try scrolling down to load more content',
'Switch to a different job board (LinkedIn, Indeed, etc.)'
],
[this.errorTypes.STORAGE]: [
'Clear browser cache and cookies',
'Free up disk space on your computer',
'Try using the extension in an incognito window'
],
[this.errorTypes.PERMISSION]: [
'Refresh the current page',
'Check that the extension is enabled in Chrome settings',
'Try disabling other extensions temporarily'
]
};
return suggestions[errorType] || [
'Try refreshing the page',
'Restart your browser',
'Contact support if the problem persists'
];
}
}
// Create global instance
const errorHandler = new ErrorHandler();
// Export for use in other scripts
if (typeof module !== 'undefined' && module.exports) {
module.exports = ErrorHandler;
} else if (typeof window !== 'undefined') {
window.ErrorHandler = ErrorHandler;
window.errorHandler = errorHandler;
}