export type LogLevel = "info" | "warn" | "error"; export interface LogEntry { timestamp: number; level: LogLevel; message: string; } type LogListener = () => void; const MAX_ENTRIES = 500; const STORAGE_KEY = "simpl-resultat-logs"; const logs: LogEntry[] = []; const listeners = new Set(); let initialized = false; function loadFromStorage() { try { const stored = sessionStorage.getItem(STORAGE_KEY); if (stored) { const parsed: LogEntry[] = JSON.parse(stored); logs.push(...parsed); } } catch { // ignore corrupted storage } } function saveToStorage() { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(logs)); } catch { // ignore quota errors } } function addEntry(level: LogLevel, args: unknown[]) { const message = args .map((a) => { if (typeof a === "string") return a; try { return JSON.stringify(a); } catch { return String(a); } }) .join(" "); logs.push({ timestamp: Date.now(), level, message }); if (logs.length > MAX_ENTRIES) { logs.splice(0, logs.length - MAX_ENTRIES); } saveToStorage(); listeners.forEach((fn) => fn()); } export function initLogCapture() { if (initialized) return; initialized = true; loadFromStorage(); const origLog = console.log.bind(console); const origWarn = console.warn.bind(console); const origError = console.error.bind(console); console.log = (...args: unknown[]) => { addEntry("info", args); origLog(...args); }; console.warn = (...args: unknown[]) => { addEntry("warn", args); origWarn(...args); }; console.error = (...args: unknown[]) => { addEntry("error", args); origError(...args); }; } export function getLogs(): readonly LogEntry[] { return logs; } /// Extract the N most recent non-info entries formatted as a single string, /// suitable for appending to a feedback body. Empty string if no qualifying /// entries. Each line: `[ISO timestamp] LEVEL: message`. export function getRecentErrorLogs(n: number): string { if (n <= 0) return ""; const errors = logs.filter((l) => l.level !== "info"); const tail = errors.slice(Math.max(0, errors.length - n)); return tail .map((l) => { const iso = new Date(l.timestamp).toISOString(); return `[${iso}] ${l.level.toUpperCase()}: ${l.message}`; }) .join("\n"); } export function clearLogs() { logs.length = 0; saveToStorage(); listeners.forEach((fn) => fn()); } export function subscribe(listener: LogListener): () => void { listeners.add(listener); return () => listeners.delete(listener); }