import prisma from '@/lib/prisma' export type AuditAction = | 'LOGIN' | 'LOGOUT' | 'USER_CREATED' | 'AI_REQUEST' | 'DATA_EXPORT' | 'ACCOUNT_DELETED' | 'PASSWORD_RESET' | 'AI_CONSENT_GRANTED' | 'AI_CONSENT_REVOKED' export interface AuditLogParams { userId?: string | null action: AuditAction resource?: string metadata?: Record ip?: string userAgent?: string } /** Fire-and-forget — never throws, safe to call anywhere */ export function logAuditEvent(params: AuditLogParams): void { prisma.auditLog .create({ data: { userId: params.userId ?? null, action: params.action, resource: params.resource ?? null, metadata: params.metadata ? (params.metadata as any) : undefined, ip: params.ip ?? null, userAgent: params.userAgent ?? null, }, }) .catch((err: unknown) => console.error('[audit-log] write failed:', err)) } /** Awaitable version for cases where ordering matters */ export async function logAuditEventAsync(params: AuditLogParams): Promise { try { await prisma.auditLog.create({ data: { userId: params.userId ?? null, action: params.action, resource: params.resource ?? null, metadata: params.metadata ? (params.metadata as any) : undefined, ip: params.ip ?? null, userAgent: params.userAgent ?? null, }, }) } catch (err) { console.error('[audit-log] write failed:', err) } } /** Extract IP from request headers (works behind Cloudflare / nginx) */ export function getClientIp(request: Request): string | undefined { const cf = request.headers.get('cf-connecting-ip') if (cf) return cf const xff = request.headers.get('x-forwarded-for') if (xff) return xff.split(',')[0].trim() return undefined }