import type { LogEntry, LogLevel, Logger } from '../logger.js'; /** A `LogEntry` tagged with where it came from, for display in `DebugPanel.svelte`. */ export interface DisplayLogEntry extends LogEntry { source: 'client' | 'server'; } const MAX_ENTRIES = 500; let entries: DisplayLogEntry[] = []; const subscribers = new Set<(entries: DisplayLogEntry[]) => void>(); function notify(): void { for (const run of subscribers) run(entries); } function push(entry: DisplayLogEntry): void { entries = entries.length >= MAX_ENTRIES ? [...entries.slice(1), entry] : [...entries, entry]; notify(); } /** * Feeds a server-forwarded `debug.log` entry into the same shared buffer the * panel renders. Not for direct use by app code — call `clientLogger` for * anything happening in the browser itself; this is exported specifically * for `server-log-forwarder.ts`. */ export function pushLogEntry(entry: LogEntry, source: DisplayLogEntry['source'] = 'server'): void { push({ ...entry, source }); } function log(level: LogLevel, category: string, message: string, data?: unknown): void { if (data === undefined) { console[level](`[${category}] ${message}`); } else { console[level](`[${category}] ${message}`, data); } push({ level, category, message, data, timestamp: Date.now(), source: 'client' }); } /** * Ambient client-side logger — any browser code (with or without a realtime * connection) can call this directly, e.g. `clientLogger.warn('ws', ...)`. * Feeds the same shared buffer `DebugPanel.svelte` renders. */ export const clientLogger: Logger = { debug: (category, message, data) => log('debug', category, message, data), info: (category, message, data) => log('info', category, message, data), warn: (category, message, data) => log('warn', category, message, data), error: (category, message, data) => log('error', category, message, data) }; /** * Read-only, Svelte-store-compatible view of the shared log buffer (client * entries plus anything forwarded from the server) — hand-rolled the same * way as `$lib/client/humanoid/avatar-state.ts`'s `deriveAvatarState`; no * `svelte/store` import anywhere in this repo, and this doesn't start one. */ export const debugLogStore = { subscribe(run: (entries: DisplayLogEntry[]) => void): () => void { subscribers.add(run); run(entries); return () => subscribers.delete(run); } }; export function clearLogs(): void { entries = []; notify(); }