import { run } from "../db"; const DELIVERY_RETENTION_MS = 30 * 24 * 60 * 60_000; const PRUNE_BATCH = 500; /** Integrations whose repo or org no longer exists hold live credentials for nothing; remove them. */ async function pruneOrphanedIntegrations(): Promise { await run( `DELETE FROM integrations WHERE id IN ( SELECT id FROM integrations WHERE scope_type = 'repo' AND scope_id NOT IN (SELECT id FROM repos) LIMIT ?)`, PRUNE_BATCH, ); await run( `DELETE FROM integrations WHERE id IN ( SELECT id FROM integrations WHERE scope_type = 'org' AND scope_id NOT IN (SELECT id FROM accounts) LIMIT ?)`, PRUNE_BATCH, ); } /** Integration delivery logs (inbound and outbound) are kept for 30 days, pruned in batches. */ async function pruneDeliveryLogs(now: number): Promise { const cutoff = now - DELIVERY_RETENTION_MS; await run( "DELETE FROM integration_deliveries WHERE id IN (SELECT id FROM integration_deliveries WHERE created_at < ? LIMIT ?)", cutoff, PRUNE_BATCH, ); } /** Legacy webhook deliveries live in their repository's RepoState, whose alarm expires them (housekeeping.ts). */ export const WEBHOOK_DELIVERY_RETENTION_MS = DELIVERY_RETENTION_MS; /** Cron tail: orphaned integrations (INT-A25) and unbounded delivery logs (INT-A27). */ export async function pruneIntegrationLeftovers(now: number): Promise { await pruneOrphanedIntegrations(); await pruneDeliveryLogs(now); }