import { appendFile } from 'fs/promises'; interface AuthLogParams { ip: string; userAgent: string; username: string; } interface FileNotFoundParams { ip: string; userAgent: string; fileId: string; } interface AuthLockoutTriggeredParams extends AuthLogParams { durationSeconds: number; } interface AuthLockedAttemptParams extends AuthLogParams { retryAfterSeconds: number; } interface AuthRateLimitedParams { ip: string; userAgent: string; route: string; } export interface Logger { authSuccess(params: AuthLogParams): Promise; authFailure(params: AuthLogParams): Promise; authLockoutTriggered(params: AuthLockoutTriggeredParams): Promise; authLockedAttempt(params: AuthLockedAttemptParams): Promise; authRateLimited(params: AuthRateLimitedParams): Promise; fileNotFound(params: FileNotFoundParams): Promise; } export function createLogger(logFile: string): Logger { function timestamp(): string { return new Date().toISOString(); } async function write(line: string): Promise { await appendFile(logFile, line + '\n'); } function authLine(event: string, { ip, userAgent, username }: AuthLogParams): string { return `[${timestamp()}] ${event} ip=${ip} user-agent="${userAgent}" username="${username}"`; } return { authSuccess: (params) => write(authLine('AUTH_SUCCESS', params)), authFailure: (params) => write(authLine('AUTH_FAILURE', params)), authLockoutTriggered: ({ durationSeconds, ...auth }) => write(`${authLine('AUTH_LOCKOUT_TRIGGERED', auth)} duration_seconds=${durationSeconds}`), authLockedAttempt: ({ retryAfterSeconds, ...auth }) => write(`${authLine('AUTH_LOCKED_ATTEMPT', auth)} retry_after_seconds=${retryAfterSeconds}`), authRateLimited: ({ ip, userAgent, route }) => write(`[${timestamp()}] AUTH_RATE_LIMITED ip=${ip} user-agent="${userAgent}" route="${route}"`), fileNotFound: ({ ip, userAgent, fileId }) => write(`[${timestamp()}] FILE_NOT_FOUND ip=${ip} user-agent="${userAgent}" file_id="${fileId}"`), }; }