@arela/uploader 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.claude/worktrees/agent-multi-profile/.env.template +224 -0
  2. package/.claude/worktrees/agent-multi-profile/.prettierrc +13 -0
  3. package/.claude/worktrees/agent-multi-profile/README.md +405 -0
  4. package/.claude/worktrees/agent-multi-profile/package-lock.json +7096 -0
  5. package/.claude/worktrees/agent-multi-profile/package.json +78 -0
  6. package/.claude/worktrees/agent-multi-profile/scripts/cleanup-ds-store.js +109 -0
  7. package/.claude/worktrees/agent-multi-profile/scripts/cleanup-system-files.js +69 -0
  8. package/.claude/worktrees/agent-multi-profile/scripts/scoring-compare.js +243 -0
  9. package/.claude/worktrees/agent-multi-profile/scripts/scoring-phase4-check.js +96 -0
  10. package/.claude/worktrees/agent-multi-profile/scripts/tests/phase-7-features.test.js +415 -0
  11. package/.claude/worktrees/agent-multi-profile/scripts/tests/signal-handling.test.js +275 -0
  12. package/.claude/worktrees/agent-multi-profile/scripts/tests/smart-watch-integration.test.js +554 -0
  13. package/.claude/worktrees/agent-multi-profile/scripts/tests/watch-service-integration.test.js +584 -0
  14. package/.claude/worktrees/agent-multi-profile/src/commands/AgentCommand.js +229 -0
  15. package/.claude/worktrees/agent-multi-profile/src/commands/AgentInitCommand.js +316 -0
  16. package/.claude/worktrees/agent-multi-profile/src/commands/DatastageCommand.js +164 -0
  17. package/.claude/worktrees/agent-multi-profile/src/commands/GDriveSyncCommand.js +475 -0
  18. package/.claude/worktrees/agent-multi-profile/src/commands/IdentifyCommand.js +708 -0
  19. package/.claude/worktrees/agent-multi-profile/src/commands/PollWorkerCommand.js +169 -0
  20. package/.claude/worktrees/agent-multi-profile/src/commands/PropagateCommand.js +636 -0
  21. package/.claude/worktrees/agent-multi-profile/src/commands/PushCommand.js +743 -0
  22. package/.claude/worktrees/agent-multi-profile/src/commands/ScanCommand.js +722 -0
  23. package/.claude/worktrees/agent-multi-profile/src/commands/UploadCommand.js +587 -0
  24. package/.claude/worktrees/agent-multi-profile/src/commands/WatchCommand.js +1342 -0
  25. package/.claude/worktrees/agent-multi-profile/src/commands/WorkerCommand.js +337 -0
  26. package/.claude/worktrees/agent-multi-profile/src/config/config.js +862 -0
  27. package/.claude/worktrees/agent-multi-profile/src/document-type-shared.js +131 -0
  28. package/.claude/worktrees/agent-multi-profile/src/document-types/_pedimento-shared-extractors.js +348 -0
  29. package/.claude/worktrees/agent-multi-profile/src/document-types/doda-pdf.js +121 -0
  30. package/.claude/worktrees/agent-multi-profile/src/document-types/doda-xml.js +118 -0
  31. package/.claude/worktrees/agent-multi-profile/src/document-types/factura-inter-agencia.js +186 -0
  32. package/.claude/worktrees/agent-multi-profile/src/document-types/facturas-comerciales.js +233 -0
  33. package/.claude/worktrees/agent-multi-profile/src/document-types/pedimento-completo-xml.js +372 -0
  34. package/.claude/worktrees/agent-multi-profile/src/document-types/pedimento-completo.js +108 -0
  35. package/.claude/worktrees/agent-multi-profile/src/document-types/pedimento-simplificado.js +76 -0
  36. package/.claude/worktrees/agent-multi-profile/src/document-types/proforma.js +29 -0
  37. package/.claude/worktrees/agent-multi-profile/src/document-types/support-document.js +200 -0
  38. package/.claude/worktrees/agent-multi-profile/src/errors/ErrorHandler.js +278 -0
  39. package/.claude/worktrees/agent-multi-profile/src/errors/ErrorTypes.js +104 -0
  40. package/.claude/worktrees/agent-multi-profile/src/file-detection.js +338 -0
  41. package/.claude/worktrees/agent-multi-profile/src/index.js +890 -0
  42. package/.claude/worktrees/agent-multi-profile/src/scoring/db-matcher-adapter.js +98 -0
  43. package/.claude/worktrees/agent-multi-profile/src/scoring/matchers-seed.js +386 -0
  44. package/.claude/worktrees/agent-multi-profile/src/scoring/scoring-engine.js +251 -0
  45. package/.claude/worktrees/agent-multi-profile/src/services/AdvancedFilterService.js +505 -0
  46. package/.claude/worktrees/agent-multi-profile/src/services/AutoProcessingService.js +749 -0
  47. package/.claude/worktrees/agent-multi-profile/src/services/BenchmarkingService.js +381 -0
  48. package/.claude/worktrees/agent-multi-profile/src/services/DatabaseService.js +2173 -0
  49. package/.claude/worktrees/agent-multi-profile/src/services/DatastageApiService.js +240 -0
  50. package/.claude/worktrees/agent-multi-profile/src/services/ErrorMonitor.js +275 -0
  51. package/.claude/worktrees/agent-multi-profile/src/services/GoogleDriveService.js +217 -0
  52. package/.claude/worktrees/agent-multi-profile/src/services/LoggingService.js +649 -0
  53. package/.claude/worktrees/agent-multi-profile/src/services/MonitoringService.js +401 -0
  54. package/.claude/worktrees/agent-multi-profile/src/services/PerformanceOptimizer.js +511 -0
  55. package/.claude/worktrees/agent-multi-profile/src/services/PipelineApiService.js +274 -0
  56. package/.claude/worktrees/agent-multi-profile/src/services/PipelineJobRunner.js +389 -0
  57. package/.claude/worktrees/agent-multi-profile/src/services/ProfileManager.js +164 -0
  58. package/.claude/worktrees/agent-multi-profile/src/services/ReportingService.js +511 -0
  59. package/.claude/worktrees/agent-multi-profile/src/services/ScanApiService.js +775 -0
  60. package/.claude/worktrees/agent-multi-profile/src/services/SignalHandler.js +255 -0
  61. package/.claude/worktrees/agent-multi-profile/src/services/SmartWatchDatabaseService.js +527 -0
  62. package/.claude/worktrees/agent-multi-profile/src/services/WatchService.js +783 -0
  63. package/.claude/worktrees/agent-multi-profile/src/services/upload/ApiUploadService.js +676 -0
  64. package/.claude/worktrees/agent-multi-profile/src/services/upload/BaseUploadService.js +36 -0
  65. package/.claude/worktrees/agent-multi-profile/src/services/upload/MultiApiUploadService.js +233 -0
  66. package/.claude/worktrees/agent-multi-profile/src/services/upload/SupabaseUploadService.js +148 -0
  67. package/.claude/worktrees/agent-multi-profile/src/services/upload/UploadServiceFactory.js +100 -0
  68. package/.claude/worktrees/agent-multi-profile/src/utils/CleanupManager.js +262 -0
  69. package/.claude/worktrees/agent-multi-profile/src/utils/FileOperations.js +192 -0
  70. package/.claude/worktrees/agent-multi-profile/src/utils/FileSanitizer.js +99 -0
  71. package/.claude/worktrees/agent-multi-profile/src/utils/PathDetector.js +198 -0
  72. package/.claude/worktrees/agent-multi-profile/src/utils/PathNormalizer.js +274 -0
  73. package/.claude/worktrees/agent-multi-profile/src/utils/WatchEventHandler.js +522 -0
  74. package/.claude/worktrees/agent-multi-profile/supabase/migrations/001_create_initial_schema.sql +366 -0
  75. package/.claude/worktrees/agent-multi-profile/supabase/migrations/002_align_with_arela_api_schema.sql +145 -0
  76. package/.claude/worktrees/agent-multi-profile/tests/commands/IdentifyCommand.test.js +570 -0
  77. package/.claude/worktrees/agent-multi-profile/tests/commands/PropagateCommand.test.js +568 -0
  78. package/.claude/worktrees/agent-multi-profile/tests/commands/PushCommand.test.js +754 -0
  79. package/.claude/worktrees/agent-multi-profile/tests/commands/ScanCommand.test.js +382 -0
  80. package/.claude/worktrees/agent-multi-profile/tests/unit/PathAndTableNameGeneration.test.js +1211 -0
  81. package/.claude/worktrees/agent-multi-profile/tests/unit/factura-inter-agencia.test.js +218 -0
  82. package/.claude/worktrees/agent-multi-profile/tests/unit/pedimento-completo-xml-matcher.test.js +271 -0
  83. package/.claude/worktrees/agent-multi-profile/tests/unit/pedimento-simplificado-matcher.test.js +185 -0
  84. package/.claude/worktrees/agent-multi-profile/tests/unit/scoring-engine.test.js +221 -0
  85. package/README.md +65 -0
  86. package/package.json +1 -1
  87. package/src/commands/AgentCommand.js +210 -0
  88. package/src/commands/AgentInitCommand.js +316 -0
  89. package/src/commands/PollWorkerCommand.js +11 -322
  90. package/src/config/config.js +44 -6
  91. package/src/document-type-shared.js +1 -1
  92. package/src/document-types/pedimento-completo.js +8 -1
  93. package/src/file-detection.js +9 -0
  94. package/src/index.js +55 -0
  95. package/src/scoring/scoring-engine.js +1 -1
  96. package/src/services/LoggingService.js +35 -0
  97. package/src/services/PipelineApiService.js +7 -1
  98. package/src/services/PipelineJobRunner.js +389 -0
  99. package/src/services/ProfileManager.js +164 -0
