import { readdir, stat, rm } from "node:fs/promises"; import { PrismaClient } from "@prisma/client"; import { attachmentDirectory, attachmentPath } from "../src/lib/attachments"; // Dry run by default. A 24-hour grace period protects concurrent uploads. const prisma = new PrismaClient(); async function main() { const remove = process.argv.includes("--delete"); let candidates = 0; for (const entry of await readdir(attachmentDirectory(), { withFileTypes: true })) { if (!entry.isFile()) continue; let file: string; try { file = attachmentPath(entry.name); } catch { continue; } if ((await stat(file)).mtimeMs > Date.now() - 24 * 60 * 60_000) continue; if (await prisma.attachment.findUnique({ where: { id: entry.name }, select: { id: true } })) continue; candidates++; if (remove) await rm(file, { force: true }); } console.log(`${candidates} orphan attachments ${remove ? "removed" : "found (dry run)"}`); } main().finally(() => prisma.$disconnect()).catch(error => { console.error(error); process.exitCode = 1; });