import { readFile, writeFile, readdir, copyFile, stat } from "fs/promises"; const PAGES_BASE = "https://rp.jarviscli.dev"; const REPO_BASE = "https://github.com/everestmcarthur/revenge-plugins"; const meta = JSON.parse(await readFile("./site/meta.json", "utf8")); const plugins = []; // The overlay holds the fast-changing bits (status, "broken" flag/reason, tags) meant to be flipped // from the admin plugin without a git push - meta.json above stays the source of truth for real // content. A fetch failure here (API down, first-ever build before it exists) must never break the // public build, so this always falls back to an empty overlay. let overlay = {}; try { const res = await fetch(`${PAGES_BASE}/api/overlay`); if (res.ok) overlay = await res.json(); } catch { console.warn("Couldn't reach the overlay API - building with meta.json alone."); } for (const id of await readdir("./dist")) { const dir = `./dist/${id}`; if (!(await stat(dir)).isDirectory()) continue; let manifest; try { manifest = JSON.parse(await readFile(`${dir}/install/manifest.json`, "utf8")); } catch { continue; // not a plugin output directory } const info = meta[id] ?? {}; const over = overlay[id] ?? {}; plugins.push({ id, name: manifest.name, description: manifest.description, authors: (manifest.authors ?? []).map((a) => a.name), category: info.category ?? "Other", status: over.status ?? info.status ?? "new", broken: over.broken ?? null, tags: over.tags ?? [], accent: info.accent ?? "#5865f2", tagline: info.tagline ?? manifest.description, note: info.note ?? "", howItWorks: info.howItWorks ?? "", features: info.features ?? [], commands: info.commands ?? [], limitations: info.limitations ?? "", pageUrl: `${PAGES_BASE}/${id}/`, installUrl: `${PAGES_BASE}/${id}/install/`, sourceUrl: `${REPO_BASE}/tree/main/plugins/${id}`, issueUrl: `${REPO_BASE}/issues/new?title=${encodeURIComponent(`[${manifest.name}] `)}` }); } plugins.sort((a, b) => a.category.localeCompare(b.category) || a.name.localeCompare(b.name)); await writeFile("./dist/plugins-data.json", JSON.stringify(plugins, null, 2)); await copyFile("./site/index.html", "./dist/index.html"); await copyFile("./site/index.html", "./dist/404.html"); await copyFile("./site/CNAME", "./dist/CNAME"); // Each plugin gets its own real, bookmarkable page at // (not just a hash route) - it's the // same SPA shell, which reads location.pathname on boot to know which plugin to show directly. for (const p of plugins) { await copyFile("./site/index.html", `./dist/${p.id}/index.html`); } console.log(`Generated site data for ${plugins.length} plugin(s).`);