fix: improve error handling and stability - no logout on transient errors, add ErrorBoundary, global error logging

This commit is contained in:
Agent Zero
2026-07-26 12:18:52 +02:00
parent e12b85c2ce
commit 808da564f3
7 changed files with 344 additions and 8 deletions
+106
View File
@@ -0,0 +1,106 @@
/**
* Global Error Logger
*
* Centralized error collection and reporting.
* - Always logs to console.error
* - Optionally POSTs to /api/v1/errors (silently fails if endpoint unavailable)
* - Buffers errors in sessionStorage (ring buffer, max 50)
*/
const STORAGE_KEY = 'leocrm_error_buffer';
const MAX_BUFFER_SIZE = 50;
interface ErrorEntry {
timestamp: string;
message: string;
stack?: string;
context?: Record<string, any>;
url?: string;
userAgent?: string;
}
function getBuffer(): ErrorEntry[] {
try {
const raw = sessionStorage.getItem(STORAGE_KEY);
if (!raw) return [];
return JSON.parse(raw) as ErrorEntry[];
} catch {
return [];
}
}
function saveBuffer(buffer: ErrorEntry[]): void {
try {
// Ring buffer: keep only the last MAX_BUFFER_SIZE entries
const trimmed = buffer.slice(-MAX_BUFFER_SIZE);
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(trimmed));
} catch {
// sessionStorage might be full or unavailable — silently ignore
}
}
function addToBuffer(entry: ErrorEntry): void {
const buffer = getBuffer();
buffer.push(entry);
saveBuffer(buffer);
}
/**
* Log an error with optional context.
* Always writes to console.error.
* Attempts to POST to /api/v1/errors (silently fails if unavailable).
* Buffers in sessionStorage as a ring buffer (max 50 entries).
*/
export function logError(error: Error | string, context?: Record<string, any>): void {
const message = typeof error === 'string' ? error : error.message;
const stack = typeof error === 'string' ? undefined : error.stack;
const entry: ErrorEntry = {
timestamp: new Date().toISOString(),
message,
stack,
context,
url: typeof window !== 'undefined' ? window.location.href : undefined,
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,
};
// Always log to console
console.error('[ErrorLogger]', message, { stack, context, url: entry.url });
// Buffer in sessionStorage
addToBuffer(entry);
// Attempt to send to backend (fire-and-forget, silently fail)
try {
fetch('/api/v1/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(entry),
}).catch(() => {
// Silently fail — endpoint may not exist or network may be down
});
} catch {
// Silently fail
}
}
/**
* Retrieve the buffered errors from sessionStorage.
*/
export function getErrorBuffer(): ErrorEntry[] {
return getBuffer();
}
/**
* Clear the error buffer from sessionStorage.
*/
export function clearErrorBuffer(): void {
try {
sessionStorage.removeItem(STORAGE_KEY);
} catch {
// Silently ignore
}
}
export default { logError, getErrorBuffer, clearErrorBuffer };