@@ -0,0 +1,200 @@
1
+ import { FieldResult } from '../document-type-shared.js';
2
+
3
+ /**
4
+ * Support Document Definition
5
+ * Detects XML and other supporting documents related to customs operations
6
+ * These documents are typically metadata or supporting files that accompany pedimento simplificado
7
+ */
8
+ export const supportDocumentDefinition = {
9
+ type: 'support_document',
10
+ extensions: ['xml', 'txt', 'json'],
11
+ match: (source) => {
12
+ // Detect SOAP/XML structures common in customs systems
13
+ const soapClues = [
14
+ /soapenv:Envelope/i,
15
+ /xmlns:soapenv=/i,
16
+ /solicitarRecibirCoveServicio/i,
17
+ /tipoOperacion/i,
18
+ /patenteAduanal/i,
19
+ ];
20
+
21
+ // Detect customs-related metadata
22
+ const customsClues = [/rfc|RFC/, /patente|aduana|customs|pedimento/i];
23
+
24
+ const soapFound = soapClues.filter((clue) => clue.test(source)).length;
25
+ const customsFound = customsClues.filter((clue) =>
26
+ clue.test(source),
27
+ ).length;
28
+
29
+ // Must have SOAP structure OR customs metadata
30
+ return soapFound >= 2 || customsFound >= 2;
31
+ },
32
+
33
+ extractNumPedimento: (source, fields) => {
34
+ // Try to extract pedimento from various XML/text formats
35
+ const patterns = [
36
+ // SOAP format with tipoOperacion
37
+ /tipoOperacion[^>]*>([A-Z]{4}[^<]*)<\/oxml:tipoOperacion/i,
38
+ // Pedimento number in XML
39
+ /numPedimento[^>]*>(\d{15})<\/\w+:numPedimento/i,
40
+ // Generic pattern
41
+ /pedimento[:\s]*(\d{15})/i,
42
+ ];
43
+
44
+ for (const pattern of patterns) {
45
+ const match = source.match(pattern);
46
+ if (match) {
47
+ return match[1];
48
+ }
49
+ }
50
+
51
+ return null;
52
+ },
53
+
54
+ extractPedimentoYear: (source, fields) => {
55
+ const numPedimento = fields?.find((f) => f.name === 'numPedimento')?.value;
56
+ if (!numPedimento) {
57
+ // Try to extract year from date in XML
58
+ const dateMatch = source.match(/(\d{4})-\d{2}-\d{2}/);
59
+ if (dateMatch) {
60
+ return parseInt(dateMatch[1], 10);
61
+ }
62
+ return null;
63
+ }
64
+
65
+ const year = parseInt(numPedimento.substring(0, 2), 10);
66
+ return year < 50 ? year + 2000 : year + 1900;
67
+ },
68
+
69
+ extractors: [
70
+ // RFC (Registro Federal de Contribuyentes)
71
+ {
72
+ field: 'rfc',
73
+ extract: (source) => {
74
+ const patterns = [
75
+ /rfc[^>]*>([A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3})<\/\w+:rfc/i,
76
+ /rfcConsulta[^>]*>([A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3})<\/\w+:rfcConsulta/i,
77
+ /RFC[:\s]*([A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3})/,
78
+ ];
79
+
80
+ for (const pattern of patterns) {
81
+ const match = source.match(pattern);
82
+ if (match) {
83
+ return new FieldResult('rfc', true, match[1]);
84
+ }
85
+ }
86
+
87
+ return new FieldResult('rfc', false, null);
88
+ },
89
+ },
90
+
91
+ // Patente Aduanal
92
+ {
93
+ field: 'patente',
94
+ extract: (source) => {
95
+ const patterns = [
96
+ /patenteAduanal[^>]*>(\d{4})<\/\w+:patenteAduanal/i,
97
+ /patente[:\s]*(\d{4})/i,
98
+ ];
99
+
100
+ for (const pattern of patterns) {
101
+ const match = source.match(pattern);
102
+ if (match) {
103
+ return new FieldResult('patente', true, match[1]);
104
+ }
105
+ }
106
+
107
+ return new FieldResult('patente', false, null);
108
+ },
109
+ },
110
+
111
+ // Aduana
112
+ {
113
+ field: 'aduanaEntradaSalida',
114
+ extract: (source) => {
115
+ const patterns = [
116
+ /aduanaEntradaSalida[^>]*>(\d{1,2})<\/\w+:aduanaEntradaSalida/i,
117
+ /aduana[:\s]*(\d{1,2})/i,
118
+ ];
119
+
120
+ for (const pattern of patterns) {
121
+ const match = source.match(pattern);
122
+ if (match) {
123
+ return new FieldResult('aduanaEntradaSalida', true, match[1]);
124
+ }
125
+ }
126
+
127
+ return new FieldResult('aduanaEntradaSalida', false, null);
128
+ },
129
+ },
130
+
131
+ // Pedimento Number
132
+ {
133
+ field: 'numPedimento',
134
+ extract: (source) => {
135
+ const patterns = [
136
+ /numPedimento[^>]*>(\d{15})<\/\w+:numPedimento/i,
137
+ /pedimento[:\s]*(\d{15})/i,
138
+ ];
139
+
140
+ for (const pattern of patterns) {
141
+ const match = source.match(pattern);
142
+ if (match) {
143
+ return new FieldResult('numPedimento', true, match[1]);
144
+ }
145
+ }
146
+
147
+ return new FieldResult('numPedimento', false, null);
148
+ },
149
+ },
150
+
151
+ // Email/Contact
152
+ {
153
+ field: 'email',
154
+ extract: (source) => {
155
+ const match = source.match(/[\w.-]+@[\w.-]+\.\w+/);
156
+ return new FieldResult('email', !!match, match ? match[0] : null);
157
+ },
158
+ },
159
+
160
+ // Type of Operation
161
+ {
162
+ field: 'tipoOperacion',
163
+ extract: (source) => {
164
+ const patterns = [
165
+ /tipoOperacion[^>]*>([A-Z]{4}[^<]*)<\/\w+:tipoOperacion/i,
166
+ /tipoOperacion[:\s]*([A-Z]{4})/i,
167
+ ];
168
+
169
+ for (const pattern of patterns) {
170
+ const match = source.match(pattern);
171
+ if (match) {
172
+ return new FieldResult('tipoOperacion', true, match[1]);
173
+ }
174
+ }
175
+
176
+ return new FieldResult('tipoOperacion', false, null);
177
+ },
178
+ },
179
+
180
+ // Document Date
181
+ {
182
+ field: 'documentDate',
183
+ extract: (source) => {
184
+ const patterns = [
185
+ /fechaExpedicion[^>]*>(\d{4}-\d{2}-\d{2})<\/\w+:fechaExpedicion/i,
186
+ /fecha[:\s]*(\d{4}-\d{2}-\d{2})/i,
187
+ ];
188
+
189
+ for (const pattern of patterns) {
190
+ const match = source.match(pattern);
191
+ if (match) {
192
+ return new FieldResult('documentDate', true, match[1]);
193
+ }
194
+ }
195
+
196
+ return new FieldResult('documentDate', false, null);
197
+ },
198
+ },
199
+ ],
200
+ };
@@ -0,0 +1,278 @@
1
+ import {
2
+ ApiError,
3
+ ArelaError,
4
+ ConfigurationError,
5
+ DatabaseError,
6
+ DetectionError,
7
+ FileOperationError,
8
+ NetworkError,
9
+ UploadServiceError,
10
+ ValidationError,
11
+ } from './ErrorTypes.js';
12
+
13
+ /**
14
+ * Error Handler Service
15
+ * Provides centralized error handling, logging, and user-friendly error messages
16
+ */
17
+ export class ErrorHandler {
18
+ constructor(logger) {
19
+ this.logger = logger;
20
+ }
21
+
22
+ /**
23
+ * Handle and format error for user display
24
+ * @param {Error} error - The error to handle
25
+ * @param {Object} context - Additional context about where the error occurred
26
+ * @returns {Object} Formatted error information
27
+ */
28
+ handleError(error, context = {}) {
29
+ const errorInfo = this.#analyzeError(error, context);
30
+
31
+ // Log the error with appropriate level
32
+ this.#logError(errorInfo);
33
+
34
+ return errorInfo;
35
+ }
36
+
37
+ /**
38
+ * Handle fatal errors that should terminate the application
39
+ * @param {Error} error - The fatal error
40
+ * @param {Object} context - Additional context
41
+ */
42
+ handleFatalError(error, context = {}) {
43
+ const errorInfo = this.handleError(error, context);
44
+
45
+ console.error('\n❌ Fatal Error - Application will exit');
46
+ console.error(` ${errorInfo.userMessage}`);
47
+
48
+ if (this.logger.isVerboseEnabled() && errorInfo.technicalDetails) {
49
+ console.error(` Technical Details: ${errorInfo.technicalDetails}`);
50
+ }
51
+
52
+ this.logger.flush();
53
+ process.exit(1);
54
+ }
55
+
56
+ /**
57
+ * Create a user-friendly error from a technical error
58
+ * @param {string} userMessage - User-friendly error message
59
+ * @param {Error} originalError - The original technical error
60
+ * @param {string} code - Error code
61
+ * @returns {ArelaError} User-friendly error
62
+ */
63
+ createUserFriendlyError(userMessage, originalError, code = 'USER_ERROR') {
64
+ const error = new ArelaError(userMessage, code, {
65
+ originalError: originalError.message,
66
+ originalStack: originalError.stack,
67
+ });
68
+
69
+ return error;
70
+ }
71
+
72
+ /**
73
+ * Analyze error and determine appropriate handling
74
+ * @private
75
+ * @param {Error} error - Error to analyze
76
+ * @param {Object} context - Error context
77
+ * @returns {Object} Error analysis result
78
+ */
79
+ #analyzeError(error, context) {
80
+ const analysis = {
81
+ type: error.constructor.name,
82
+ code: error.code || 'UNKNOWN_ERROR',
83
+ message: error.message,
84
+ userMessage: this.#getUserFriendlyMessage(error),
85
+ technicalDetails: error.details || null,
86
+ context,
87
+ timestamp: error.timestamp || new Date().toISOString(),
88
+ severity: this.#determineSeverity(error),
89
+ recoverable: this.#isRecoverable(error),
90
+ stack: error.stack,
91
+ };
92
+
93
+ return analysis;
94
+ }
95
+
96
+ /**
97
+ * Generate user-friendly error message
98
+ * @private
99
+ * @param {Error} error - Error to process
100
+ * @returns {string} User-friendly message
101
+ */
102
+ #getUserFriendlyMessage(error) {
103
+ if (error instanceof ConfigurationError) {
104
+ return `Configuration issue: ${error.message}`;
105
+ }
106
+
107
+ if (error instanceof FileOperationError) {
108
+ const filePath = error.details?.filePath;
109
+ return `File operation failed${filePath ? ` for ${filePath}` : ''}: ${error.message}`;
110
+ }
111
+
112
+ if (error instanceof UploadServiceError) {
113
+ const serviceName = error.details?.serviceName;
114
+ return `Upload failed${serviceName ? ` (${serviceName})` : ''}: ${error.message}`;
115
+ }
116
+
117
+ if (error instanceof ApiError) {
118
+ const statusCode = error.details?.statusCode;
119
+ return `API request failed${statusCode ? ` (HTTP ${statusCode})` : ''}: ${error.message}`;
120
+ }
121
+
122
+ if (error instanceof DatabaseError) {
123
+ const operation = error.details?.operation;
124
+ return `Database operation failed${operation ? ` (${operation})` : ''}: ${error.message}`;
125
+ }
126
+
127
+ if (error instanceof DetectionError) {
128
+ const filePath = error.details?.filePath;
129
+ return `File detection failed${filePath ? ` for ${filePath}` : ''}: ${error.message}`;
130
+ }
131
+
132
+ if (error instanceof ValidationError) {
133
+ const field = error.details?.field;
134
+ return `Validation failed${field ? ` for ${field}` : ''}: ${error.message}`;
135
+ }
136
+
137
+ if (error instanceof NetworkError) {
138
+ return `Network error: ${error.message}`;
139
+ }
140
+
141
+ if (error instanceof ArelaError) {
142
+ return error.message;
143
+ }
144
+
145
+ // Generic error handling
146
+ return `An unexpected error occurred: ${error.message}`;
147
+ }
148
+
149
+ /**
150
+ * Determine error severity
151
+ * @private
152
+ * @param {Error} error - Error to analyze
153
+ * @returns {string} Severity level
154
+ */
155
+ #determineSeverity(error) {
156
+ if (error instanceof ConfigurationError) {
157
+ return 'fatal';
158
+ }
159
+
160
+ if (error instanceof NetworkError || error instanceof ApiError) {
161
+ return 'high';
162
+ }
163
+
164
+ if (error instanceof DatabaseError || error instanceof UploadServiceError) {
165
+ return 'high';
166
+ }
167
+
168
+ if (
169
+ error instanceof FileOperationError ||
170
+ error instanceof DetectionError
171
+ ) {
172
+ return 'medium';
173
+ }
174
+
175
+ if (error instanceof ValidationError) {
176
+ return 'low';
177
+ }
178
+
179
+ return 'medium';
180
+ }
181
+
182
+ /**
183
+ * Determine if error is recoverable
184
+ * @private
185
+ * @param {Error} error - Error to analyze
186
+ * @returns {boolean} True if recoverable
187
+ */
188
+ #isRecoverable(error) {
189
+ if (error instanceof ConfigurationError) {
190
+ return false;
191
+ }
192
+
193
+ if (error instanceof NetworkError || error instanceof ApiError) {
194
+ // Network errors might be temporary
195
+ return true;
196
+ }
197
+
198
+ if (error instanceof FileOperationError) {
199
+ // File errors might be recoverable depending on the specific error
200
+ return true;
201
+ }
202
+
203
+ if (error instanceof DetectionError || error instanceof ValidationError) {
204
+ return true;
205
+ }
206
+
207
+ return false;
208
+ }
209
+
210
+ /**
211
+ * Log error with appropriate level
212
+ * @private
213
+ * @param {Object} errorInfo - Error analysis result
214
+ */
215
+ #logError(errorInfo) {
216
+ const logMessage = `${errorInfo.type}: ${errorInfo.message}`;
217
+ const contextInfo = errorInfo.context
218
+ ? ` | Context: ${JSON.stringify(errorInfo.context)}`
219
+ : '';
220
+ const detailsInfo = errorInfo.technicalDetails
221
+ ? ` | Details: ${JSON.stringify(errorInfo.technicalDetails)}`
222
+ : '';
223
+
224
+ const fullLogMessage = `${logMessage}${contextInfo}${detailsInfo}`;
225
+
226
+ switch (errorInfo.severity) {
227
+ case 'fatal':
228
+ this.logger.error(`FATAL: ${fullLogMessage}`);
229
+ break;
230
+ case 'high':
231
+ this.logger.error(`HIGH: ${fullLogMessage}`);
232
+ break;
233
+ case 'medium':
234
+ this.logger.warn(`MEDIUM: ${fullLogMessage}`);
235
+ break;
236
+ case 'low':
237
+ this.logger.info(`LOW: ${fullLogMessage}`);
238
+ break;
239
+ default:
240
+ this.logger.error(fullLogMessage);
241
+ }
242
+
243
+ // Log stack trace in verbose mode
244
+ if (this.logger.isVerboseEnabled() && errorInfo.stack) {
245
+ this.logger.debug(`Stack trace: ${errorInfo.stack}`);
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Wrap a function with error handling
251
+ * @param {Function} fn - Function to wrap
252
+ * @param {Object} context - Context for error handling
253
+ * @returns {Function} Wrapped function
254
+ */
255
+ wrapWithErrorHandling(fn, context = {}) {
256
+ return async (...args) => {
257
+ try {
258
+ return await fn(...args);
259
+ } catch (error) {
260
+ this.handleError(error, context);
261
+ throw error;
262
+ }
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Create error handler middleware for async operations
268
+ * @param {Object} context - Context for error handling
269
+ * @returns {Function} Error handler middleware
270
+ */
271
+ createAsyncErrorHandler(context = {}) {
272
+ return (error) => {
273
+ this.handleError(error, context);
274
+ };
275
+ }
276
+ }
277
+
278
+ export default ErrorHandler;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Custom Error Types for Arela Uploader
3
+ */
4
+
5
+ /**
6
+ * Base error class for Arela Uploader
7
+ */
8
+ export class ArelaError extends Error {
9
+ constructor(message, code = 'ARELA_ERROR', details = null) {
10
+ super(message);
11
+ this.name = this.constructor.name;
12
+ this.code = code;
13
+ this.details = details;
14
+ this.timestamp = new Date().toISOString();
15
+
16
+ // Ensure proper stack trace
17
+ if (Error.captureStackTrace) {
18
+ Error.captureStackTrace(this, this.constructor);
19
+ }
20
+ }
21
+
22
+ toJSON() {
23
+ return {
24
+ name: this.name,
25
+ message: this.message,
26
+ code: this.code,
27
+ details: this.details,
28
+ timestamp: this.timestamp,
29
+ stack: this.stack,
30
+ };
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Configuration related errors
36
+ */
37
+ export class ConfigurationError extends ArelaError {
38
+ constructor(message, details = null) {
39
+ super(message, 'CONFIGURATION_ERROR', details);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * File operation related errors
45
+ */
46
+ export class FileOperationError extends ArelaError {
47
+ constructor(message, filePath = null, details = null) {
48
+ super(message, 'FILE_OPERATION_ERROR', { filePath, ...details });
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Upload service related errors
54
+ */
55
+ export class UploadServiceError extends ArelaError {
56
+ constructor(message, serviceName = null, details = null) {
57
+ super(message, 'UPLOAD_SERVICE_ERROR', { serviceName, ...details });
58
+ }
59
+ }
60
+
61
+ /**
62
+ * API related errors
63
+ */
64
+ export class ApiError extends ArelaError {
65
+ constructor(message, statusCode = null, response = null, details = null) {
66
+ super(message, 'API_ERROR', { statusCode, response, ...details });
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Database operation related errors
72
+ */
73
+ export class DatabaseError extends ArelaError {
74
+ constructor(message, operation = null, details = null) {
75
+ super(message, 'DATABASE_ERROR', { operation, ...details });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * File detection related errors
81
+ */
82
+ export class DetectionError extends ArelaError {
83
+ constructor(message, filePath = null, details = null) {
84
+ super(message, 'DETECTION_ERROR', { filePath, ...details });
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Validation related errors
90
+ */
91
+ export class ValidationError extends ArelaError {
92
+ constructor(message, field = null, value = null, details = null) {
93
+ super(message, 'VALIDATION_ERROR', { field, value, ...details });
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Network related errors
99
+ */
100
+ export class NetworkError extends ArelaError {
101
+ constructor(message, url = null, details = null) {
102
+ super(message, 'NETWORK_ERROR', { url, ...details });
103
+ }
104
+ }