rs-loader.ts

2.4 KB · raw

1/**2 * rs-loader.ts — load the Reed-Solomon erasure WASM module.3 *4 * The same code runs in two contexts:5 *  - Extension popup (browser): fetch the WASM via `chrome.runtime.getURL`6 *    so the asset path resolves against the extension package. The WASM7 *    file is shipped from `public/codex/reed_solomon_erasure_bg.wasm`.8 *  - Vitest (Node + jsdom): read the WASM bytes from `node_modules`9 *    synchronously. We avoid the library's `fromCurrentDirectory*` helpers10 *    because they probe `__dirname`, which is unreliable when the test11 *    file is bundled by Vite.12 *13 * The instance is cached — WASM instantiation is non-trivial work and the14 * library is safe to reuse across encode / reconstruct calls.15 */1617import { ReedSolomonErasure } from "@subspace/reed-solomon-erasure.wasm";18import { CodexError } from "../../shared/codex-types";1920const WASM_RELATIVE_PATH = "codex/reed_solomon_erasure_bg.wasm";2122let cached: Promise<ReedSolomonErasure> | null = null;2324export function getReedSolomon(): Promise<ReedSolomonErasure> {25  if (!cached) cached = loadReedSolomon();26  return cached;27}2829async function loadReedSolomon(): Promise<ReedSolomonErasure> {30  try {31    if (isExtensionPopup()) {32      const url = chrome.runtime.getURL(WASM_RELATIVE_PATH);33      const response = await fetch(url);34      if (!response.ok) {35        throw new Error(`fetch ${url} → ${response.status}`);36      }37      const bytes = new Uint8Array(await response.arrayBuffer());38      return ReedSolomonErasure.fromBytes(bytes);39    }4041    // Node / vitest path. Dynamic import so the bundler does not try to42    // resolve `node:fs` for the browser build.43    const fs = await import("node:fs");44    const path = await import("node:path");45    const wasmPath = path.resolve(46      "node_modules/@subspace/reed-solomon-erasure.wasm/dist/reed_solomon_erasure_bg.wasm",47    );48    const bytes = fs.readFileSync(wasmPath);49    return ReedSolomonErasure.fromBytes(bytes);50  } catch (err) {51    throw new CodexError(52      "RS_LIBRARY_FAILED",53      `Failed to load Reed-Solomon WASM module: ${err instanceof Error ? err.message : String(err)}`,54    );55  }56}5758function isExtensionPopup(): boolean {59  return (60    typeof chrome !== "undefined" &&61    typeof chrome.runtime !== "undefined" &&62    typeof chrome.runtime.getURL === "function"63  );64}6566/** Reset the cache. Test-only — never called from production code. */67export function _resetReedSolomonCacheForTest(): void {68  cached = null;69}