SPB Git

Repository Public

janitor.ts 1.6 KB 39 lines typescript

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
Files main
Menu

Theme