@arela/uploader 0.2.12 → 0.3.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 (38) hide show
  1. package/.env.template +66 -0
  2. package/.vscode/settings.json +1 -0
  3. package/README.md +134 -58
  4. package/SUPABASE_UPLOAD_FIX.md +157 -0
  5. package/package.json +3 -2
  6. package/scripts/cleanup-ds-store.js +109 -0
  7. package/scripts/cleanup-system-files.js +69 -0
  8. package/scripts/tests/phase-7-features.test.js +415 -0
  9. package/scripts/tests/signal-handling.test.js +275 -0
  10. package/scripts/tests/smart-watch-integration.test.js +554 -0
  11. package/scripts/tests/watch-service-integration.test.js +584 -0
  12. package/src/commands/UploadCommand.js +36 -2
  13. package/src/commands/WatchCommand.js +1305 -0
  14. package/src/config/config.js +113 -0
  15. package/src/document-type-shared.js +2 -0
  16. package/src/document-types/support-document.js +201 -0
  17. package/src/file-detection.js +2 -1
  18. package/src/index.js +44 -0
  19. package/src/services/AdvancedFilterService.js +505 -0
  20. package/src/services/AutoProcessingService.js +639 -0
  21. package/src/services/BenchmarkingService.js +381 -0
  22. package/src/services/DatabaseService.js +723 -170
  23. package/src/services/ErrorMonitor.js +275 -0
  24. package/src/services/LoggingService.js +419 -1
  25. package/src/services/MonitoringService.js +401 -0
  26. package/src/services/PerformanceOptimizer.js +511 -0
  27. package/src/services/ReportingService.js +511 -0
  28. package/src/services/SignalHandler.js +255 -0
  29. package/src/services/SmartWatchDatabaseService.js +527 -0
  30. package/src/services/WatchService.js +783 -0
  31. package/src/services/upload/ApiUploadService.js +30 -4
  32. package/src/services/upload/SupabaseUploadService.js +28 -6
  33. package/src/utils/CleanupManager.js +262 -0
  34. package/src/utils/FileOperations.js +41 -0
  35. package/src/utils/WatchEventHandler.js +517 -0
  36. package/supabase/migrations/001_create_initial_schema.sql +366 -0
  37. package/supabase/migrations/002_align_with_arela_api_schema.sql +145 -0
  38. package/commands.md +0 -6
