import { appendFileSync, closeSync, mkdirSync, openSync, readdirSync, unlinkSync } from 'fs' import { join } from 'path' export function redactLog(value: string): string { return value .replace(/(https?:\/\/)[^\s/@]+@/gi, '$1[REDACTED]@') .replace(/\bBearer\s+[^\s"',;]+/gi, 'Bearer [REDACTED]') .replace(/((?:[?&]|--)(?:[^\s=&]*token|password|secret|code|key)=)[^\s&#"']+/gi, '$1[REDACTED]') .replace(/(["']?(?:[\w-]*token|password|secret|authorization|api[_-]?key)["']?\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,;}]+)/gi, '$1[REDACTED]') } function localDate(now: Date): string { return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}` } export function createDailyLog(directories: string[], now: () => Date = () => new Date()) { let activePath = '' let activeDay = '' function selectFile(): string { const day = localDate(now()) if (activePath && activeDay === day) return activePath for (const directory of [...new Set(directories)]) { try { mkdirSync(directory, { recursive: true }) const path = join(directory, `lms-${day}.log`) closeSync(openSync(path, 'a', 0o600)) activePath = path activeDay = day for (const name of readdirSync(directory)) { if (/^lms-\d{4}-\d{2}-\d{2}\.log$/.test(name) && name < `lms-${day}.log`) { try { unlinkSync(join(directory, name)) } catch { /* Retention must not block startup. */ } } } return path } catch { /* Try the user-writable fallback directory. */ } } return '' } return { path: selectFile, write(kind: string, message: string): void { try { const path = selectFile() if (!path) return appendFileSync(path, `[${now().toISOString()}] [${redactLog(kind)}] ${redactLog(message)}\n`, { mode: 0o600 }) } catch { /* Diagnostics must not interrupt the app. */ } } } }