export interface LogEntry { id: string; timestamp: Date; level: "debug" | "info" | "warn" | "error"; message: string; details?: string; } let nextId = 1; export function useLoggerState() { return useState("dev-logs", () => []); } export function useLogger() { const logs = useLoggerState(); function log(level: LogEntry["level"], message: string, details?: string) { const entry: LogEntry = { id: String(nextId++), timestamp: new Date(), level, message, details, }; logs.value.unshift(entry); // Keep max 200 entries if (logs.value.length > 200) { logs.value = logs.value.slice(0, 200); } // Also mirror to console const consoleMsg = details ? `${message} | ${details}` : message; if (level === "error") console.error(consoleMsg); else if (level === "warn") console.warn(consoleMsg); else if (level === "debug") console.debug(consoleMsg); else console.log(consoleMsg); } function debug(message: string, details?: string) { log("debug", message, details); } function info(message: string, details?: string) { log("info", message, details); } function warn(message: string, details?: string) { log("warn", message, details); } function error(message: string, details?: string) { log("error", message, details); } function clear() { logs.value = []; } function exportLogs(): string { return logs.value .slice() .reverse() .map( (entry) => `[${entry.timestamp.toISOString()}] [${entry.level.toUpperCase()}] ${entry.message}${ entry.details ? `\n Details: ${entry.details}` : "" }`, ) .join("\n---\n"); } return { logs, debug, info, warn, error, clear, exportLogs, }; } export function formatError(err: unknown): { message: string; details?: string } { if (err instanceof Error) { return { message: err.message, details: err.stack }; } if (typeof err === "string") { return { message: err }; } try { return { message: JSON.stringify(err) }; } catch { return { message: "Unknown error" }; } }