@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.
- package/.env.template +66 -0
- package/README.md +263 -62
- package/docs/API_ENDPOINTS_FOR_DETECTION.md +647 -0
- package/docs/QUICK_REFERENCE_API_DETECTION.md +264 -0
- package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +200 -0
- package/package.json +3 -2
- package/scripts/cleanup-ds-store.js +109 -0
- package/scripts/cleanup-system-files.js +69 -0
- package/scripts/tests/phase-7-features.test.js +415 -0
- package/scripts/tests/signal-handling.test.js +275 -0
- package/scripts/tests/smart-watch-integration.test.js +554 -0
- package/scripts/tests/watch-service-integration.test.js +584 -0
- package/src/commands/UploadCommand.js +31 -4
- package/src/commands/WatchCommand.js +1342 -0
- package/src/config/config.js +270 -2
- package/src/document-type-shared.js +2 -0
- package/src/document-types/support-document.js +200 -0
- package/src/file-detection.js +9 -1
- package/src/index.js +163 -4
- package/src/services/AdvancedFilterService.js +505 -0
- package/src/services/AutoProcessingService.js +749 -0
- package/src/services/BenchmarkingService.js +381 -0
- package/src/services/DatabaseService.js +1019 -539
- package/src/services/ErrorMonitor.js +275 -0
- package/src/services/LoggingService.js +419 -1
- package/src/services/MonitoringService.js +401 -0
- package/src/services/PerformanceOptimizer.js +511 -0
- package/src/services/ReportingService.js +511 -0
- package/src/services/SignalHandler.js +255 -0
- package/src/services/SmartWatchDatabaseService.js +527 -0
- package/src/services/WatchService.js +783 -0
- package/src/services/upload/ApiUploadService.js +447 -3
- package/src/services/upload/MultiApiUploadService.js +233 -0
- package/src/services/upload/SupabaseUploadService.js +12 -5
- package/src/services/upload/UploadServiceFactory.js +24 -0
- package/src/utils/CleanupManager.js +262 -0
- package/src/utils/FileOperations.js +44 -0
- package/src/utils/WatchEventHandler.js +522 -0
- package/supabase/migrations/001_create_initial_schema.sql +366 -0
- package/supabase/migrations/002_align_with_arela_api_schema.sql +145 -0
- package/.envbackup +0 -37
- package/SUPABASE_UPLOAD_FIX.md +0 -157
- package/commands.md +0 -14
|
@@ -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;
|