@@ -0,0 +1,381 @@
1
+ /**
2
+ * BenchmarkingService.js
3
+ * Phase 7 - Task 3: Performance Benchmarking
4
+ *
5
+ * Provides comprehensive performance benchmarking including:
6
+ * - Execution benchmarking
7
+ * - Memory profiling
8
+ * - Resource utilization tracking
9
+ * - Benchmark comparison
10
+ * - Performance regression detection
11
+ */
12
+
13
+ class BenchmarkingService {
14
+ constructor(logger) {
15
+ this.logger = logger;
16
+ this.benchmarks = [];
17
+ this.profiles = [];
18
+
19
+ this.config = {
20
+ enableMemoryProfiling: true,
21
+ enableCpuProfiling: true,
22
+ sampleInterval: 100, // milliseconds
23
+ retainLimit: 100, // keep last N benchmarks
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Start a benchmark session
29
+ */
30
+ startBenchmark(name, metadata = {}) {
31
+ const benchmark = {
32
+ id: `bench_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
33
+ name,
34
+ startTime: Date.now(),
35
+ startMemory: process.memoryUsage(),
36
+ metadata,
37
+ marks: [],
38
+ measurements: [],
39
+ complete: false,
40
+ };
41
+
42
+ return benchmark;
43
+ }
44
+
45
+ /**
46
+ * Mark a point in benchmark
47
+ */
48
+ mark(benchmark, markName) {
49
+ const mark = {
50
+ name: markName,
51
+ timestamp: Date.now(),
52
+ memory: process.memoryUsage(),
53
+ };
54
+
55
+ benchmark.marks.push(mark);
56
+ return mark;
57
+ }
58
+
59
+ /**
60
+ * Complete benchmark and calculate metrics
61
+ */
62
+ completeBenchmark(benchmark) {
63
+ const endTime = Date.now();
64
+ const endMemory = process.memoryUsage();
65
+
66
+ benchmark.endTime = endTime;
67
+ benchmark.endMemory = endMemory;
68
+ benchmark.complete = true;
69
+
70
+ // Calculate overall duration
71
+ benchmark.duration = endTime - benchmark.startTime;
72
+
73
+ // Calculate memory changes
74
+ benchmark.memoryDelta = {
75
+ heapUsed: endMemory.heapUsed - benchmark.startMemory.heapUsed,
76
+ heapTotal: endMemory.heapTotal - benchmark.startMemory.heapTotal,
77
+ external: endMemory.external - benchmark.startMemory.external,
78
+ rss: endMemory.rss - benchmark.startMemory.rss,
79
+ };
80
+
81
+ // Calculate mark durations
82
+ benchmark.measurements = [];
83
+ for (let i = 0; i < benchmark.marks.length; i++) {
84
+ const current = benchmark.marks[i];
85
+ const previous =
86
+ i > 0 ? benchmark.marks[i - 1] : { timestamp: benchmark.startTime };
87
+
88
+ const measurement = {
89
+ markName: current.name,
90
+ duration: current.timestamp - previous.timestamp,
91
+ memoryUsed: current.memory.heapUsed,
92
+ memoryDelta: current.memory.heapUsed - previous.memory.heapUsed,
93
+ };
94
+
95
+ benchmark.measurements.push(measurement);
96
+ }
97
+
98
+ // Store benchmark
99
+ this.benchmarks.push(benchmark);
100
+
101
+ // Maintain retention limit
102
+ if (this.benchmarks.length > this.config.retainLimit) {
103
+ this.benchmarks = this.benchmarks.slice(-this.config.retainLimit);
104
+ }
105
+
106
+ this.logger.debug(
107
+ `Benchmark completed: ${benchmark.name} (${benchmark.duration}ms, ` +
108
+ `Memory: ${(benchmark.memoryDelta.heapUsed / 1024 / 1024).toFixed(2)}MB)`,
109
+ );
110
+
111
+ return benchmark;
112
+ }
113
+
114
+ /**
115
+ * Profile memory usage over time
116
+ */
117
+ async profileMemory(testFunction, duration = 5000) {
118
+ const profile = {
119
+ id: `profile_${Date.now()}`,
120
+ timestamp: new Date().toISOString(),
121
+ duration,
122
+ samples: [],
123
+ summary: {},
124
+ };
125
+
126
+ const startTime = Date.now();
127
+ const sampleInterval = this.config.sampleInterval;
128
+
129
+ // Start test function
130
+ const testPromise = testFunction();
131
+
132
+ // Collect samples
133
+ const samplingPromise = new Promise((resolve) => {
134
+ const sampler = setInterval(() => {
135
+ const memory = process.memoryUsage();
136
+ profile.samples.push({
137
+ timestamp: Date.now() - startTime,
138
+ heapUsed: memory.heapUsed,
139
+ heapTotal: memory.heapTotal,
140
+ rss: memory.rss,
141
+ });
142
+
143
+ if (Date.now() - startTime >= duration) {
144
+ clearInterval(sampler);
145
+ resolve();
146
+ }
147
+ }, sampleInterval);
148
+ });
149
+
150
+ // Wait for both to complete
151
+ await Promise.all([testPromise, samplingPromise]);
152
+
153
+ // Calculate summary statistics
154
+ if (profile.samples.length > 0) {
155
+ const heapSamples = profile.samples.map((s) => s.heapUsed);
156
+ const rssSamples = profile.samples.map((s) => s.rss);
157
+
158
+ profile.summary = {
159
+ peakHeapUsed: Math.max(...heapSamples),
160
+ minHeapUsed: Math.min(...heapSamples),
161
+ averageHeapUsed:
162
+ heapSamples.reduce((a, b) => a + b, 0) / heapSamples.length,
163
+ heapGrowth: heapSamples[heapSamples.length - 1] - heapSamples[0],
164
+ peakRss: Math.max(...rssSamples),
165
+ sampleCount: profile.samples.length,
166
+ };
167
+ }
168
+
169
+ this.profiles.push(profile);
170
+ return profile;
171
+ }
172
+
173
+ /**
174
+ * Compare two benchmarks
175
+ */
176
+ compareBenchmarks(benchmark1, benchmark2) {
177
+ const comparison = {
178
+ benchmark1: benchmark1.name,
179
+ benchmark2: benchmark2.name,
180
+ timestamp: new Date().toISOString(),
181
+ durationComparison: {
182
+ benchmark1Duration: benchmark1.duration,
183
+ benchmark2Duration: benchmark2.duration,
184
+ difference: benchmark2.duration - benchmark1.duration,
185
+ percentChange:
186
+ (
187
+ ((benchmark2.duration - benchmark1.duration) /
188
+ benchmark1.duration) *
189
+ 100
190
+ ).toFixed(2) + '%',
191
+ faster:
192
+ benchmark1.duration < benchmark2.duration
193
+ ? benchmark1.name
194
+ : benchmark2.name,
195
+ },
196
+ memoryComparison: {
197
+ benchmark1: benchmark1.memoryDelta,
198
+ benchmark2: benchmark2.memoryDelta,
199
+ difference: {
200
+ heapUsed:
201
+ benchmark2.memoryDelta.heapUsed - benchmark1.memoryDelta.heapUsed,
202
+ rss: benchmark2.memoryDelta.rss - benchmark1.memoryDelta.rss,
203
+ },
204
+ },
205
+ };
206
+
207
+ return comparison;
208
+ }
209
+
210
+ /**
211
+ * Detect performance regression
212
+ */
213
+ detectRegression(baselineIndex, currentIndex, threshold = 0.1) {
214
+ if (
215
+ currentIndex >= this.benchmarks.length ||
216
+ baselineIndex >= this.benchmarks.length
217
+ ) {
218
+ return null;
219
+ }
220
+
221
+ const baseline = this.benchmarks[baselineIndex];
222
+ const current = this.benchmarks[currentIndex];
223
+
224
+ const durationIncrease =
225
+ (current.duration - baseline.duration) / baseline.duration;
226
+ const memoryIncrease =
227
+ (current.memoryDelta.heapUsed - baseline.memoryDelta.heapUsed) /
228
+ Math.abs(baseline.memoryDelta.heapUsed || 1);
229
+
230
+ const regression = {
231
+ detected: false,
232
+ baseline: baseline.name,
233
+ current: current.name,
234
+ metrics: {
235
+ duration: {
236
+ baseline: baseline.duration,
237
+ current: current.duration,
238
+ increase: durationIncrease,
239
+ thresholdExceeded: durationIncrease > threshold,
240
+ },
241
+ memory: {
242
+ baseline: baseline.memoryDelta.heapUsed,
243
+ current: current.memoryDelta.heapUsed,
244
+ increase: memoryIncrease,
245
+ thresholdExceeded: Math.abs(memoryIncrease) > threshold,
246
+ },
247
+ },
248
+ };
249
+
250
+ regression.detected =
251
+ regression.metrics.duration.thresholdExceeded ||
252
+ regression.metrics.memory.thresholdExceeded;
253
+
254
+ return regression;
255
+ }
256
+
257
+ /**
258
+ * Get benchmark statistics
259
+ */
260
+ getBenchmarkStatistics() {
261
+ if (this.benchmarks.length === 0) {
262
+ return { error: 'No benchmarks available' };
263
+ }
264
+
265
+ const durations = this.benchmarks.map((b) => b.duration);
266
+ const memoryDeltas = this.benchmarks.map((b) => b.memoryDelta.heapUsed);
267
+
268
+ return {
269
+ totalBenchmarks: this.benchmarks.length,
270
+ averageDuration:
271
+ (durations.reduce((a, b) => a + b, 0) / durations.length).toFixed(0) +
272
+ 'ms',
273
+ minDuration: Math.min(...durations) + 'ms',
274
+ maxDuration: Math.max(...durations) + 'ms',
275
+ medianDuration: this._calculateMedian(durations) + 'ms',
276
+ averageMemoryDelta:
277
+ (
278
+ memoryDeltas.reduce((a, b) => a + b, 0) /
279
+ memoryDeltas.length /
280
+ 1024 /
281
+ 1024
282
+ ).toFixed(2) + 'MB',
283
+ standardDeviation:
284
+ this._calculateStandardDeviation(durations).toFixed(0) + 'ms',
285
+ };
286
+ }
287
+
288
+ /**
289
+ * Get memory profile summary
290
+ */
291
+ getMemoryProfileSummary() {
292
+ if (this.profiles.length === 0) {
293
+ return { error: 'No memory profiles available' };
294
+ }
295
+
296
+ const recentProfiles = this.profiles.slice(-5);
297
+ const avgPeakHeap =
298
+ recentProfiles.reduce(
299
+ (sum, p) => sum + (p.summary.peakHeapUsed || 0),
300
+ 0,
301
+ ) / recentProfiles.length;
302
+ const avgHeapGrowth =
303
+ recentProfiles.reduce((sum, p) => sum + (p.summary.heapGrowth || 0), 0) /
304
+ recentProfiles.length;
305
+
306
+ return {
307
+ profileCount: this.profiles.length,
308
+ recentProfiles: recentProfiles.length,
309
+ averagePeakHeap: (avgPeakHeap / 1024 / 1024).toFixed(2) + 'MB',
310
+ averageHeapGrowth: (avgHeapGrowth / 1024 / 1024).toFixed(2) + 'MB',
311
+ lastProfile: recentProfiles[recentProfiles.length - 1].summary,
312
+ };
313
+ }
314
+
315
+ /**
316
+ * Generate benchmark report
317
+ */
318
+ generateBenchmarkReport() {
319
+ const report = {
320
+ timestamp: new Date().toISOString(),
321
+ benchmarkCount: this.benchmarks.length,
322
+ profileCount: this.profiles.length,
323
+ statistics: this.getBenchmarkStatistics(),
324
+ memoryProfiles: this.getMemoryProfileSummary(),
325
+ benchmarks: this.benchmarks.map((b) => ({
326
+ id: b.id,
327
+ name: b.name,
328
+ duration: b.duration + 'ms',
329
+ memoryDelta: {
330
+ heapUsed: (b.memoryDelta.heapUsed / 1024 / 1024).toFixed(2) + 'MB',
331
+ rss: (b.memoryDelta.rss / 1024 / 1024).toFixed(2) + 'MB',
332
+ },
333
+ markCount: b.marks.length,
334
+ })),
335
+ };
336
+
337
+ return report;
338
+ }
339
+
340
+ /**
341
+ * Clear benchmarks
342
+ */
343
+ clearBenchmarks() {
344
+ const count = this.benchmarks.length;
345
+ this.benchmarks = [];
346
+ this.logger.info(`Cleared ${count} benchmarks`);
347
+ return { cleared: count };
348
+ }
349
+
350
+ /**
351
+ * Clear profiles
352
+ */
353
+ clearProfiles() {
354
+ const count = this.profiles.length;
355
+ this.profiles = [];
356
+ this.logger.info(`Cleared ${count} memory profiles`);
357
+ return { cleared: count };
358
+ }
359
+
360
+ /**
361
+ * Private helper methods
362
+ */
363
+
364
+ _calculateMedian(values) {
365
+ const sorted = [...values].sort((a, b) => a - b);
366
+ const mid = Math.floor(sorted.length / 2);
367
+ return sorted.length % 2
368
+ ? sorted[mid]
369
+ : (sorted[mid - 1] + sorted[mid]) / 2;
370
+ }
371
+
372
+ _calculateStandardDeviation(values) {
373
+ const mean = values.reduce((a, b) => a + b, 0) / values.length;
374
+ const variance =
375
+ values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) /
376
+ values.length;
377
+ return Math.sqrt(variance);
378
+ }
379
+ }
380
+
381
+ export default BenchmarkingService;