// Derive dist-firefox/ from dist/ by swapping in a Firefox-flavored manifest. // // Firefox MV3 differs from Chrome: no service-worker background, no sidePanel // API/permission, native sidebar instead of side_panel, and a required gecko id // + data-collection declaration. Everything else (JS/CSS/HTML) is identical. // // Runs as part of `npm run build`; also imported by scripts/package.mjs. // node scripts/firefox-dist.mjs (standalone, after `vite build`) import { cpSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, resolve } from "node:path"; const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const dist = resolve(root, "dist"); const distFirefox = resolve(root, "dist-firefox"); /** Build dist-firefox/ from dist/. Returns the output dir path. */ export function buildFirefoxDist() { try { statSync(resolve(dist, "manifest.json")); } catch { throw new Error("dist/ not built yet — run `vite build` first."); } const base = JSON.parse(readFileSync(resolve(dist, "manifest.json"), "utf8")); const firefox = { ...base }; firefox.background = { scripts: ["background.js"], type: "module" }; delete firefox.side_panel; // sidePanel is a Chrome-only permission; Firefox warns on the unknown key. firefox.permissions = (base.permissions ?? []).filter( (p) => p !== "sidePanel", ); firefox.icons = { 128: "icon.svg" }; firefox.sidebar_action = { default_panel: "viewer.html?panel=1", default_title: "History Graph", default_icon: "icon.svg", }; firefox.browser_specific_settings = { gecko: { id: "history-graph@chuckdries", // 140 is the floor for data_collection_permissions (below it the key is // ignored); storage.session only needs 115. strict_min_version: "140.0", // Everything stays in local IndexedDB / storage.session — nothing is ever // transmitted, so we declare no data collection. (Required by AMO.) data_collection_permissions: { required: ["none"] }, }, }; rmSync(distFirefox, { recursive: true, force: true }); cpSync(dist, distFirefox, { recursive: true }); writeFileSync( resolve(distFirefox, "manifest.json"), JSON.stringify(firefox, null, 2) + "\n", ); return distFirefox; } // Allow running directly: `node scripts/firefox-dist.mjs`. if (import.meta.url === `file://${process.argv[1]}`) { const out = buildFirefoxDist(); console.log(`Wrote ${out}/manifest.json`); }