@dynamicu/chromedebug-mcp 2.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.
- package/CLAUDE.md +344 -0
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/chrome-extension/README.md +41 -0
- package/chrome-extension/background.js +3917 -0
- package/chrome-extension/chrome-session-manager.js +706 -0
- package/chrome-extension/content.css +181 -0
- package/chrome-extension/content.js +3022 -0
- package/chrome-extension/data-buffer.js +435 -0
- package/chrome-extension/dom-tracker.js +411 -0
- package/chrome-extension/extension-config.js +78 -0
- package/chrome-extension/firebase-client.js +278 -0
- package/chrome-extension/firebase-config.js +32 -0
- package/chrome-extension/firebase-config.module.js +22 -0
- package/chrome-extension/firebase-config.module.template.js +27 -0
- package/chrome-extension/firebase-config.template.js +36 -0
- package/chrome-extension/frame-capture.js +407 -0
- package/chrome-extension/icon128.png +1 -0
- package/chrome-extension/icon16.png +1 -0
- package/chrome-extension/icon48.png +1 -0
- package/chrome-extension/license-helper.js +181 -0
- package/chrome-extension/logger.js +23 -0
- package/chrome-extension/manifest.json +73 -0
- package/chrome-extension/network-tracker.js +510 -0
- package/chrome-extension/offscreen.html +10 -0
- package/chrome-extension/options.html +203 -0
- package/chrome-extension/options.js +282 -0
- package/chrome-extension/pako.min.js +2 -0
- package/chrome-extension/performance-monitor.js +533 -0
- package/chrome-extension/pii-redactor.js +405 -0
- package/chrome-extension/popup.html +532 -0
- package/chrome-extension/popup.js +2446 -0
- package/chrome-extension/upload-manager.js +323 -0
- package/chrome-extension/web-vitals.iife.js +1 -0
- package/config/api-keys.json +11 -0
- package/config/chrome-pilot-config.json +45 -0
- package/package.json +126 -0
- package/scripts/cleanup-processes.js +109 -0
- package/scripts/config-manager.js +280 -0
- package/scripts/generate-extension-config.js +53 -0
- package/scripts/setup-security.js +64 -0
- package/src/capture/architecture.js +426 -0
- package/src/capture/error-handling-tests.md +38 -0
- package/src/capture/error-handling-types.ts +360 -0
- package/src/capture/index.js +508 -0
- package/src/capture/interfaces.js +625 -0
- package/src/capture/memory-manager.js +713 -0
- package/src/capture/types.js +342 -0
- package/src/chrome-controller.js +2658 -0
- package/src/cli.js +19 -0
- package/src/config-loader.js +303 -0
- package/src/database.js +2178 -0
- package/src/firebase-license-manager.js +462 -0
- package/src/firebase-privacy-guard.js +397 -0
- package/src/http-server.js +1516 -0
- package/src/index-direct.js +157 -0
- package/src/index-modular.js +219 -0
- package/src/index-monolithic-backup.js +2230 -0
- package/src/index.js +305 -0
- package/src/legacy/chrome-controller-old.js +1406 -0
- package/src/legacy/index-express.js +625 -0
- package/src/legacy/index-old.js +977 -0
- package/src/legacy/routes.js +260 -0
- package/src/legacy/shared-storage.js +101 -0
- package/src/logger.js +10 -0
- package/src/mcp/handlers/chrome-tool-handler.js +306 -0
- package/src/mcp/handlers/element-tool-handler.js +51 -0
- package/src/mcp/handlers/frame-tool-handler.js +957 -0
- package/src/mcp/handlers/request-handler.js +104 -0
- package/src/mcp/handlers/workflow-tool-handler.js +636 -0
- package/src/mcp/server.js +68 -0
- package/src/mcp/tools/index.js +701 -0
- package/src/middleware/auth.js +371 -0
- package/src/middleware/security.js +267 -0
- package/src/port-discovery.js +258 -0
- package/src/routes/admin.js +182 -0
- package/src/services/browser-daemon.js +494 -0
- package/src/services/chrome-service.js +375 -0
- package/src/services/failover-manager.js +412 -0
- package/src/services/git-safety-service.js +675 -0
- package/src/services/heartbeat-manager.js +200 -0
- package/src/services/http-client.js +195 -0
- package/src/services/process-manager.js +318 -0
- package/src/services/process-tracker.js +574 -0
- package/src/services/profile-manager.js +449 -0
- package/src/services/project-manager.js +415 -0
- package/src/services/session-manager.js +497 -0
- package/src/services/session-registry.js +491 -0
- package/src/services/unified-session-manager.js +678 -0
- package/src/shared-storage-old.js +267 -0
- package/src/standalone-server.js +53 -0
- package/src/utils/extension-path.js +145 -0
- package/src/utils.js +187 -0
- package/src/validation/log-transformer.js +125 -0
- package/src/validation/schemas.js +391 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
// Performance Monitor for Chrome Debug Full Data Recording
|
|
2
|
+
// Tracks CPU usage, memory consumption, and Core Web Vitals
|
|
3
|
+
|
|
4
|
+
class PerformanceMonitor {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.isMonitoring = false;
|
|
7
|
+
this.stats = {
|
|
8
|
+
cpuUsage: 0,
|
|
9
|
+
memoryUsage: 0,
|
|
10
|
+
dataVolume: 0,
|
|
11
|
+
eventCount: 0,
|
|
12
|
+
bufferSize: 0,
|
|
13
|
+
lastCheck: Date.now(),
|
|
14
|
+
// Web Vitals
|
|
15
|
+
lcp: null,
|
|
16
|
+
cls: null,
|
|
17
|
+
fid: null,
|
|
18
|
+
inp: null,
|
|
19
|
+
ttfb: null
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
this.thresholds = {
|
|
23
|
+
cpuUsage: 80, // % - throttle recording if exceeded
|
|
24
|
+
memoryUsage: 100 * 1024 * 1024, // 100MB
|
|
25
|
+
dataVolumePerSecond: 1024 * 1024, // 1MB/sec
|
|
26
|
+
eventCountPerSecond: 100,
|
|
27
|
+
// Web Vitals thresholds
|
|
28
|
+
lcp: 2500, // 2.5s is "good" LCP
|
|
29
|
+
cls: 0.1, // 0.1 is "good" CLS
|
|
30
|
+
inp: 200 // 200ms is "good" INP
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
this.callbacks = {
|
|
34
|
+
onThrottleRequired: null,
|
|
35
|
+
onPerformanceAlert: null,
|
|
36
|
+
onStatsUpdate: null
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
this.monitoringInterval = null;
|
|
40
|
+
this.dataBuffer = null;
|
|
41
|
+
this.startTime = Date.now();
|
|
42
|
+
this.webVitalsUnsubscribers = [];
|
|
43
|
+
this.performanceObserver = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init(dataBuffer, callbacks = {}) {
|
|
47
|
+
this.dataBuffer = dataBuffer;
|
|
48
|
+
this.callbacks = { ...this.callbacks, ...callbacks };
|
|
49
|
+
|
|
50
|
+
// Just prepare for monitoring, don't start yet (lazy loading)
|
|
51
|
+
console.log('[PerformanceMonitor] Initialized (lazy mode - not started)');
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
startMonitoring() {
|
|
56
|
+
if (this.isMonitoring) {
|
|
57
|
+
console.log('[PerformanceMonitor] Already monitoring');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isMonitoring = true;
|
|
62
|
+
this.startTime = Date.now();
|
|
63
|
+
|
|
64
|
+
// Start Web Vitals collection
|
|
65
|
+
this.startWebVitalsCollection();
|
|
66
|
+
|
|
67
|
+
// Start resource monitoring
|
|
68
|
+
if (performance && performance.memory) {
|
|
69
|
+
this.startResourceMonitoring();
|
|
70
|
+
console.log('[PerformanceMonitor] Started with full performance tracking');
|
|
71
|
+
} else {
|
|
72
|
+
console.warn('[PerformanceMonitor] Performance API not available, using basic monitoring');
|
|
73
|
+
this.startBasicMonitoring();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
startWebVitalsCollection() {
|
|
78
|
+
// Check if web-vitals library is available
|
|
79
|
+
if (typeof webVitals !== 'undefined') {
|
|
80
|
+
console.log('[PerformanceMonitor] Using web-vitals library');
|
|
81
|
+
|
|
82
|
+
// Track LCP
|
|
83
|
+
if (webVitals.onLCP) {
|
|
84
|
+
const unsubscribeLCP = webVitals.onLCP((metric) => {
|
|
85
|
+
this.stats.lcp = metric.value;
|
|
86
|
+
console.log('[Web Vitals] LCP:', metric.value);
|
|
87
|
+
this.checkWebVitalsThresholds('lcp', metric.value);
|
|
88
|
+
});
|
|
89
|
+
this.webVitalsUnsubscribers.push(unsubscribeLCP);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Track CLS
|
|
93
|
+
if (webVitals.onCLS) {
|
|
94
|
+
const unsubscribeCLS = webVitals.onCLS((metric) => {
|
|
95
|
+
this.stats.cls = metric.value;
|
|
96
|
+
console.log('[Web Vitals] CLS:', metric.value);
|
|
97
|
+
this.checkWebVitalsThresholds('cls', metric.value);
|
|
98
|
+
});
|
|
99
|
+
this.webVitalsUnsubscribers.push(unsubscribeCLS);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Track FID
|
|
103
|
+
if (webVitals.onFID) {
|
|
104
|
+
const unsubscribeFID = webVitals.onFID((metric) => {
|
|
105
|
+
this.stats.fid = metric.value;
|
|
106
|
+
console.log('[Web Vitals] FID:', metric.value);
|
|
107
|
+
});
|
|
108
|
+
this.webVitalsUnsubscribers.push(unsubscribeFID);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Track INP
|
|
112
|
+
if (webVitals.onINP) {
|
|
113
|
+
const unsubscribeINP = webVitals.onINP((metric) => {
|
|
114
|
+
this.stats.inp = metric.value;
|
|
115
|
+
console.log('[Web Vitals] INP:', metric.value);
|
|
116
|
+
this.checkWebVitalsThresholds('inp', metric.value);
|
|
117
|
+
});
|
|
118
|
+
this.webVitalsUnsubscribers.push(unsubscribeINP);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Track TTFB
|
|
122
|
+
if (webVitals.onTTFB) {
|
|
123
|
+
const unsubscribeTTFB = webVitals.onTTFB((metric) => {
|
|
124
|
+
this.stats.ttfb = metric.value;
|
|
125
|
+
console.log('[Web Vitals] TTFB:', metric.value);
|
|
126
|
+
});
|
|
127
|
+
this.webVitalsUnsubscribers.push(unsubscribeTTFB);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
console.log('[PerformanceMonitor] web-vitals not available, using fallback PerformanceObserver');
|
|
131
|
+
this.startPerformanceObserverFallback();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
startPerformanceObserverFallback() {
|
|
136
|
+
// Fallback implementation using PerformanceObserver
|
|
137
|
+
if (typeof PerformanceObserver === 'undefined') {
|
|
138
|
+
console.warn('[PerformanceMonitor] PerformanceObserver not available');
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
// Observe paint entries (includes LCP)
|
|
144
|
+
const paintObserver = new PerformanceObserver((list) => {
|
|
145
|
+
for (const entry of list.getEntries()) {
|
|
146
|
+
if (entry.entryType === 'largest-contentful-paint') {
|
|
147
|
+
this.stats.lcp = entry.startTime;
|
|
148
|
+
console.log('[Fallback] LCP:', entry.startTime);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Try to observe paint entries
|
|
154
|
+
try {
|
|
155
|
+
paintObserver.observe({ entryTypes: ['largest-contentful-paint'] });
|
|
156
|
+
this.performanceObserver = paintObserver;
|
|
157
|
+
} catch (e) {
|
|
158
|
+
console.warn('[PerformanceMonitor] Could not observe LCP:', e);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Note: CLS and other metrics are complex to implement correctly without web-vitals
|
|
162
|
+
console.warn('[PerformanceMonitor] Using fallback - some metrics may be less accurate');
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error('[PerformanceMonitor] Failed to create PerformanceObserver:', error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
startResourceMonitoring() {
|
|
169
|
+
// Monitor every 2 seconds
|
|
170
|
+
this.monitoringInterval = setInterval(() => {
|
|
171
|
+
this.updateResourceStats();
|
|
172
|
+
this.checkResourceThresholds();
|
|
173
|
+
}, 2000);
|
|
174
|
+
|
|
175
|
+
// Initial update
|
|
176
|
+
this.updateResourceStats();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
startBasicMonitoring() {
|
|
180
|
+
// Basic monitoring without performance.memory
|
|
181
|
+
this.monitoringInterval = setInterval(() => {
|
|
182
|
+
this.updateBasicStats();
|
|
183
|
+
this.checkBasicThresholds();
|
|
184
|
+
}, 5000);
|
|
185
|
+
|
|
186
|
+
// Initial update
|
|
187
|
+
this.updateBasicStats();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async updateResourceStats() {
|
|
191
|
+
const now = Date.now();
|
|
192
|
+
const timeDelta = (now - this.stats.lastCheck) / 1000; // seconds
|
|
193
|
+
|
|
194
|
+
// CPU Usage (estimated from script execution time)
|
|
195
|
+
const startTime = performance.now();
|
|
196
|
+
this.simulateWork(); // Small workload to measure responsiveness
|
|
197
|
+
const executionTime = performance.now() - startTime;
|
|
198
|
+
this.stats.cpuUsage = Math.min(100, (executionTime / 10) * 100); // Rough estimate
|
|
199
|
+
|
|
200
|
+
// Memory Usage
|
|
201
|
+
if (performance.memory) {
|
|
202
|
+
this.stats.memoryUsage = performance.memory.usedJSHeapSize;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Data Buffer Stats
|
|
206
|
+
if (this.dataBuffer) {
|
|
207
|
+
const bufferStats = await this.dataBuffer.getStats();
|
|
208
|
+
const newEventCount = bufferStats.eventCount;
|
|
209
|
+
const newDataVolume = bufferStats.totalSize;
|
|
210
|
+
|
|
211
|
+
// Calculate rates
|
|
212
|
+
this.stats.eventRate = (newEventCount - this.stats.eventCount) / timeDelta;
|
|
213
|
+
this.stats.dataRate = (newDataVolume - this.stats.dataVolume) / timeDelta;
|
|
214
|
+
|
|
215
|
+
this.stats.eventCount = newEventCount;
|
|
216
|
+
this.stats.dataVolume = newDataVolume;
|
|
217
|
+
this.stats.bufferSize = bufferStats.totalSize;
|
|
218
|
+
this.stats.bufferUtilization = (bufferStats.totalSize / bufferStats.maxSize) * 100;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.stats.lastCheck = now;
|
|
222
|
+
|
|
223
|
+
// Notify callbacks
|
|
224
|
+
if (this.callbacks.onStatsUpdate) {
|
|
225
|
+
this.callbacks.onStatsUpdate(this.getPublicStats());
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
updateBasicStats() {
|
|
230
|
+
const now = Date.now();
|
|
231
|
+
|
|
232
|
+
// Basic stats without performance.memory
|
|
233
|
+
if (this.dataBuffer) {
|
|
234
|
+
this.dataBuffer.getStats().then(bufferStats => {
|
|
235
|
+
this.stats.eventCount = bufferStats.eventCount;
|
|
236
|
+
this.stats.dataVolume = bufferStats.totalSize;
|
|
237
|
+
this.stats.bufferSize = bufferStats.totalSize;
|
|
238
|
+
this.stats.bufferUtilization = (bufferStats.totalSize / bufferStats.maxSize) * 100;
|
|
239
|
+
|
|
240
|
+
if (this.callbacks.onStatsUpdate) {
|
|
241
|
+
this.callbacks.onStatsUpdate(this.getPublicStats());
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.stats.lastCheck = now;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
simulateWork() {
|
|
250
|
+
// Small computational task to measure responsiveness
|
|
251
|
+
let sum = 0;
|
|
252
|
+
for (let i = 0; i < 1000; i++) {
|
|
253
|
+
sum += Math.random();
|
|
254
|
+
}
|
|
255
|
+
return sum;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
checkWebVitalsThresholds(metric, value) {
|
|
259
|
+
const alerts = [];
|
|
260
|
+
|
|
261
|
+
if (metric === 'lcp' && value > this.thresholds.lcp) {
|
|
262
|
+
alerts.push({
|
|
263
|
+
type: 'webvitals',
|
|
264
|
+
severity: 'medium',
|
|
265
|
+
message: `Poor LCP: ${value.toFixed(0)}ms (threshold: ${this.thresholds.lcp}ms)`,
|
|
266
|
+
recommendation: 'Optimize largest content paint performance'
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (metric === 'cls' && value > this.thresholds.cls) {
|
|
271
|
+
alerts.push({
|
|
272
|
+
type: 'webvitals',
|
|
273
|
+
severity: 'medium',
|
|
274
|
+
message: `Poor CLS: ${value.toFixed(3)} (threshold: ${this.thresholds.cls})`,
|
|
275
|
+
recommendation: 'Reduce layout shifts during page load'
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (metric === 'inp' && value > this.thresholds.inp) {
|
|
280
|
+
alerts.push({
|
|
281
|
+
type: 'webvitals',
|
|
282
|
+
severity: 'medium',
|
|
283
|
+
message: `Poor INP: ${value.toFixed(0)}ms (threshold: ${this.thresholds.inp}ms)`,
|
|
284
|
+
recommendation: 'Improve interaction responsiveness'
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (alerts.length > 0 && this.callbacks.onPerformanceAlert) {
|
|
289
|
+
this.callbacks.onPerformanceAlert(alerts);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
checkResourceThresholds() {
|
|
294
|
+
const alerts = [];
|
|
295
|
+
|
|
296
|
+
// CPU threshold
|
|
297
|
+
if (this.stats.cpuUsage > this.thresholds.cpuUsage) {
|
|
298
|
+
alerts.push({
|
|
299
|
+
type: 'cpu',
|
|
300
|
+
severity: 'high',
|
|
301
|
+
message: `High CPU usage: ${this.stats.cpuUsage.toFixed(1)}%`,
|
|
302
|
+
recommendation: 'Consider reducing instrumentation level'
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Memory threshold
|
|
307
|
+
if (this.stats.memoryUsage > this.thresholds.memoryUsage) {
|
|
308
|
+
alerts.push({
|
|
309
|
+
type: 'memory',
|
|
310
|
+
severity: 'high',
|
|
311
|
+
message: `High memory usage: ${(this.stats.memoryUsage / 1024 / 1024).toFixed(1)}MB`,
|
|
312
|
+
recommendation: 'Buffer may need to be cleared'
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Data rate threshold
|
|
317
|
+
if (this.stats.dataRate > this.thresholds.dataVolumePerSecond) {
|
|
318
|
+
alerts.push({
|
|
319
|
+
type: 'dataRate',
|
|
320
|
+
severity: 'medium',
|
|
321
|
+
message: `High data rate: ${(this.stats.dataRate / 1024).toFixed(1)}KB/s`,
|
|
322
|
+
recommendation: 'Consider reducing capture frequency'
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Event rate threshold
|
|
327
|
+
if (this.stats.eventRate > this.thresholds.eventCountPerSecond) {
|
|
328
|
+
alerts.push({
|
|
329
|
+
type: 'eventRate',
|
|
330
|
+
severity: 'medium',
|
|
331
|
+
message: `High event rate: ${this.stats.eventRate.toFixed(1)} events/s`,
|
|
332
|
+
recommendation: 'Consider filtering events or reducing instrumentation'
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Buffer utilization
|
|
337
|
+
if (this.stats.bufferUtilization > 90) {
|
|
338
|
+
alerts.push({
|
|
339
|
+
type: 'buffer',
|
|
340
|
+
severity: 'high',
|
|
341
|
+
message: `Buffer nearly full: ${this.stats.bufferUtilization.toFixed(1)}%`,
|
|
342
|
+
recommendation: 'Force upload or clear buffer'
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Send alerts
|
|
347
|
+
if (alerts.length > 0) {
|
|
348
|
+
this.handlePerformanceAlerts(alerts);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
checkBasicThresholds() {
|
|
353
|
+
const alerts = [];
|
|
354
|
+
|
|
355
|
+
// Only check buffer-related thresholds in basic mode
|
|
356
|
+
if (this.stats.bufferUtilization > 90) {
|
|
357
|
+
alerts.push({
|
|
358
|
+
type: 'buffer',
|
|
359
|
+
severity: 'high',
|
|
360
|
+
message: `Buffer nearly full: ${this.stats.bufferUtilization.toFixed(1)}%`,
|
|
361
|
+
recommendation: 'Force upload or clear buffer'
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (alerts.length > 0) {
|
|
366
|
+
this.handlePerformanceAlerts(alerts);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
handlePerformanceAlerts(alerts) {
|
|
371
|
+
console.warn('[PerformanceMonitor] Performance alerts:', JSON.stringify(alerts, null, 2));
|
|
372
|
+
|
|
373
|
+
// Check if throttling is required
|
|
374
|
+
const highSeverityAlerts = alerts.filter(a => a.severity === 'high');
|
|
375
|
+
if (highSeverityAlerts.length > 0 && this.callbacks.onThrottleRequired) {
|
|
376
|
+
this.callbacks.onThrottleRequired(highSeverityAlerts);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Send all alerts to callback
|
|
380
|
+
if (this.callbacks.onPerformanceAlert) {
|
|
381
|
+
this.callbacks.onPerformanceAlert(alerts);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
getPublicStats() {
|
|
386
|
+
const uptime = (Date.now() - this.startTime) / 1000;
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
...this.stats,
|
|
390
|
+
uptime: uptime,
|
|
391
|
+
averageEventRate: this.stats.eventCount / uptime,
|
|
392
|
+
averageDataRate: this.stats.dataVolume / uptime,
|
|
393
|
+
memoryUsageMB: this.stats.memoryUsage ? (this.stats.memoryUsage / 1024 / 1024).toFixed(2) : 'N/A',
|
|
394
|
+
dataVolumeMB: (this.stats.dataVolume / 1024 / 1024).toFixed(2),
|
|
395
|
+
isHealthy: this.isPerformanceHealthy(),
|
|
396
|
+
webVitals: {
|
|
397
|
+
lcp: this.stats.lcp,
|
|
398
|
+
cls: this.stats.cls,
|
|
399
|
+
fid: this.stats.fid,
|
|
400
|
+
inp: this.stats.inp,
|
|
401
|
+
ttfb: this.stats.ttfb
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
isPerformanceHealthy() {
|
|
407
|
+
return (
|
|
408
|
+
this.stats.cpuUsage < this.thresholds.cpuUsage &&
|
|
409
|
+
this.stats.memoryUsage < this.thresholds.memoryUsage &&
|
|
410
|
+
this.stats.bufferUtilization < 80 &&
|
|
411
|
+
(this.stats.lcp === null || this.stats.lcp < this.thresholds.lcp) &&
|
|
412
|
+
(this.stats.cls === null || this.stats.cls < this.thresholds.cls)
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
recordEvent(eventType, data) {
|
|
417
|
+
// Record custom performance events
|
|
418
|
+
if (performance.mark) {
|
|
419
|
+
performance.mark(`chromepilot-${eventType}-${Date.now()}`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Track event-specific metrics
|
|
423
|
+
switch (eventType) {
|
|
424
|
+
case 'dom_mutation':
|
|
425
|
+
this.stats.domMutationCount = (this.stats.domMutationCount || 0) + 1;
|
|
426
|
+
break;
|
|
427
|
+
case 'function_call':
|
|
428
|
+
this.stats.functionCallCount = (this.stats.functionCallCount || 0) + 1;
|
|
429
|
+
break;
|
|
430
|
+
case 'network_request':
|
|
431
|
+
this.stats.networkRequestCount = (this.stats.networkRequestCount || 0) + 1;
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
getRecommendations() {
|
|
437
|
+
const recommendations = [];
|
|
438
|
+
|
|
439
|
+
if (this.stats.cpuUsage > 60) {
|
|
440
|
+
recommendations.push({
|
|
441
|
+
type: 'instrumentation',
|
|
442
|
+
message: 'Reduce instrumentation level to improve performance',
|
|
443
|
+
action: 'lower_level'
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (this.stats.bufferUtilization > 70) {
|
|
448
|
+
recommendations.push({
|
|
449
|
+
type: 'buffer',
|
|
450
|
+
message: 'Force upload data to free buffer space',
|
|
451
|
+
action: 'force_upload'
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (this.stats.eventRate > 50) {
|
|
456
|
+
recommendations.push({
|
|
457
|
+
type: 'filtering',
|
|
458
|
+
message: 'Add event filtering to reduce data volume',
|
|
459
|
+
action: 'add_filters'
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Web Vitals recommendations
|
|
464
|
+
if (this.stats.lcp > this.thresholds.lcp) {
|
|
465
|
+
recommendations.push({
|
|
466
|
+
type: 'performance',
|
|
467
|
+
message: 'LCP is poor - optimize largest content paint',
|
|
468
|
+
action: 'optimize_lcp'
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (this.stats.cls > this.thresholds.cls) {
|
|
473
|
+
recommendations.push({
|
|
474
|
+
type: 'performance',
|
|
475
|
+
message: 'CLS is poor - reduce layout shifts',
|
|
476
|
+
action: 'reduce_cls'
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return recommendations;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
setThresholds(newThresholds) {
|
|
484
|
+
this.thresholds = { ...this.thresholds, ...newThresholds };
|
|
485
|
+
console.log('[PerformanceMonitor] Updated thresholds:', this.thresholds);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
stopMonitoring() {
|
|
489
|
+
if (!this.isMonitoring) {
|
|
490
|
+
console.log('[PerformanceMonitor] Not currently monitoring');
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Stop resource monitoring interval
|
|
495
|
+
if (this.monitoringInterval) {
|
|
496
|
+
clearInterval(this.monitoringInterval);
|
|
497
|
+
this.monitoringInterval = null;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Cleanup web-vitals observers
|
|
501
|
+
if (this.webVitalsUnsubscribers.length > 0) {
|
|
502
|
+
this.webVitalsUnsubscribers.forEach(unsubscribe => {
|
|
503
|
+
if (typeof unsubscribe === 'function') {
|
|
504
|
+
unsubscribe();
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
this.webVitalsUnsubscribers = [];
|
|
508
|
+
console.log('[PerformanceMonitor] Web Vitals observers cleaned up');
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Cleanup PerformanceObserver fallback
|
|
512
|
+
if (this.performanceObserver) {
|
|
513
|
+
this.performanceObserver.disconnect();
|
|
514
|
+
this.performanceObserver = null;
|
|
515
|
+
console.log('[PerformanceMonitor] PerformanceObserver cleaned up');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
this.isMonitoring = false;
|
|
519
|
+
console.log('[PerformanceMonitor] Stopped monitoring');
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
destroy() {
|
|
523
|
+
this.stopMonitoring();
|
|
524
|
+
this.callbacks = {};
|
|
525
|
+
this.dataBuffer = null;
|
|
526
|
+
console.log('[PerformanceMonitor] Destroyed');
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Export for use in content and background scripts
|
|
531
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
532
|
+
module.exports = PerformanceMonitor;
|
|
533
|
+
}
|