globalCapture.ts2.4 KBView on GitHub import { push } from './buffer';
const LONGTASK_THRESHOLD_MS = 100;
let initialized = false;
let perfObserver: PerformanceObserver | null = null;
let errorHandler: ((e: ErrorEvent) => void) | null = null;
let rejectionHandler: ((e: PromiseRejectionEvent) => void) | null = null;
export function initGlobalCapture(): void {
if (initialized || typeof window === 'undefined') return;
initialized = true;
errorHandler = (e: ErrorEvent) => {
push({
source: 'error',
kind: 'window',
message: e.message || String(e.error),
stack: e.error instanceof Error ? e.error.stack : undefined,
});
};
window.addEventListener('error', errorHandler);
rejectionHandler = (e: PromiseRejectionEvent) => {
const reason = e.reason;
push({
source: 'error',
kind: 'rejection',
message: reason instanceof Error ? reason.message : String(reason),
stack: reason instanceof Error ? reason.stack : undefined,
});
};
window.addEventListener('unhandledrejection', rejectionHandler);
if (typeof PerformanceObserver !== 'undefined') {
try {
perfObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'longtask' && entry.duration >= LONGTASK_THRESHOLD_MS) {
push({
source: 'perf',
name: 'longtask',
durationMs: entry.duration,
detail: {
startTime: entry.startTime,
attribution: (entry as PerformanceEntry & {
attribution?: Array<{ name?: string; containerType?: string; containerSrc?: string }>;
}).attribution?.map((a) => ({
name: a.name,
containerType: a.containerType,
containerSrc: a.containerSrc,
})),
},
});
}
}
});
perfObserver.observe({ entryTypes: ['longtask'] });
} catch {
// longtask not supported in this browser; ignore
}
}
}
export function disposeGlobalCapture(): void {
if (!initialized) return;
if (errorHandler) window.removeEventListener('error', errorHandler);
if (rejectionHandler) window.removeEventListener('unhandledrejection', rejectionHandler);
perfObserver?.disconnect();
errorHandler = null;
rejectionHandler = null;
perfObserver = null;
initialized = false;
}