// License-firewall CI guard. // // Every vendored asset under public/illustrations/ (and public/lottie/) MUST have a // row in public/illustrations/assets.json. No row -> the asset may not ship. Fails // the build (exit 1) on any un-ledgered file. Run: npm run check:assets import { readFileSync, readdirSync, statSync, existsSync } from "node:fs"; import { join, dirname, relative } from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const PUBLIC = join(__dirname, "..", "public"); const ILLUS = join(PUBLIC, "illustrations"); const ledgerPath = join(ILLUS, "assets.json"); if (!existsSync(ledgerPath)) { console.error(`MISSING license ledger: ${ledgerPath}`); process.exit(1); } const ledger = JSON.parse(readFileSync(ledgerPath, "utf8")); function walk(dir) { if (!existsSync(dir)) return []; let out = []; for (const e of readdirSync(dir)) { const p = join(dir, e); if (statSync(p).isDirectory()) out = out.concat(walk(p)); else if (/\.(svg|json)$/i.test(e) && e !== "assets.json") out.push(p); } return out; } // Asset files live under illustrations// and lottie/. const files = [...walk(ILLUS), ...walk(join(PUBLIC, "lottie"))] .map((p) => relative(ILLUS, p).split("\\").join("/")); const missing = files.filter((f) => !ledger[f]); if (missing.length) { console.error(`Un-ledgered assets (add a row to assets.json):\n ${missing.join("\n ")}`); process.exit(1); } console.log(`assets.json OK — ${files.length} vendored asset(s), all ledgered.`);