Repository Public
1/**2 * Daily retention of the server-owned tables:3 * login_attempts: 30 d · audit_events: 400 d · notifications: 90 d ·4 * auth_sessions: 7 d after expiry/revocation · preauth_challenges: once expired.5 * Kernel tables (steps, events, waits…) are the journal and are never pruned here.6 */7import type { FastifyBaseLogger } from 'fastify';8import type { Db } from './db.js';910export async function runJanitor(db: Db): Promise<Record<string, number>> {11 const del = async (sql: string): Promise<number> => (await db.q(`WITH d AS (${sql} RETURNING 1) SELECT count(*)::int AS n FROM d`))[0]?.n as number;12 return {13 login_attempts: await del("DELETE FROM login_attempts WHERE at < now() - interval '30 days'"),14 audit_events: await del("DELETE FROM audit_events WHERE at < now() - interval '400 days'"),15 notifications: await del("DELETE FROM notifications WHERE created_at < now() - interval '90 days'"),16 auth_sessions: await del(17 "DELETE FROM auth_sessions WHERE expires_at < now() - interval '7 days' OR revoked_at < now() - interval '7 days'",18 ),19 preauth_challenges: await del('DELETE FROM preauth_challenges WHERE expires_at < now()'),20 };21}2223export function startJanitor(db: Db, log: FastifyBaseLogger): () => void {24 const run = (): void => {25 runJanitor(db).then(26 (deleted) => log.info({ deleted }, 'janitor pass'),27 (err: unknown) => log.error({ err }, 'janitor failed'),28 );29 };30 const first = setTimeout(run, 60_000);31 const timer = setInterval(run, 24 * 3600 * 1000);32 first.unref();33 timer.unref();34 return () => {35 clearTimeout(first);36 clearInterval(timer);37 };38}39