import assert from "node:assert/strict"; import { randomUUID } from "node:crypto"; import { mkdir, writeFile } from "node:fs/promises"; import { createClient } from "@supabase/supabase-js"; import sharp from "sharp"; process.loadEnvFile(".env.local"); const origin = new URL(process.argv[2] || "https://minegeo.site").origin; const db = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.SUPABASE_SECRET_KEY, { auth: { persistSession: false, autoRefreshToken: false } }, ); const checked = (r) => { if (r.error) throw new Error(r.error.message); return r.data; }; const cookies = new Map(); let id; await mkdir(".data/retention-check", { recursive: true }); async function api(path, body, expected = 200, stranger = false) { const response = await fetch(`${origin}/api/v1/bug-reports${path}`, { method: body === undefined ? "GET" : "POST", headers: { origin, "content-type": "application/json", cookie: stranger ? "" : [...cookies].map(([k, v]) => `${k}=${v}`).join("; "), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), signal: AbortSignal.timeout(60000), }); if (!stranger) for (const cookie of response.headers.getSetCookie()) { const part = cookie.split(";")[0], at = part.indexOf("="); cookies.set(part.slice(0, at), part.slice(at + 1)); } const result = await response.json(); assert.equal(response.status, expected, `${path}: ${JSON.stringify(result)}`); return result; } async function row() { return checked( await db.from("bug_reports").select("*").eq("id", id).maybeSingle(), ); } async function waitFor(predicate, label) { for (let n = 0; n < 40; n++) { const current = await row(); if (predicate(current)) return current; if (current?.cleanup_error) throw new Error(current.cleanup_error); await new Promise((r) => setTimeout(r, 3000)); } throw new Error(`Timed out: ${label}`); } assert.equal((await api("")).ready, true); const created = await api("", { clientId: randomUUID(), title: `[Verification] Retention ${randomUUID()}`, description: "Automated temporary verification fixture for three-day report retention. This is not a real player bug.", displayName: "Support verification", pagePath: "/support", screenshot: true, }); id = created.id; await writeFile( ".data/retention-check/fixture.json", JSON.stringify({ id, cookies: [...cookies] }), ); const image = await sharp({ create: { width: 8, height: 8, channels: 3, background: "#334455" }, }) .png() .toBuffer(); assert.equal( ( await fetch(created.upload, { method: "PUT", headers: { "content-type": "image/png" }, body: image, }) ).ok, true, ); await api(`/${id}/submit`, {}); await waitFor((r) => r?.issue_synced, "Linear issue creation"); await api(`/${id}/close`, {}, 404, true); const closed = await api(`/${id}/close`, {}); assert.equal(closed.state, "done"); assert.equal( Date.parse(closed.delete_after) - Date.parse(closed.closed_at), 3 * 86400000, ); assert.equal((await api(`/${id}/close`, {})).delete_after, closed.delete_after); await api( `/${id}/messages`, { clientId: randomUUID(), text: "Blocked after closure" }, 409, ); await waitFor((r) => r?.linear_done_synced, "Linear Done status"); console.log( JSON.stringify({ fixture: id, checkpoint: "Done synchronized; three-day deadline and ownership verified", }), ); // Accelerate only this journaled verification fixture; no real report is modified. const backdated = new Date(Date.now() - 3 * 86400000 - 60000).toISOString(); checked( await db .from("bug_reports") .update({ closed_at: backdated, delete_after: new Date(Date.now() - 60000).toISOString(), cleanup_run_id: null, cleanup_lease_until: null, status_checked_at: new Date().toISOString(), }) .eq("id", id) .like("title", "[Verification] Retention %"), ); await api(`/${id}/retry-cleanup`, {}); await waitFor((r) => r === null, "both-system deletion"); assert.equal( checked(await db.from("bug_report_messages").select("id").eq("report_id", id)) .length, 0, ); assert.equal( checked(await db.storage.from("minegeo-support").list(id)).length, 0, ); await api(`/${id}`, undefined, 404); await writeFile( ".data/retention-check/fixture.json", JSON.stringify({ id, deleted: true }), ); console.log( JSON.stringify({ fixture: id, checkpoint: "Expired report, messages, screenshots and Linear issue deleted", }), );