@arela/uploader 0.2.13 → 1.0.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 (43) hide show
  1. package/.env.template +66 -0
  2. package/README.md +263 -62
  3. package/docs/API_ENDPOINTS_FOR_DETECTION.md +647 -0
  4. package/docs/QUICK_REFERENCE_API_DETECTION.md +264 -0
  5. package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +200 -0
  6. package/package.json +3 -2
  7. package/scripts/cleanup-ds-store.js +109 -0
  8. package/scripts/cleanup-system-files.js +69 -0
  9. package/scripts/tests/phase-7-features.test.js +415 -0
  10. package/scripts/tests/signal-handling.test.js +275 -0
  11. package/scripts/tests/smart-watch-integration.test.js +554 -0
  12. package/scripts/tests/watch-service-integration.test.js +584 -0
  13. package/src/commands/UploadCommand.js +31 -4
  14. package/src/commands/WatchCommand.js +1342 -0
  15. package/src/config/config.js +270 -2
  16. package/src/document-type-shared.js +2 -0
  17. package/src/document-types/support-document.js +200 -0
  18. package/src/file-detection.js +9 -1
  19. package/src/index.js +163 -4
  20. package/src/services/AdvancedFilterService.js +505 -0
  21. package/src/services/AutoProcessingService.js +749 -0
  22. package/src/services/BenchmarkingService.js +381 -0
  23. package/src/services/DatabaseService.js +1019 -539
  24. package/src/services/ErrorMonitor.js +275 -0
  25. package/src/services/LoggingService.js +419 -1
  26. package/src/services/MonitoringService.js +401 -0
  27. package/src/services/PerformanceOptimizer.js +511 -0
  28. package/src/services/ReportingService.js +511 -0
  29. package/src/services/SignalHandler.js +255 -0
  30. package/src/services/SmartWatchDatabaseService.js +527 -0
  31. package/src/services/WatchService.js +783 -0
  32. package/src/services/upload/ApiUploadService.js +447 -3
  33. package/src/services/upload/MultiApiUploadService.js +233 -0
  34. package/src/services/upload/SupabaseUploadService.js +12 -5
  35. package/src/services/upload/UploadServiceFactory.js +24 -0
  36. package/src/utils/CleanupManager.js +262 -0
  37. package/src/utils/FileOperations.js +44 -0
  38. package/src/utils/WatchEventHandler.js +522 -0
  39. package/supabase/migrations/001_create_initial_schema.sql +366 -0
  40. package/supabase/migrations/002_align_with_arela_api_schema.sql +145 -0
  41. package/.envbackup +0 -37
  42. package/SUPABASE_UPLOAD_FIX.md +0 -157
  43. package/commands.md +0 -14
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Error Monitor Service
3
+ * Tracks, logs, and monitors errors during signal handling and cleanup operations
4
+ * Provides detailed error reporting and failure recovery mechanisms
5
+ */
6
+ export class ErrorMonitor {
7
+ constructor(logger, cleanupManager, signalHandler) {
8
+ this.logger = logger;
9
+ this.cleanupManager = cleanupManager;
10
+ this.signalHandler = signalHandler;
11
+
12
+ /**
13
+ * Array of recorded errors
14
+ * @type {Array<Object>}
15
+ */
16
+ this.errors = [];
17
+
18
+ /**
19
+ * Error categories
20
+ * @type {Object}
21
+ */
22
+ this.errorCategories = {
23
+ SIGNAL: 'signal_error',
24
+ CLEANUP: 'cleanup_error',
25
+ DATABASE: 'database_error',
26
+ WATCH_SERVICE: 'watch_service_error',
27
+ LOGGING: 'logging_error',
28
+ GENERAL: 'general_error',
29
+ };
30
+
31
+ /**
32
+ * Error statistics
33
+ * @type {Object}
34
+ */
35
+ this.stats = {
36
+ totalErrors: 0,
37
+ errorsByCategory: {},
38
+ fatalErrors: 0,
39
+ recoveredErrors: 0,
40
+ lastErrorTime: null,
41
+ };
42
+
43
+ // Initialize error category stats
44
+ for (const category of Object.values(this.errorCategories)) {
45
+ this.stats.errorsByCategory[category] = 0;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Record an error occurrence
51
+ * @param {string} category - Error category
52
+ * @param {string} message - Error message
53
+ * @param {Error} error - Error object
54
+ * @param {Object} context - Additional context
55
+ * @param {boolean} isFatal - Whether error is fatal
56
+ * @returns {Object} Error record
57
+ */
58
+ recordError(category, message, error, context = {}, isFatal = false) {
59
+ const errorRecord = {
60
+ id: `err_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
61
+ timestamp: new Date().toISOString(),
62
+ category,
63
+ message,
64
+ isFatal,
65
+ stack: error?.stack || null,
66
+ context,
67
+ signal: this.signalHandler?.getSignalReceived() || null,
68
+ resolved: false,
69
+ };
70
+
71
+ this.errors.push(errorRecord);
72
+ this.stats.totalErrors++;
73
+ this.stats.errorsByCategory[category]++;
74
+ this.stats.lastErrorTime = errorRecord.timestamp;
75
+
76
+ if (isFatal) {
77
+ this.stats.fatalErrors++;
78
+ this.logger.error(
79
+ `🚨 FATAL ERROR [${category}]: ${message} - ${error?.message}`,
80
+ );
81
+ } else {
82
+ this.logger.warn(
83
+ `⚠️ ERROR [${category}]: ${message} - ${error?.message}`,
84
+ );
85
+ }
86
+
87
+ return errorRecord;
88
+ }
89
+
90
+ /**
91
+ * Mark an error as resolved
92
+ * @param {string} errorId - Error ID to resolve
93
+ * @returns {boolean} True if resolved
94
+ */
95
+ resolveError(errorId) {
96
+ const errorRecord = this.errors.find((e) => e.id === errorId);
97
+ if (errorRecord) {
98
+ errorRecord.resolved = true;
99
+ this.stats.recoveredErrors++;
100
+ this.logger.info(`✅ Error resolved: ${errorId}`);
101
+ return true;
102
+ }
103
+ return false;
104
+ }
105
+
106
+ /**
107
+ * Get all unresolved errors
108
+ * @returns {Array<Object>} Unresolved error records
109
+ */
110
+ getUnresolvedErrors() {
111
+ return this.errors.filter((e) => !e.resolved);
112
+ }
113
+
114
+ /**
115
+ * Get errors by category
116
+ * @param {string} category - Error category
117
+ * @returns {Array<Object>} Errors in category
118
+ */
119
+ getErrorsByCategory(category) {
120
+ return this.errors.filter((e) => e.category === category);
121
+ }
122
+
123
+ /**
124
+ * Check if critical errors occurred
125
+ * @returns {boolean} True if there are fatal errors
126
+ */
127
+ hasCriticalErrors() {
128
+ return this.stats.fatalErrors > 0;
129
+ }
130
+
131
+ /**
132
+ * Get error statistics
133
+ * @returns {Object} Error statistics
134
+ */
135
+ getStatistics() {
136
+ return {
137
+ totalErrors: this.stats.totalErrors,
138
+ fatalErrors: this.stats.fatalErrors,
139
+ recoveredErrors: this.stats.recoveredErrors,
140
+ unresolvedErrors: this.getUnresolvedErrors().length,
141
+ errorsByCategory: { ...this.stats.errorsByCategory },
142
+ lastErrorTime: this.stats.lastErrorTime,
143
+ successRate:
144
+ this.stats.totalErrors > 0
145
+ ? (
146
+ (this.stats.recoveredErrors / this.stats.totalErrors) *
147
+ 100
148
+ ).toFixed(2)
149
+ : 100,
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Generate detailed error report
155
+ * @returns {string} Formatted error report
156
+ */
157
+ generateErrorReport() {
158
+ const stats = this.getStatistics();
159
+ let report =
160
+ '\n═══════════════════════════════════════════════════════════\n';
161
+ report += 'ERROR MONITORING REPORT\n';
162
+ report += '═══════════════════════════════════════════════════════════\n\n';
163
+
164
+ report += 'STATISTICS\n';
165
+ report += `├─ Total Errors: ${stats.totalErrors}\n`;
166
+ report += `├─ Fatal Errors: ${stats.fatalErrors}\n`;
167
+ report += `├─ Recovered Errors: ${stats.recoveredErrors}\n`;
168
+ report += `├─ Unresolved Errors: ${stats.unresolvedErrors}\n`;
169
+ report += `├─ Recovery Rate: ${stats.successRate}%\n`;
170
+ report += `└─ Last Error: ${stats.lastErrorTime || 'None'}\n\n`;
171
+
172
+ if (this.errors.length > 0) {
173
+ report += 'ERROR DETAILS (Last 10)\n';
174
+ const recentErrors = this.errors.slice(-10);
175
+ recentErrors.forEach((err, idx) => {
176
+ const status = err.resolved ? '✅' : '❌';
177
+ const severity = err.isFatal ? '🚨' : '⚠️ ';
178
+ report += `${idx + 1}. ${status} ${severity} [${err.category}]\n`;
179
+ report += ` Message: ${err.message}\n`;
180
+ report += ` Time: ${err.timestamp}\n`;
181
+ if (err.signal) {
182
+ report += ` Signal: ${err.signal}\n`;
183
+ }
184
+ report += '\n';
185
+ });
186
+ }
187
+
188
+ report += '═══════════════════════════════════════════════════════════\n';
189
+ return report;
190
+ }
191
+
192
+ /**
193
+ * Clear error history (useful after processing)
194
+ * @returns {void}
195
+ */
196
+ clearErrors() {
197
+ const count = this.errors.length;
198
+ this.errors = [];
199
+ this.logger.debug(`ErrorMonitor: Cleared ${count} error records`);
200
+ }
201
+
202
+ /**
203
+ * Get error monitor status
204
+ * @returns {Object} Status information
205
+ */
206
+ getStatus() {
207
+ return {
208
+ isHealthy: this.stats.fatalErrors === 0,
209
+ hasErrors: this.stats.totalErrors > 0,
210
+ unresolvedCount: this.getUnresolvedErrors().length,
211
+ stats: this.getStatistics(),
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Validate cleanup operation for errors
217
+ * @param {Object} cleanupResult - Result from cleanup operation
218
+ * @returns {Object} Validation result
219
+ */
220
+ validateCleanupResult(cleanupResult) {
221
+ const validation = {
222
+ isValid: cleanupResult.failureCount === 0,
223
+ failureCount: cleanupResult.failureCount,
224
+ successCount: cleanupResult.successCount,
225
+ issues: [],
226
+ };
227
+
228
+ if (cleanupResult.results) {
229
+ for (const result of cleanupResult.results) {
230
+ if (!result.success) {
231
+ validation.issues.push({
232
+ resource: result.name,
233
+ error: result.error,
234
+ duration: result.duration,
235
+ });
236
+
237
+ this.recordError(
238
+ this.errorCategories.CLEANUP,
239
+ `Cleanup failed for ${result.name}`,
240
+ new Error(result.error),
241
+ { resource: result.name, duration: result.duration },
242
+ false,
243
+ );
244
+ }
245
+ }
246
+ }
247
+
248
+ return validation;
249
+ }
250
+
251
+ /**
252
+ * Reset monitor state (for testing)
253
+ * @returns {void}
254
+ */
255
+ reset() {
256
+ this.errors = [];
257
+ this.stats.totalErrors = 0;
258
+ this.stats.fatalErrors = 0;
259
+ this.stats.recoveredErrors = 0;
260
+ this.stats.lastErrorTime = null;
261
+
262
+ for (const category of Object.keys(this.stats.errorsByCategory)) {
263
+ this.stats.errorsByCategory[category] = 0;
264
+ }
265
+
266
+ this.logger.debug('ErrorMonitor: Reset to initial state');
267
+ }
268
+ }
269
+
270
+ // Export singleton
271
+ export function createErrorMonitor(logger, cleanupManager, signalHandler) {
272
+ return new ErrorMonitor(logger, cleanupManager, signalHandler);
273
+ }
274
+
275
+ export default ErrorMonitor;