import { postJson } from './http'; export type ClientErrorLevel = 'fatal' | 'error' | 'warn' | 'info'; export type ClientErrorCategory = | 'js_error' | 'unhandled_rejection' | 'api_error' | 'validation_error' | 'network' | 'render' | 'bridge' | 'other'; export type ClientErrorReporterOptions = { apiBase: string; clientApp: string; getToken?: () => string | null; }; export function installClientErrorReporting(opts: ClientErrorReporterOptions) { if (typeof window === 'undefined') return; const report = (payload: { level: ClientErrorLevel; category: ClientErrorCategory; message: string; stack?: string; extra?: Record; }) => { const token = opts.getToken?.() ?? localStorage.getItem('accessToken'); const headers: Record = { 'Content-Type': 'application/json', 'X-Client-App': opts.clientApp, }; if (token) headers.Authorization = `Bearer ${token}`; postJson({ url: `${opts.apiBase}/common/client-errors`, headers, body: { level: payload.level, category: payload.category, message: payload.message, stack: payload.stack, pagePath: window.location.pathname, clientApp: opts.clientApp, extra: payload.extra, }, }); }; window.addEventListener('error', (ev) => { report({ level: 'error', category: 'js_error', message: ev.message || 'Unknown error', stack: ev.error instanceof Error ? ev.error.stack : undefined, }); }); window.addEventListener('unhandledrejection', (ev) => { const reason = ev.reason; report({ level: 'error', category: 'unhandled_rejection', message: reason instanceof Error ? reason.message : String(reason), stack: reason instanceof Error ? reason.stack : undefined, }); }); } export function reportApiError( opts: ClientErrorReporterOptions, input: { message: string; status?: number; url?: string; category?: ClientErrorCategory }, ) { if (typeof window === 'undefined') return; if (input.url?.includes('/common/client-errors')) return; const token = opts.getToken?.() ?? localStorage.getItem('accessToken'); const headers: Record = { 'Content-Type': 'application/json', 'X-Client-App': opts.clientApp, }; if (token) headers.Authorization = `Bearer ${token}`; postJson({ url: `${opts.apiBase}/common/client-errors`, headers, body: { level: 'warn', category: input.category ?? (input.status === 400 ? 'validation_error' : 'api_error'), message: input.message.slice(0, 1000), pagePath: window.location.pathname, clientApp: opts.clientApp, extra: { status: input.status, url: input.url }, }, }); }