routerOnly / src /lib /consoleLogBuffer.js
HF Deployer
Init 9Router for HF Space (no binaries)
ebd68ab
Raw
History Blame Contribute Delete
2.63 kB
import { EventEmitter } from "events";
import { CONSOLE_LOG_CONFIG } from "@/shared/constants/config.js";
const consoleLevels = ["log", "info", "warn", "error", "debug"];
if (!global._consoleLogBufferState) {
global._consoleLogBufferState = {
logs: [],
patched: false,
originals: {},
emitter: new EventEmitter(),
};
global._consoleLogBufferState.emitter.setMaxListeners(50);
}
const state = global._consoleLogBufferState;
// Ensure emitter exists (handles hot reload with stale global)
if (!state.emitter) {
state.emitter = new EventEmitter();
state.emitter.setMaxListeners(50);
}
if (!state.pendingLines) state.pendingLines = [];
if (!state.flushTimer) state.flushTimer = null;
const FLUSH_INTERVAL_MS = 100;
const MAX_BATCH_LINES = 50;
function flushPendingLines() {
state.flushTimer = null;
if (!state.pendingLines.length) return;
const lines = state.pendingLines.splice(0, state.pendingLines.length);
state.emitter.emit("lines", lines);
}
function scheduleFlush() {
if (state.flushTimer) return;
state.flushTimer = setTimeout(flushPendingLines, FLUSH_INTERVAL_MS);
state.flushTimer?.unref?.();
}
function toLogLine(level, args) {
return args.map(formatArg).join(" ");
}
// Strip ANSI escape codes so terminal colors don't bleed into UI
const ANSI_RE = /\x1b\[[0-9;]*m/g;
function stripAnsi(str) {
return str.replace(ANSI_RE, "");
}
function formatArg(arg) {
if (typeof arg === "string") return stripAnsi(arg);
if (arg instanceof Error) return stripAnsi(arg.stack || arg.message || String(arg));
try {
return stripAnsi(JSON.stringify(arg));
} catch {
return stripAnsi(String(arg));
}
}
function appendLine(line) {
state.logs.push(line);
const maxLines = CONSOLE_LOG_CONFIG.maxLines;
if (state.logs.length > maxLines) {
state.logs = state.logs.slice(-maxLines);
}
state.pendingLines.push(line);
if (state.pendingLines.length >= MAX_BATCH_LINES) {
if (state.flushTimer) {
clearTimeout(state.flushTimer);
state.flushTimer = null;
}
flushPendingLines();
} else {
scheduleFlush();
}
}
export function initConsoleLogCapture() {
if (state.patched) return;
for (const level of consoleLevels) {
state.originals[level] = console[level];
console[level] = (...args) => {
appendLine(toLogLine(level, args));
state.originals[level](...args);
};
}
state.patched = true;
}
export function getConsoleLogs() {
return state.logs;
}
export function clearConsoleLogs() {
state.logs = [];
state.emitter.emit("clear");
}
export function getConsoleEmitter() {
return state.emitter;
}