@crashsense/core 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1219 @@
1
+ 'use strict';
2
+
3
+ var utils = require('@crashsense/utils');
4
+
5
+ // src/crashsense.ts
6
+
7
+ // src/config.ts
8
+ var SDK_VERSION = "0.1.0";
9
+ function resolveConfig(userConfig) {
10
+ if (!userConfig.appId) {
11
+ throw new Error("[CrashSense] appId is required");
12
+ }
13
+ const sampleRate = userConfig.sampleRate ?? 1;
14
+ if (sampleRate < 0 || sampleRate > 1) {
15
+ throw new Error("[CrashSense] sampleRate must be between 0 and 1");
16
+ }
17
+ const maxEventsPerMinute = userConfig.maxEventsPerMinute ?? 30;
18
+ if (maxEventsPerMinute <= 0) {
19
+ throw new Error("[CrashSense] maxEventsPerMinute must be positive");
20
+ }
21
+ return {
22
+ appId: userConfig.appId,
23
+ environment: userConfig.environment ?? "production",
24
+ release: userConfig.release ?? "",
25
+ sampleRate,
26
+ maxEventsPerMinute,
27
+ enableMemoryMonitoring: userConfig.enableMemoryMonitoring ?? true,
28
+ enableLongTaskMonitoring: userConfig.enableLongTaskMonitoring ?? true,
29
+ enableNetworkMonitoring: userConfig.enableNetworkMonitoring ?? true,
30
+ enableIframeTracking: userConfig.enableIframeTracking ?? true,
31
+ enablePreCrashWarning: userConfig.enablePreCrashWarning ?? true,
32
+ preCrashMemoryThreshold: userConfig.preCrashMemoryThreshold ?? 0.8,
33
+ piiScrubbing: userConfig.piiScrubbing ?? true,
34
+ debug: userConfig.debug ?? false,
35
+ onCrash: userConfig.onCrash ?? null
36
+ };
37
+ }
38
+
39
+ // src/error-interceptor.ts
40
+ var IGNORED_MESSAGES = [
41
+ "ResizeObserver loop limit exceeded",
42
+ "ResizeObserver loop completed with undelivered notifications"
43
+ ];
44
+ function isIgnoredError(message, filename) {
45
+ if (IGNORED_MESSAGES.some((m) => message.includes(m))) return true;
46
+ if (filename?.startsWith("chrome-extension://")) return true;
47
+ if (filename?.startsWith("moz-extension://")) return true;
48
+ if (message === "Script error." || message === "Script error") return true;
49
+ return false;
50
+ }
51
+ function createErrorInterceptor(bus) {
52
+ let errorHandler = null;
53
+ let rejectionHandler = null;
54
+ return {
55
+ install() {
56
+ if (typeof window === "undefined") return;
57
+ errorHandler = (event) => {
58
+ if (isIgnoredError(event.message, event.filename)) return;
59
+ const error = event.error instanceof Error ? event.error : new Error(event.message);
60
+ bus.emit("error", {
61
+ error,
62
+ timestamp: performance.now() + performance.timeOrigin
63
+ });
64
+ };
65
+ rejectionHandler = (event) => {
66
+ const reason = event.reason;
67
+ bus.emit("unhandled_rejection", {
68
+ reason,
69
+ timestamp: performance.now() + performance.timeOrigin
70
+ });
71
+ };
72
+ window.addEventListener("error", errorHandler);
73
+ window.addEventListener("unhandledrejection", rejectionHandler);
74
+ },
75
+ uninstall() {
76
+ if (typeof window === "undefined") return;
77
+ if (errorHandler) window.removeEventListener("error", errorHandler);
78
+ if (rejectionHandler) window.removeEventListener("unhandledrejection", rejectionHandler);
79
+ errorHandler = null;
80
+ rejectionHandler = null;
81
+ }
82
+ };
83
+ }
84
+ var SAMPLE_INTERVAL = 5e3;
85
+ var HISTORY_SIZE = 12;
86
+ var WARNING_THRESHOLD = 0.85;
87
+ function computeTrend(samples) {
88
+ if (samples.length < 3) return "stable";
89
+ const recent = samples.slice(-6);
90
+ const first = recent[0].used;
91
+ const last = recent[recent.length - 1].used;
92
+ const growthRate = (last - first) / first;
93
+ if (growthRate > 0.2) return "growing";
94
+ if (growthRate < -0.2) return "shrinking";
95
+ const shortRecent = samples.slice(-3);
96
+ const min = Math.min(...shortRecent.map((s) => s.used));
97
+ const max = Math.max(...shortRecent.map((s) => s.used));
98
+ if (max > 0 && (max - min) / max > 0.2) return "spike";
99
+ return "stable";
100
+ }
101
+ function createMemoryMonitor(bus, _config) {
102
+ const history2 = new utils.RingBuffer(HISTORY_SIZE);
103
+ let intervalId = null;
104
+ function hasPerformanceMemory() {
105
+ return typeof performance !== "undefined" && "memory" in performance && performance.memory !== void 0;
106
+ }
107
+ function sample() {
108
+ if (!hasPerformanceMemory()) return;
109
+ const mem = performance.memory;
110
+ const s = {
111
+ used: mem.usedJSHeapSize,
112
+ total: mem.totalJSHeapSize,
113
+ limit: mem.jsHeapSizeLimit,
114
+ timestamp: Date.now()
115
+ };
116
+ history2.push(s);
117
+ const utilization = s.limit > 0 ? s.used / s.limit : 0;
118
+ if (utilization > WARNING_THRESHOLD) {
119
+ const samples = history2.drain();
120
+ bus.emit("memory_warning", {
121
+ utilization,
122
+ trend: computeTrend(samples),
123
+ timestamp: performance.now() + performance.timeOrigin
124
+ });
125
+ }
126
+ }
127
+ return {
128
+ start() {
129
+ if (!hasPerformanceMemory()) return;
130
+ sample();
131
+ intervalId = setInterval(sample, SAMPLE_INTERVAL);
132
+ },
133
+ stop() {
134
+ if (intervalId !== null) {
135
+ clearInterval(intervalId);
136
+ intervalId = null;
137
+ }
138
+ },
139
+ getSnapshot() {
140
+ if (!hasPerformanceMemory()) {
141
+ return {
142
+ usedJSHeapSize: null,
143
+ totalJSHeapSize: null,
144
+ heapSizeLimit: null,
145
+ trend: "stable",
146
+ utilizationPercent: null
147
+ };
148
+ }
149
+ const mem = performance.memory;
150
+ const samples = history2.drain();
151
+ const utilization = mem.jsHeapSizeLimit > 0 ? mem.usedJSHeapSize / mem.jsHeapSizeLimit : null;
152
+ return {
153
+ usedJSHeapSize: mem.usedJSHeapSize,
154
+ totalJSHeapSize: mem.totalJSHeapSize,
155
+ heapSizeLimit: mem.jsHeapSizeLimit,
156
+ trend: computeTrend(samples),
157
+ utilizationPercent: utilization !== null ? Math.round(utilization * 100) : null
158
+ };
159
+ }
160
+ };
161
+ }
162
+ var LONG_TASK_THRESHOLD = 100;
163
+ var HISTORY_SIZE2 = 200;
164
+ function createEventLoopMonitor(bus, _config) {
165
+ const taskHistory = new utils.RingBuffer(HISTORY_SIZE2);
166
+ let observer = null;
167
+ let rafId = null;
168
+ let lastFrameTime = 0;
169
+ let fps = 60;
170
+ function supportsLongTasks() {
171
+ if (typeof PerformanceObserver === "undefined") return false;
172
+ try {
173
+ const supported = PerformanceObserver.supportedEntryTypes;
174
+ return Array.isArray(supported) && supported.includes("longtask");
175
+ } catch {
176
+ return false;
177
+ }
178
+ }
179
+ function measureFps(timestamp) {
180
+ if (lastFrameTime > 0) {
181
+ const delta = timestamp - lastFrameTime;
182
+ if (delta > 0) {
183
+ const instantFps = 1e3 / delta;
184
+ fps = fps * 0.9 + instantFps * 0.1;
185
+ }
186
+ }
187
+ lastFrameTime = timestamp;
188
+ rafId = requestAnimationFrame(measureFps);
189
+ }
190
+ return {
191
+ start() {
192
+ if (typeof window === "undefined") return;
193
+ if (supportsLongTasks()) {
194
+ observer = new PerformanceObserver((list) => {
195
+ for (const entry of list.getEntries()) {
196
+ const task = {
197
+ duration: entry.duration,
198
+ startTime: entry.startTime
199
+ };
200
+ taskHistory.push(task);
201
+ if (entry.duration > LONG_TASK_THRESHOLD) {
202
+ bus.emit("long_task", {
203
+ duration: entry.duration,
204
+ startTime: entry.startTime,
205
+ timestamp: performance.now() + performance.timeOrigin
206
+ });
207
+ }
208
+ }
209
+ });
210
+ observer.observe({ entryTypes: ["longtask"] });
211
+ }
212
+ if (typeof requestAnimationFrame !== "undefined") {
213
+ rafId = requestAnimationFrame(measureFps);
214
+ }
215
+ },
216
+ stop() {
217
+ if (observer) {
218
+ observer.disconnect();
219
+ observer = null;
220
+ }
221
+ if (rafId !== null && typeof cancelAnimationFrame !== "undefined") {
222
+ cancelAnimationFrame(rafId);
223
+ rafId = null;
224
+ }
225
+ },
226
+ getCpuSnapshot() {
227
+ const now = performance.now();
228
+ const tasks = taskHistory.drain();
229
+ const recentTasks = tasks.filter((t) => now - t.startTime < 3e4);
230
+ const durations = recentTasks.map((t) => t.duration);
231
+ const totalBlocking = durations.filter((d) => d > 50).reduce((sum, d) => sum + (d - 50), 0);
232
+ return {
233
+ longTasksLast30s: recentTasks.length,
234
+ avgLongTaskDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
235
+ maxLongTaskDuration: durations.length > 0 ? Math.max(...durations) : 0,
236
+ estimatedBlockingTime: totalBlocking
237
+ };
238
+ },
239
+ getEventLoopSnapshot() {
240
+ const cpuState = this.getCpuSnapshot();
241
+ return {
242
+ isBlocked: cpuState.maxLongTaskDuration > 1e3,
243
+ blockDuration: cpuState.maxLongTaskDuration > 0 ? cpuState.maxLongTaskDuration : null,
244
+ fps: Math.round(fps)
245
+ };
246
+ }
247
+ };
248
+ }
249
+ var HISTORY_SIZE3 = 100;
250
+ function createNetworkMonitor(bus, _config) {
251
+ const history2 = new utils.RingBuffer(HISTORY_SIZE3);
252
+ let originalFetch = null;
253
+ let pendingCount = 0;
254
+ function wrapFetch() {
255
+ if (typeof window === "undefined" || typeof fetch === "undefined") return;
256
+ originalFetch = window.fetch;
257
+ window.fetch = async function patchedFetch(input, init) {
258
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
259
+ const method = init?.method ?? "GET";
260
+ const startTime = performance.now();
261
+ pendingCount++;
262
+ try {
263
+ const response = await originalFetch.call(window, input, init);
264
+ const duration = performance.now() - startTime;
265
+ pendingCount--;
266
+ const request = {
267
+ url,
268
+ method,
269
+ status: response.status,
270
+ duration,
271
+ startTime,
272
+ error: null,
273
+ responseSize: null
274
+ };
275
+ history2.push(request);
276
+ if (response.status >= 500 || response.status === 0) {
277
+ bus.emit("network_failure", {
278
+ url,
279
+ status: response.status,
280
+ error: `HTTP ${response.status}`,
281
+ timestamp: performance.now() + performance.timeOrigin
282
+ });
283
+ }
284
+ return response;
285
+ } catch (err) {
286
+ const duration = performance.now() - startTime;
287
+ pendingCount--;
288
+ const errorMsg = err instanceof Error ? err.message : String(err);
289
+ const request = {
290
+ url,
291
+ method,
292
+ status: 0,
293
+ duration,
294
+ startTime,
295
+ error: errorMsg,
296
+ responseSize: null
297
+ };
298
+ history2.push(request);
299
+ bus.emit("network_failure", {
300
+ url,
301
+ status: 0,
302
+ error: errorMsg,
303
+ timestamp: performance.now() + performance.timeOrigin
304
+ });
305
+ throw err;
306
+ }
307
+ };
308
+ }
309
+ return {
310
+ start() {
311
+ wrapFetch();
312
+ },
313
+ stop() {
314
+ if (originalFetch && typeof window !== "undefined") {
315
+ window.fetch = originalFetch;
316
+ originalFetch = null;
317
+ }
318
+ },
319
+ getSnapshot() {
320
+ const now = performance.now();
321
+ const requests = history2.drain();
322
+ const recentRequests = requests.filter((r) => now - r.startTime < 6e4);
323
+ const failedCount = recentRequests.filter(
324
+ (r) => r.status === 0 || r.status >= 500 || r.error !== null
325
+ ).length;
326
+ const latencies = recentRequests.filter((r) => r.error === null).map((r) => r.duration);
327
+ const avgLatency = latencies.length > 0 ? latencies.reduce((a, b) => a + b, 0) / latencies.length : 0;
328
+ let connectionType = null;
329
+ if (typeof navigator !== "undefined" && "connection" in navigator) {
330
+ const conn = navigator.connection;
331
+ connectionType = conn?.effectiveType ?? null;
332
+ }
333
+ return {
334
+ pendingRequests: pendingCount,
335
+ failedRequestsLast60s: failedCount,
336
+ avgLatencyLast60s: Math.round(avgLatency),
337
+ connectionType,
338
+ isOnline: typeof navigator !== "undefined" ? navigator.onLine : true
339
+ };
340
+ }
341
+ };
342
+ }
343
+ var BUFFER_SIZE = 50;
344
+ function createBreadcrumbTracker(bus) {
345
+ const buffer = new utils.RingBuffer(BUFFER_SIZE);
346
+ let clickHandler = null;
347
+ let originalPushState = null;
348
+ let originalReplaceState = null;
349
+ function addBreadcrumb(bc) {
350
+ const crumb = {
351
+ ...bc,
352
+ timestamp: performance.now() + performance.timeOrigin
353
+ };
354
+ buffer.push(crumb);
355
+ bus.emit("breadcrumb", crumb);
356
+ }
357
+ function getElementDescription(target) {
358
+ if (!target || !(target instanceof Element)) return "unknown";
359
+ const tag = target.tagName.toLowerCase();
360
+ const id = target.id ? `#${target.id}` : "";
361
+ const cls = target.className && typeof target.className === "string" ? `.${target.className.split(" ").slice(0, 2).join(".")}` : "";
362
+ const text = target.textContent?.trim().slice(0, 30) ?? "";
363
+ return `${tag}${id}${cls}${text ? ` "${text}"` : ""}`;
364
+ }
365
+ return {
366
+ install() {
367
+ if (typeof window === "undefined") return;
368
+ clickHandler = (e) => {
369
+ addBreadcrumb({
370
+ type: "click",
371
+ message: `Click on ${getElementDescription(e.target)}`
372
+ });
373
+ };
374
+ document.addEventListener("click", clickHandler, { capture: true, passive: true });
375
+ originalPushState = history.pushState;
376
+ history.pushState = function(...args) {
377
+ addBreadcrumb({
378
+ type: "navigation",
379
+ message: `pushState to ${String(args[2] ?? "")}`
380
+ });
381
+ return originalPushState.apply(this, args);
382
+ };
383
+ originalReplaceState = history.replaceState;
384
+ history.replaceState = function(...args) {
385
+ addBreadcrumb({
386
+ type: "navigation",
387
+ message: `replaceState to ${String(args[2] ?? "")}`
388
+ });
389
+ return originalReplaceState.apply(this, args);
390
+ };
391
+ bus.on("error", (data) => {
392
+ addBreadcrumb({
393
+ type: "console",
394
+ message: `Error: ${data.error.message}`
395
+ });
396
+ });
397
+ bus.on("network_failure", (data) => {
398
+ addBreadcrumb({
399
+ type: "network",
400
+ message: `Network failure: ${data.url} (${data.error})`
401
+ });
402
+ });
403
+ },
404
+ uninstall() {
405
+ if (typeof window === "undefined") return;
406
+ if (clickHandler) {
407
+ document.removeEventListener("click", clickHandler, { capture: true });
408
+ clickHandler = null;
409
+ }
410
+ if (originalPushState) {
411
+ history.pushState = originalPushState;
412
+ originalPushState = null;
413
+ }
414
+ if (originalReplaceState) {
415
+ history.replaceState = originalReplaceState;
416
+ originalReplaceState = null;
417
+ }
418
+ },
419
+ getBreadcrumbs() {
420
+ return buffer.drain();
421
+ },
422
+ addBreadcrumb
423
+ };
424
+ }
425
+
426
+ // src/iframe-tracker.ts
427
+ var HISTORY_WINDOW = 6e4;
428
+ function extractOrigin(src) {
429
+ try {
430
+ return new URL(src, location.href).origin;
431
+ } catch {
432
+ return "unknown";
433
+ }
434
+ }
435
+ function isCrossOrigin(origin) {
436
+ if (typeof location === "undefined") return false;
437
+ return origin !== "unknown" && origin !== location.origin;
438
+ }
439
+ function createIframeTracker(bus, _config) {
440
+ const events = [];
441
+ let observer = null;
442
+ let currentCount = 0;
443
+ function pruneOldEvents() {
444
+ const cutoff = Date.now() - HISTORY_WINDOW;
445
+ while (events.length > 0 && events[0].timestamp < cutoff) {
446
+ events.shift();
447
+ }
448
+ }
449
+ function countCurrentIframes() {
450
+ if (typeof document === "undefined") return 0;
451
+ return document.querySelectorAll("iframe").length;
452
+ }
453
+ function handleAddedIframe(iframe) {
454
+ const src = iframe.src || iframe.getAttribute("src") || "";
455
+ const origin = extractOrigin(src);
456
+ const crossOrigin = isCrossOrigin(origin);
457
+ currentCount = countCurrentIframes();
458
+ const now = Date.now();
459
+ events.push({ src, origin, crossOrigin, timestamp: now, action: "added" });
460
+ bus.emit("iframe_added", {
461
+ src,
462
+ origin,
463
+ crossOrigin,
464
+ totalCount: currentCount,
465
+ timestamp: performance.now() + performance.timeOrigin
466
+ });
467
+ }
468
+ function handleRemovedIframe(iframe) {
469
+ const src = iframe.src || iframe.getAttribute("src") || "";
470
+ currentCount = countCurrentIframes();
471
+ events.push({ src, origin: extractOrigin(src), crossOrigin: false, timestamp: Date.now(), action: "removed" });
472
+ bus.emit("iframe_removed", {
473
+ src,
474
+ totalCount: currentCount,
475
+ timestamp: performance.now() + performance.timeOrigin
476
+ });
477
+ }
478
+ function processNodes(nodes, action) {
479
+ for (const node of Array.from(nodes)) {
480
+ if (node instanceof HTMLIFrameElement) {
481
+ if (action === "added") handleAddedIframe(node);
482
+ else handleRemovedIframe(node);
483
+ }
484
+ if (node instanceof Element) {
485
+ const nested = node.querySelectorAll("iframe");
486
+ for (const iframe of Array.from(nested)) {
487
+ if (action === "added") handleAddedIframe(iframe);
488
+ else handleRemovedIframe(iframe);
489
+ }
490
+ }
491
+ }
492
+ }
493
+ return {
494
+ start() {
495
+ if (typeof window === "undefined" || typeof MutationObserver === "undefined") return;
496
+ currentCount = countCurrentIframes();
497
+ observer = new MutationObserver((mutations) => {
498
+ for (const mutation of mutations) {
499
+ if (mutation.addedNodes.length > 0) processNodes(mutation.addedNodes, "added");
500
+ if (mutation.removedNodes.length > 0) processNodes(mutation.removedNodes, "removed");
501
+ }
502
+ });
503
+ observer.observe(document.documentElement, {
504
+ childList: true,
505
+ subtree: true
506
+ });
507
+ },
508
+ stop() {
509
+ if (observer) {
510
+ observer.disconnect();
511
+ observer = null;
512
+ }
513
+ },
514
+ getSnapshot() {
515
+ pruneOldEvents();
516
+ const addedLast60s = events.filter((e) => e.action === "added").length;
517
+ const removedLast60s = events.filter((e) => e.action === "removed").length;
518
+ const originsSet = /* @__PURE__ */ new Set();
519
+ let crossOriginCount = 0;
520
+ if (typeof document !== "undefined") {
521
+ const iframes = document.querySelectorAll("iframe");
522
+ for (const iframe of Array.from(iframes)) {
523
+ const src = iframe.src || iframe.getAttribute("src") || "";
524
+ const origin = extractOrigin(src);
525
+ originsSet.add(origin);
526
+ if (isCrossOrigin(origin)) crossOriginCount++;
527
+ }
528
+ }
529
+ return {
530
+ totalCount: currentCount,
531
+ addedLast60s,
532
+ removedLast60s,
533
+ origins: Array.from(originsSet),
534
+ crossOriginCount
535
+ };
536
+ }
537
+ };
538
+ }
539
+
540
+ // src/pre-crash-warning.ts
541
+ var CHECK_INTERVAL = 3e3;
542
+ var TREND_WINDOW = 5;
543
+ function createPreCrashWarning(bus, config, memoryMonitor, iframeTracker) {
544
+ let intervalId = null;
545
+ let lastLevel = null;
546
+ const recentReadings = [];
547
+ function getMemoryUtilization() {
548
+ const snap = memoryMonitor.getSnapshot();
549
+ return snap.utilizationPercent !== null ? snap.utilizationPercent / 100 : null;
550
+ }
551
+ function isGrowingTrend() {
552
+ if (recentReadings.length < 3) return false;
553
+ const recent = recentReadings.slice(-TREND_WINDOW);
554
+ let increases = 0;
555
+ for (let i = 1; i < recent.length; i++) {
556
+ if (recent[i].utilization > recent[i - 1].utilization) increases++;
557
+ }
558
+ return increases >= Math.floor(recent.length * 0.6);
559
+ }
560
+ function computeLevel(memUtil, iframeCount) {
561
+ const threshold = config.preCrashMemoryThreshold;
562
+ if (memUtil !== null && memUtil > 0.95) {
563
+ return { level: "imminent", reason: `Memory at ${(memUtil * 100).toFixed(0)}% \u2014 crash likely` };
564
+ }
565
+ if (memUtil !== null && memUtil > threshold + 0.15 && isGrowingTrend()) {
566
+ return { level: "imminent", reason: `Memory at ${(memUtil * 100).toFixed(0)}% with growing trend` };
567
+ }
568
+ if (memUtil !== null && memUtil > threshold + 0.05) {
569
+ if (isGrowingTrend()) {
570
+ return { level: "critical", reason: `Memory at ${(memUtil * 100).toFixed(0)}% with growing trend` };
571
+ }
572
+ if (iframeCount > 5) {
573
+ return { level: "critical", reason: `Memory at ${(memUtil * 100).toFixed(0)}% with ${iframeCount} iframes` };
574
+ }
575
+ }
576
+ if (memUtil !== null && memUtil > threshold && iframeCount > 3) {
577
+ return { level: "elevated", reason: `Memory at ${(memUtil * 100).toFixed(0)}% with ${iframeCount} iframes` };
578
+ }
579
+ if (memUtil !== null && memUtil > threshold && isGrowingTrend()) {
580
+ return { level: "elevated", reason: `Memory at ${(memUtil * 100).toFixed(0)}% with growing trend` };
581
+ }
582
+ return null;
583
+ }
584
+ const LEVEL_SEVERITY = {
585
+ elevated: 1,
586
+ critical: 2,
587
+ imminent: 3
588
+ };
589
+ function check() {
590
+ const memUtil = getMemoryUtilization();
591
+ if (memUtil !== null) {
592
+ recentReadings.push({ utilization: memUtil, timestamp: Date.now() });
593
+ while (recentReadings.length > TREND_WINDOW * 2) {
594
+ recentReadings.shift();
595
+ }
596
+ }
597
+ const iframeSnap = iframeTracker.getSnapshot();
598
+ const result = computeLevel(memUtil, iframeSnap.totalCount);
599
+ if (!result) {
600
+ lastLevel = null;
601
+ return;
602
+ }
603
+ if (lastLevel === null || LEVEL_SEVERITY[result.level] > LEVEL_SEVERITY[lastLevel]) {
604
+ lastLevel = result.level;
605
+ bus.emit("pre_crash_warning", {
606
+ level: result.level,
607
+ memoryUtilization: memUtil,
608
+ iframeCount: iframeSnap.totalCount,
609
+ reason: result.reason,
610
+ timestamp: performance.now() + performance.timeOrigin
611
+ });
612
+ }
613
+ }
614
+ return {
615
+ start() {
616
+ if (typeof window === "undefined") return;
617
+ check();
618
+ intervalId = setInterval(check, CHECK_INTERVAL);
619
+ },
620
+ stop() {
621
+ if (intervalId !== null) {
622
+ clearInterval(intervalId);
623
+ intervalId = null;
624
+ }
625
+ lastLevel = null;
626
+ recentReadings.length = 0;
627
+ }
628
+ };
629
+ }
630
+
631
+ // src/crash-classifier.ts
632
+ function evaluateRuntimeError(event) {
633
+ const type = event.error.type;
634
+ const knownTypes = ["TypeError", "ReferenceError", "RangeError", "SyntaxError", "URIError", "EvalError"];
635
+ if (knownTypes.includes(type)) {
636
+ return {
637
+ category: "runtime_error",
638
+ subcategory: type.toLowerCase(),
639
+ confidence: 0.95,
640
+ factors: [{
641
+ factor: "known_error_type",
642
+ weight: 0.95,
643
+ evidence: `Error type: ${type}`
644
+ }]
645
+ };
646
+ }
647
+ if (event.error.message) {
648
+ return {
649
+ category: "runtime_error",
650
+ subcategory: "custom_error",
651
+ confidence: 0.7,
652
+ factors: [{
653
+ factor: "unhandled_error",
654
+ weight: 0.7,
655
+ evidence: `Custom error: ${event.error.message.slice(0, 100)}`
656
+ }]
657
+ };
658
+ }
659
+ return {
660
+ category: "runtime_error",
661
+ subcategory: "unknown",
662
+ confidence: 0.5,
663
+ factors: []
664
+ };
665
+ }
666
+ function evaluateMemoryIssue(event) {
667
+ const mem = event.system.memory;
668
+ if (!mem) return { category: "memory_issue", subcategory: "unknown", confidence: 0, factors: [] };
669
+ const factors = [];
670
+ let confidence = 0;
671
+ if (mem.utilizationPercent !== void 0 && mem.utilizationPercent !== null && mem.utilizationPercent > 85) {
672
+ confidence += 0.35;
673
+ factors.push({
674
+ factor: "high_memory_utilization",
675
+ weight: 0.35,
676
+ evidence: `Memory utilization: ${mem.utilizationPercent}%`
677
+ });
678
+ }
679
+ if (mem.trend === "growing") {
680
+ confidence += 0.25;
681
+ factors.push({
682
+ factor: "growing_memory_trend",
683
+ weight: 0.25,
684
+ evidence: "Memory usage is growing over time"
685
+ });
686
+ }
687
+ if (mem.trend === "spike") {
688
+ confidence += 0.15;
689
+ factors.push({
690
+ factor: "memory_spike",
691
+ weight: 0.15,
692
+ evidence: "Memory usage spiked recently"
693
+ });
694
+ }
695
+ const msg = event.error.message.toLowerCase();
696
+ if (msg.includes("out of memory") || msg.includes("allocation failed") || msg.includes("arraybuffer")) {
697
+ confidence += 0.25;
698
+ factors.push({
699
+ factor: "memory_error_message",
700
+ weight: 0.25,
701
+ evidence: `Error message suggests memory issue: ${event.error.message.slice(0, 80)}`
702
+ });
703
+ }
704
+ const subcategory = mem.trend === "growing" ? "memory_leak" : mem.trend === "spike" ? "heap_spike" : (mem.utilizationPercent ?? 0) > 95 ? "heap_overflow" : "memory_pressure";
705
+ return {
706
+ category: "memory_issue",
707
+ subcategory,
708
+ confidence: Math.min(confidence, 1),
709
+ factors
710
+ };
711
+ }
712
+ function evaluateEventLoopBlocking(event) {
713
+ const cpu = event.system.cpu;
714
+ if (!cpu) return { category: "event_loop_blocking", subcategory: "unknown", confidence: 0, factors: [] };
715
+ const factors = [];
716
+ let confidence = 0;
717
+ if (cpu.maxLongTaskDuration > 1e3) {
718
+ confidence += 0.4;
719
+ factors.push({
720
+ factor: "critical_blocking",
721
+ weight: 0.4,
722
+ evidence: `Max long task: ${Math.round(cpu.maxLongTaskDuration)}ms`
723
+ });
724
+ } else if (cpu.maxLongTaskDuration > 200) {
725
+ confidence += 0.2;
726
+ factors.push({
727
+ factor: "long_task_detected",
728
+ weight: 0.2,
729
+ evidence: `Max long task: ${Math.round(cpu.maxLongTaskDuration)}ms`
730
+ });
731
+ }
732
+ if (cpu.longTasksLast30s > 10) {
733
+ confidence += 0.3;
734
+ factors.push({
735
+ factor: "frequent_long_tasks",
736
+ weight: 0.3,
737
+ evidence: `${cpu.longTasksLast30s} long tasks in last 30s`
738
+ });
739
+ }
740
+ if (cpu.estimatedBlockingTime > 5e3) {
741
+ confidence += 0.3;
742
+ factors.push({
743
+ factor: "high_tbt",
744
+ weight: 0.3,
745
+ evidence: `Estimated blocking time: ${Math.round(cpu.estimatedBlockingTime)}ms`
746
+ });
747
+ }
748
+ const subcategory = cpu.maxLongTaskDuration > 5e3 ? "infinite_loop" : cpu.maxLongTaskDuration > 1e3 ? "critical_blocking" : cpu.longTasksLast30s > 10 ? "frequent_blocking" : "long_task";
749
+ return {
750
+ category: "event_loop_blocking",
751
+ subcategory,
752
+ confidence: Math.min(confidence, 1),
753
+ factors
754
+ };
755
+ }
756
+ function evaluateReactFramework(event) {
757
+ if (event.framework.name !== "react") {
758
+ return { category: "framework_react", subcategory: "unknown", confidence: 0, factors: [] };
759
+ }
760
+ const msg = event.error.message.toLowerCase();
761
+ const factors = [];
762
+ let confidence = 0;
763
+ let subcategory = "component_error";
764
+ if (msg.includes("hydrat")) {
765
+ confidence = 0.95;
766
+ subcategory = "hydration_mismatch";
767
+ factors.push({
768
+ factor: "hydration_error",
769
+ weight: 0.95,
770
+ evidence: "Error message indicates hydration mismatch"
771
+ });
772
+ } else if (msg.includes("maximum update depth") || msg.includes("too many re-renders")) {
773
+ confidence = 0.95;
774
+ subcategory = "infinite_rerender";
775
+ factors.push({
776
+ factor: "infinite_render_loop",
777
+ weight: 0.95,
778
+ evidence: "React detected infinite re-render loop"
779
+ });
780
+ } else if (msg.includes("rendered fewer hooks") || msg.includes("rendered more hooks")) {
781
+ confidence = 0.9;
782
+ subcategory = "hook_violation";
783
+ factors.push({
784
+ factor: "hook_rule_violation",
785
+ weight: 0.9,
786
+ evidence: "Hook ordering violation detected"
787
+ });
788
+ } else if (event.framework.lifecycleStage) {
789
+ confidence = 0.85;
790
+ subcategory = `lifecycle_error_${event.framework.lifecycleStage}`;
791
+ factors.push({
792
+ factor: "react_lifecycle_error",
793
+ weight: 0.85,
794
+ evidence: `Error during React ${event.framework.lifecycleStage} phase`
795
+ });
796
+ } else {
797
+ confidence = 0.7;
798
+ factors.push({
799
+ factor: "react_context",
800
+ weight: 0.7,
801
+ evidence: "Error occurred in React application context"
802
+ });
803
+ }
804
+ return {
805
+ category: "framework_react",
806
+ subcategory,
807
+ confidence,
808
+ factors
809
+ };
810
+ }
811
+ function evaluateVueFramework(event) {
812
+ if (event.framework.name !== "vue") {
813
+ return { category: "framework_vue", subcategory: "unknown", confidence: 0, factors: [] };
814
+ }
815
+ const msg = event.error.message.toLowerCase();
816
+ const factors = [];
817
+ let confidence = 0;
818
+ let subcategory = "component_error";
819
+ if (msg.includes("maximum recursive") || msg.includes("infinite") && msg.includes("computed")) {
820
+ confidence = 0.95;
821
+ subcategory = "reactivity_loop";
822
+ factors.push({
823
+ factor: "vue_reactivity_loop",
824
+ weight: 0.95,
825
+ evidence: "Detected infinite reactivity loop"
826
+ });
827
+ } else if (event.framework.lifecycleStage) {
828
+ confidence = 0.85;
829
+ subcategory = `lifecycle_error_${event.framework.lifecycleStage}`;
830
+ factors.push({
831
+ factor: "vue_lifecycle_error",
832
+ weight: 0.85,
833
+ evidence: `Error during Vue ${event.framework.lifecycleStage} phase`
834
+ });
835
+ } else {
836
+ confidence = 0.7;
837
+ factors.push({
838
+ factor: "vue_context",
839
+ weight: 0.7,
840
+ evidence: "Error occurred in Vue application context"
841
+ });
842
+ }
843
+ return {
844
+ category: "framework_vue",
845
+ subcategory,
846
+ confidence,
847
+ factors
848
+ };
849
+ }
850
+ function evaluateNetworkInduced(event) {
851
+ const network = event.system.network;
852
+ if (!network) return { category: "network_induced", subcategory: "unknown", confidence: 0, factors: [] };
853
+ const factors = [];
854
+ let confidence = 0;
855
+ if (network.failedRequestsLast60s !== void 0 && network.failedRequestsLast60s > 0) {
856
+ confidence += 0.3;
857
+ factors.push({
858
+ factor: "recent_network_failures",
859
+ weight: 0.3,
860
+ evidence: `${network.failedRequestsLast60s} failed requests in last 60s`
861
+ });
862
+ }
863
+ if (network.isOnline === false) {
864
+ confidence += 0.3;
865
+ factors.push({
866
+ factor: "offline",
867
+ weight: 0.3,
868
+ evidence: "Device is offline"
869
+ });
870
+ }
871
+ const msg = event.error.message.toLowerCase();
872
+ if (msg.includes("fetch") || msg.includes("network") || msg.includes("cors") || msg.includes("xhr")) {
873
+ confidence += 0.3;
874
+ factors.push({
875
+ factor: "network_error_message",
876
+ weight: 0.3,
877
+ evidence: `Error message suggests network issue: ${event.error.message.slice(0, 80)}`
878
+ });
879
+ }
880
+ const subcategory = network.isOnline === false ? "offline" : msg.includes("cors") ? "cors_block" : msg.includes("timeout") ? "timeout" : (network.failedRequestsLast60s ?? 0) > 0 ? "failed_request" : "network_error";
881
+ return {
882
+ category: "network_induced",
883
+ subcategory,
884
+ confidence: Math.min(confidence, 1),
885
+ factors
886
+ };
887
+ }
888
+ function evaluateIframeOverload(event) {
889
+ const iframe = event.system.iframe;
890
+ if (!iframe) return { category: "iframe_overload", subcategory: "unknown", confidence: 0, factors: [] };
891
+ const factors = [];
892
+ let confidence = 0;
893
+ if (iframe.totalCount > 10) {
894
+ confidence += 0.3;
895
+ factors.push({
896
+ factor: "excessive_iframes",
897
+ weight: 0.3,
898
+ evidence: `${iframe.totalCount} iframes active`
899
+ });
900
+ } else if (iframe.totalCount > 5) {
901
+ confidence += 0.15;
902
+ factors.push({
903
+ factor: "many_iframes",
904
+ weight: 0.15,
905
+ evidence: `${iframe.totalCount} iframes active`
906
+ });
907
+ }
908
+ if (iframe.addedLast60s > 5) {
909
+ confidence += 0.25;
910
+ factors.push({
911
+ factor: "rapid_iframe_creation",
912
+ weight: 0.25,
913
+ evidence: `${iframe.addedLast60s} iframes added in last 60s`
914
+ });
915
+ }
916
+ if (iframe.crossOriginCount > 3) {
917
+ confidence += 0.2;
918
+ factors.push({
919
+ factor: "cross_origin_iframes",
920
+ weight: 0.2,
921
+ evidence: `${iframe.crossOriginCount} cross-origin iframes`
922
+ });
923
+ }
924
+ const mem = event.system.memory;
925
+ if (mem && mem.trend === "growing" && (mem.utilizationPercent ?? 0) > 70) {
926
+ confidence += 0.25;
927
+ factors.push({
928
+ factor: "iframe_memory_correlation",
929
+ weight: 0.25,
930
+ evidence: `Memory growing at ${mem.utilizationPercent}% with ${iframe.totalCount} iframes`
931
+ });
932
+ }
933
+ const subcategory = iframe.addedLast60s > 5 ? "rapid_creation" : iframe.crossOriginCount > 3 ? "cross_origin_overload" : iframe.totalCount > 10 ? "excessive_count" : "iframe_pressure";
934
+ return {
935
+ category: "iframe_overload",
936
+ subcategory,
937
+ confidence: Math.min(confidence, 1),
938
+ factors
939
+ };
940
+ }
941
+ function classifyCrash(event) {
942
+ const evaluators = [
943
+ evaluateReactFramework,
944
+ evaluateVueFramework,
945
+ evaluateIframeOverload,
946
+ evaluateMemoryIssue,
947
+ evaluateEventLoopBlocking,
948
+ evaluateNetworkInduced,
949
+ evaluateRuntimeError
950
+ ];
951
+ let best = {
952
+ category: "runtime_error",
953
+ subcategory: "unknown",
954
+ confidence: 0.1};
955
+ const allFactors = [];
956
+ for (const evaluate of evaluators) {
957
+ const result = evaluate(event);
958
+ if (result.confidence > 0.2) {
959
+ allFactors.push(...result.factors);
960
+ }
961
+ if (result.confidence > best.confidence) {
962
+ best = result;
963
+ }
964
+ }
965
+ return {
966
+ category: best.category,
967
+ subcategory: best.subcategory,
968
+ confidence: best.confidence,
969
+ contributingFactors: allFactors
970
+ };
971
+ }
972
+
973
+ // src/crashsense.ts
974
+ function createCrashSense(userConfig) {
975
+ const config = resolveConfig(userConfig);
976
+ const bus = utils.createEventBus();
977
+ const sessionId = utils.generateId();
978
+ const rateLimiter = utils.createRateLimiter(config.maxEventsPerMinute);
979
+ const deviceInfo = utils.collectDeviceInfo();
980
+ const plugins = [];
981
+ let userContext = {};
982
+ let destroyed = false;
983
+ const errorInterceptor = createErrorInterceptor(bus);
984
+ const memoryMonitor = createMemoryMonitor(bus);
985
+ const eventLoopMonitor = createEventLoopMonitor(bus);
986
+ const networkMonitor = createNetworkMonitor(bus);
987
+ const breadcrumbTracker = createBreadcrumbTracker(bus);
988
+ const iframeTracker = createIframeTracker(bus);
989
+ const preCrashWarning = createPreCrashWarning(bus, config, memoryMonitor, iframeTracker);
990
+ function buildRawEvent(error, source) {
991
+ const stack = error.stack ? utils.parseStackTrace(error.stack) : [];
992
+ return {
993
+ id: utils.generateId(),
994
+ timestamp: performance.now() + performance.timeOrigin,
995
+ sessionId,
996
+ error: {
997
+ type: error.constructor.name || error.name || "Error",
998
+ message: config.piiScrubbing ? utils.scrubPII(error.message) : error.message,
999
+ stack,
1000
+ raw: config.piiScrubbing ? utils.scrubPII(error.stack || "") : error.stack || ""
1001
+ },
1002
+ system: {
1003
+ memory: memoryMonitor.getSnapshot(),
1004
+ cpu: eventLoopMonitor.getCpuSnapshot(),
1005
+ eventLoop: eventLoopMonitor.getEventLoopSnapshot(),
1006
+ network: networkMonitor.getSnapshot(),
1007
+ iframe: config.enableIframeTracking ? iframeTracker.getSnapshot() : void 0
1008
+ },
1009
+ device: deviceInfo,
1010
+ framework: {},
1011
+ breadcrumbs: breadcrumbTracker.getBreadcrumbs(),
1012
+ meta: {
1013
+ appId: config.appId,
1014
+ environment: config.environment,
1015
+ release: config.release || void 0,
1016
+ userId: userContext.id,
1017
+ tags: { source },
1018
+ sdkVersion: SDK_VERSION
1019
+ }
1020
+ };
1021
+ }
1022
+ function processRawEvent(rawEvent) {
1023
+ if (destroyed) return;
1024
+ if (Math.random() > config.sampleRate) return;
1025
+ if (!rateLimiter.tryAcquire()) return;
1026
+ const classification = classifyCrash(rawEvent);
1027
+ let crashEvent = {
1028
+ id: rawEvent.id,
1029
+ fingerprint: utils.generateFingerprint(
1030
+ rawEvent.error.type,
1031
+ rawEvent.error.message,
1032
+ rawEvent.error.stack
1033
+ ),
1034
+ timestamp: rawEvent.timestamp,
1035
+ sessionId: rawEvent.sessionId,
1036
+ category: classification.category,
1037
+ subcategory: classification.subcategory,
1038
+ severity: classification.confidence > 0.8 ? "critical" : "error",
1039
+ confidence: classification.confidence,
1040
+ error: rawEvent.error,
1041
+ system: {
1042
+ memory: rawEvent.system.memory ?? memoryMonitor.getSnapshot(),
1043
+ cpu: rawEvent.system.cpu ?? eventLoopMonitor.getCpuSnapshot(),
1044
+ eventLoop: rawEvent.system.eventLoop ?? eventLoopMonitor.getEventLoopSnapshot(),
1045
+ network: rawEvent.system.network ?? networkMonitor.getSnapshot(),
1046
+ iframe: rawEvent.system.iframe ?? (config.enableIframeTracking ? iframeTracker.getSnapshot() : void 0)
1047
+ },
1048
+ device: rawEvent.device,
1049
+ framework: {
1050
+ name: rawEvent.framework.name ?? "vanilla",
1051
+ version: rawEvent.framework.version ?? "",
1052
+ adapter: rawEvent.framework.adapter ?? SDK_VERSION,
1053
+ componentTree: rawEvent.framework.componentTree,
1054
+ currentRoute: rawEvent.framework.currentRoute,
1055
+ storeState: rawEvent.framework.storeState,
1056
+ lifecycleStage: rawEvent.framework.lifecycleStage,
1057
+ renderCount: rawEvent.framework.renderCount
1058
+ },
1059
+ breadcrumbs: rawEvent.breadcrumbs,
1060
+ contributingFactors: classification.contributingFactors,
1061
+ meta: rawEvent.meta
1062
+ };
1063
+ for (const plugin of plugins) {
1064
+ if (plugin.onCrashEvent) {
1065
+ const modified = plugin.onCrashEvent(crashEvent);
1066
+ if (modified === null) return;
1067
+ crashEvent = modified;
1068
+ }
1069
+ }
1070
+ const report = {
1071
+ event: crashEvent,
1072
+ analysis: null,
1073
+ timestamp: Date.now()
1074
+ };
1075
+ bus.emit("crash_detected", { event: crashEvent });
1076
+ if (config.onCrash) {
1077
+ try {
1078
+ config.onCrash(report);
1079
+ } catch (_) {
1080
+ }
1081
+ }
1082
+ if (config.debug) {
1083
+ logCrashReport(report);
1084
+ }
1085
+ }
1086
+ function logCrashReport(report) {
1087
+ const e = report.event;
1088
+ const header = `[CrashSense] ${e.category}/${e.subcategory} (confidence: ${(e.confidence * 100).toFixed(0)}%)`;
1089
+ const details = [
1090
+ `Error: ${e.error.type}: ${e.error.message}`,
1091
+ `Device: ${e.device.userAgent.slice(0, 80)}`,
1092
+ `Memory: ${e.system.memory.utilizationPercent ?? "N/A"}% used`,
1093
+ `Long Tasks (30s): ${e.system.cpu.longTasksLast30s}`,
1094
+ `FPS: ${e.system.eventLoop.fps}`
1095
+ ];
1096
+ if (typeof console !== "undefined") {
1097
+ console.groupCollapsed?.(header) ?? console.log(header);
1098
+ for (const d of details) console.log(d);
1099
+ if (e.contributingFactors.length > 0) {
1100
+ console.log("Contributing factors:");
1101
+ for (const f of e.contributingFactors) {
1102
+ console.log(` - ${f.factor} (${(f.weight * 100).toFixed(0)}%): ${f.evidence}`);
1103
+ }
1104
+ }
1105
+ console.groupEnd?.();
1106
+ }
1107
+ }
1108
+ bus.on("error", (data) => {
1109
+ const rawEvent = buildRawEvent(data.error, "window.onerror");
1110
+ processRawEvent(rawEvent);
1111
+ });
1112
+ bus.on("unhandled_rejection", (data) => {
1113
+ const error = data.reason instanceof Error ? data.reason : new Error(String(data.reason));
1114
+ const rawEvent = buildRawEvent(error, "unhandledrejection");
1115
+ processRawEvent(rawEvent);
1116
+ });
1117
+ bus.on("iframe_added", (data) => {
1118
+ breadcrumbTracker.addBreadcrumb({
1119
+ type: "custom",
1120
+ message: `Iframe added: ${data.origin} (total: ${data.totalCount})`,
1121
+ data: { src: data.src, crossOrigin: data.crossOrigin }
1122
+ });
1123
+ });
1124
+ bus.on("iframe_removed", (data) => {
1125
+ breadcrumbTracker.addBreadcrumb({
1126
+ type: "custom",
1127
+ message: `Iframe removed (total: ${data.totalCount})`,
1128
+ data: { src: data.src }
1129
+ });
1130
+ });
1131
+ bus.on("pre_crash_warning", (data) => {
1132
+ breadcrumbTracker.addBreadcrumb({
1133
+ type: "custom",
1134
+ message: `Pre-crash warning [${data.level}]: ${data.reason}`,
1135
+ data: { level: data.level, memoryUtilization: data.memoryUtilization, iframeCount: data.iframeCount }
1136
+ });
1137
+ });
1138
+ errorInterceptor.install();
1139
+ breadcrumbTracker.install();
1140
+ if (config.enableMemoryMonitoring) memoryMonitor.start();
1141
+ if (config.enableLongTaskMonitoring) eventLoopMonitor.start();
1142
+ if (config.enableNetworkMonitoring) networkMonitor.start();
1143
+ if (config.enableIframeTracking) iframeTracker.start();
1144
+ if (config.enablePreCrashWarning) preCrashWarning.start();
1145
+ const core = {
1146
+ get config() {
1147
+ return config;
1148
+ },
1149
+ get sessionId() {
1150
+ return sessionId;
1151
+ },
1152
+ use(plugin) {
1153
+ plugins.push(plugin);
1154
+ plugin.setup(core);
1155
+ },
1156
+ captureException(error, context) {
1157
+ const err = error instanceof Error ? error : new Error(String(error));
1158
+ const rawEvent = buildRawEvent(err, "manual");
1159
+ if (context) {
1160
+ rawEvent.meta.tags = { ...rawEvent.meta.tags, ...Object.fromEntries(
1161
+ Object.entries(context).map(([k, v]) => [k, String(v)])
1162
+ ) };
1163
+ }
1164
+ processRawEvent(rawEvent);
1165
+ },
1166
+ captureMessage(message, severity = "info") {
1167
+ const rawEvent = buildRawEvent(new Error(message), "message");
1168
+ rawEvent.error.type = "Message";
1169
+ rawEvent.meta.tags.severity = severity;
1170
+ processRawEvent(rawEvent);
1171
+ },
1172
+ addBreadcrumb(bc) {
1173
+ breadcrumbTracker.addBreadcrumb(bc);
1174
+ },
1175
+ setUser(user) {
1176
+ userContext = user;
1177
+ },
1178
+ setContext(key, value) {
1179
+ },
1180
+ getSystemState() {
1181
+ return {
1182
+ memory: memoryMonitor.getSnapshot(),
1183
+ cpu: eventLoopMonitor.getCpuSnapshot(),
1184
+ eventLoop: eventLoopMonitor.getEventLoopSnapshot(),
1185
+ network: networkMonitor.getSnapshot(),
1186
+ iframe: config.enableIframeTracking ? iframeTracker.getSnapshot() : void 0
1187
+ };
1188
+ },
1189
+ getDeviceInfo() {
1190
+ return deviceInfo;
1191
+ },
1192
+ destroy() {
1193
+ if (destroyed) return;
1194
+ destroyed = true;
1195
+ errorInterceptor.uninstall();
1196
+ breadcrumbTracker.uninstall();
1197
+ memoryMonitor.stop();
1198
+ eventLoopMonitor.stop();
1199
+ networkMonitor.stop();
1200
+ iframeTracker.stop();
1201
+ preCrashWarning.stop();
1202
+ for (const plugin of plugins) {
1203
+ plugin.teardown();
1204
+ }
1205
+ },
1206
+ _reportRawEvent(event) {
1207
+ processRawEvent(event);
1208
+ },
1209
+ _getEventBus() {
1210
+ return bus;
1211
+ }
1212
+ };
1213
+ return core;
1214
+ }
1215
+
1216
+ exports.classifyCrash = classifyCrash;
1217
+ exports.createCrashSense = createCrashSense;
1218
+ //# sourceMappingURL=index.js.map
1219
+ //# sourceMappingURL=index.js.map