import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import { mkdir, readFile, writeFile, copyFile } from "node:fs/promises"; import { createClient } from "@supabase/supabase-js"; process.loadEnvFile(".env.local"); const db = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SECRET_KEY!, { auth: { persistSession: false } }, ); const account = JSON.parse(await readFile(".data/test-account.json", "utf8")); const origin = "http://127.0.0.1:3100", directory = `.data/api-smoke-${Date.now()}`; await mkdir(directory, { recursive: true }); const manifest = JSON.parse( await readFile( ".cache/paper-proof/plugins/MineGeo/export/manifest.json", "utf8", ), ); manifest.name = "Private API regression"; manifest.serverName = "MineGeo API regression"; await writeFile(`${directory}/manifest.json`, JSON.stringify(manifest)); await copyFile( ".cache/paper-proof/plugins/MineGeo/export/terrain.json.gz", `${directory}/terrain.json.gz`, ); const server = spawn( process.execPath, [ "node_modules/next/dist/bin/next", "start", "--hostname", "127.0.0.1", "--port", "3100", ], { stdio: ["ignore", "pipe", "pipe"], windowsHide: true }, ); let serverLog = ""; server.stdout.on("data", (data) => (serverLog += data)); server.stderr.on("data", (data) => (serverLog += data)); const stopped = new Promise((resolve) => server.on("exit", () => resolve()), ); const request = (path: string, body?: unknown, authenticated = true) => fetch(origin + "/api/v1/" + path, { method: body === undefined ? "GET" : "POST", headers: { ...(authenticated ? { authorization: "Bearer " + account.token } : {}), "content-type": "application/json", }, body: body === undefined ? undefined : JSON.stringify(body), }); let datasetId: string | undefined, serverId: string | undefined; try { let ready = false; for (let i = 0; i < 60; i++) { try { const response = await fetch(origin + "/api/v1/health"); if (response.ok) { ready = true; break; } } catch {} await new Promise((r) => setTimeout(r, 1000)); } assert.ok(ready, "Production server and database must become healthy"); for (const path of [ "/", "/servers", "/downloads", "/fonts/VT323-Regular.ttf", "/images/example-map.webp", "/tools/plugin/minegeo-plugin-1.21.11.jar", "/tools/mod/minegeo-fabric-1.21.11.jar", ]) { const response = await fetch(origin + path); assert.equal(response.status, 200, path); const bytes = await response.arrayBuffer(); assert.ok(bytes.byteLength > 0); if (path === "/") { const html = new TextDecoder().decode(bytes); assert.ok(html.includes("blocky world")); assert.ok(html.includes("COMMUNITY MAPS")); } console.log("HTTP 200 " + path); } const child = spawn( "java", [ "--class-path", "public/tools/plugin/minegeo-plugin-1.21.11.jar", "tests/java/UploadSmoke.java", origin, directory, ".data/test-account.json", ], { stdio: ["ignore", "pipe", "pipe"], windowsHide: true }, ); let javaLog = ""; child.stdout.on("data", (data) => { javaLog += data; process.stdout.write(data); }); child.stderr.on("data", (data) => (javaLog += data)); const code = await new Promise((resolve) => child.on("exit", resolve), ); assert.equal(code, 0, javaLog); const ledger = JSON.parse( await readFile(`${directory}/.upload-state.json`, "utf8"), ); datasetId = ledger.datasetId; const draftResponse = await request("datasets/" + datasetId); assert.equal(draftResponse.status, 200); const draft = await draftResponse.json(); serverId = draft.server_id; assert.ok(["processing", "draft"].includes(draft.state)); if (draft.state === "processing") assert.ok( draft.previews.every((p: any) => p.image === null), "Pending media must not be signed", ); const anonymous = await request("datasets/" + datasetId, undefined, false); assert.ok(anonymous.status >= 400, "Private draft must reject guests"); if (draft.state === "processing") { const cancel = await request("datasets/" + datasetId + "/cancel", {}); assert.equal(cancel.status, 200, await cancel.text()); } // A never-finalized upload has no queue row: cancellation must still work. const created = await request("uploads", { manifest }); assert.equal(created.status, 200); const empty = await created.json(); const cancelled = await request( "datasets/" + empty.datasetId + "/cancel", {}, ); assert.equal(cancelled.status, 200, await cancelled.text()); const cleanup = await db .from("datasets") .delete() .eq("id", empty.datasetId) .eq("owner_id", account.id); if (cleanup.error) throw cleanup.error; await writeFile( "artifacts-api-smoke.json", JSON.stringify( { passed: true, checks: [ "production homepage/catalog/downloads/assets", "Java uploader to real Supabase Storage", "private draft before rendered assets exist", "guests denied private drafts", "cancel queued processing", "cancel unfinished upload without a queue row", ], }, null, 2, ), ); console.log("REAL STORAGE / API SMOKE PASSED"); } finally { if (!datasetId) { try { datasetId = JSON.parse( await readFile(`${directory}/.upload-state.json`, "utf8"), ).datasetId; } catch {} } if (datasetId) { const record = await db .from("datasets") .select("server_id") .eq("id", datasetId) .eq("owner_id", account.id) .maybeSingle(); serverId = record.data?.server_id ?? serverId; await db.storage .from("minegeo-raw") .remove( manifest.assets.map((a: any) => `${account.id}/${datasetId}/${a.path}`), ); const deleted = await db .from("datasets") .delete() .eq("id", datasetId) .eq("owner_id", account.id); if (deleted.error) console.error("Test dataset cleanup: " + deleted.error.message); } if (serverId) { const remaining = await db .from("datasets") .select("id") .eq("server_id", serverId) .limit(1); if (remaining.data?.length === 0) await db .from("catalog_servers") .delete() .eq("id", serverId) .eq("name", "MineGeo API regression"); } server.kill(); await stopped; await writeFile(`${directory}/server.log`, serverLog); }