/** * Self-host the @imgly/background-removal model + wasm assets. * * @imgly/background-removal is AGPL-3.0. By default it streams its ONNX model * and onnxruntime-web wasm binaries from staticimgly.com at runtime. To keep * Plimi's privacy promise (nothing leaves the user's browser, no third-party * fetches), we mirror the *version-matched* asset bundle into `public/imgly/` * and point the library at our own origin via `config.publicPath`. * * The assets are large (~300MB across all model variants) so they are NOT * committed to git — this script is run on `predev` / `prebuild` and is * idempotent: it only downloads chunks that are missing. */ import { mkdir, readFile, writeFile, stat } from "node:fs/promises"; import { fileURLToPath } from "node:url"; import path from "node:path"; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const OUT_DIR = path.join(ROOT, "public", "imgly"); // Keep the data version in lock-step with the installed library version, // otherwise the resources.json format / model keys won't match the runtime. const { version } = JSON.parse( await readFile( path.join(ROOT, "node_modules/@imgly/background-removal/package.json"), "utf8" ) ); const BASE = `https://staticimgly.com/@imgly/background-removal-data/${version}/dist/`; async function exists(p) { try { await stat(p); return true; } catch { return false; } } async function download(url, dest) { const res = await fetch(url); if (!res.ok) { throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`); } const buf = Buffer.from(await res.arrayBuffer()); await writeFile(dest, buf); return buf.length; } async function main() { await mkdir(OUT_DIR, { recursive: true }); console.log(`[imgly] Mirroring background-removal assets v${version}`); const resourcesPath = path.join(OUT_DIR, "resources.json"); await download(new URL("resources.json", BASE).toString(), resourcesPath); const resources = JSON.parse(await readFile(resourcesPath, "utf8")); const chunkNames = new Set(); for (const entry of Object.values(resources)) { for (const chunk of entry.chunks ?? []) chunkNames.add(chunk.name); } let downloaded = 0; let skipped = 0; let bytes = 0; for (const name of chunkNames) { const dest = path.join(OUT_DIR, name); if (await exists(dest)) { skipped++; continue; } bytes += await download(new URL(name, BASE).toString(), dest); downloaded++; if (downloaded % 10 === 0) { console.log(`[imgly] ${downloaded} chunks downloaded...`); } } console.log( `[imgly] Done: ${downloaded} downloaded, ${skipped} cached ` + `(${(bytes / 1024 / 1024).toFixed(1)} MB new) → public/imgly/` ); } main().catch((err) => { console.error("[imgly] Asset mirror failed:", err); process.exit(1); });