feat: add environment-aware WASM loading for Chrome/Firefox

This commit is contained in:
adlee-was-taken
2026-04-12 13:14:46 -04:00
parent b71ebcc418
commit 2524270524

View File

@@ -1,4 +1,7 @@
/// Service worker entry point for the idfoto Chrome extension.
/// Background script entry point for the idfoto browser extension.
///
/// In Chrome this runs as a service worker (MV3). In Firefox this runs
/// as a persistent background script. WASM loading adapts automatically.
///
/// Loads the WASM module, manages vault state (master key, manifest, git host),
/// and routes all messages from the popup and content scripts.
@@ -22,14 +25,14 @@ const totpSecretCache: Map<string, string> = new Map();
// --- WASM initialization ---
// Chrome MV3 service workers do NOT support dynamic import().
// Instead we load the WASM binary via fetch() and use the synchronous
// initSync() function exported by wasm-pack's --target web output.
// The JS glue is imported statically so webpack bundles it into
// the service worker script.
// Chrome MV3 uses service workers which do NOT support dynamic import().
// Firefox MV3 uses background scripts which DO support dynamic import().
// We detect the environment at runtime and use the appropriate loading strategy.
// @ts-ignore TS2307 — resolved by webpack alias / copy
import initSync, * as wasmBindings from '../../wasm/idfoto_wasm.js';
import initDefault, { initSync } from '../../wasm/idfoto_wasm.js';
// @ts-ignore TS2307
import * as wasmBindings from '../../wasm/idfoto_wasm.js';
type WasmModule = typeof wasmBindings;
let wasm: WasmModule | null = null;
@@ -37,10 +40,21 @@ let wasm: WasmModule | null = null;
async function initWasm(): Promise<WasmModule> {
if (wasm) return wasm;
// Fetch the .wasm binary and instantiate synchronously
const wasmResponse = await fetch(chrome.runtime.getURL('idfoto_wasm_bg.wasm'));
const wasmBytes = await wasmResponse.arrayBuffer();
initSync({ module: new WebAssembly.Module(wasmBytes) });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const SWGlobalScope = (globalThis as any).ServiceWorkerGlobalScope as (new () => ServiceWorker) | undefined;
const isServiceWorker = typeof SWGlobalScope !== 'undefined'
&& self instanceof (SWGlobalScope as unknown as typeof EventTarget);
if (isServiceWorker) {
// Chrome: fetch WASM binary and instantiate synchronously
const wasmResponse = await fetch(chrome.runtime.getURL('idfoto_wasm_bg.wasm'));
const wasmBytes = await wasmResponse.arrayBuffer();
initSync({ module: new WebAssembly.Module(wasmBytes) });
} else {
// Firefox: background script — async init works
const wasmUrl = chrome.runtime.getURL('idfoto_wasm_bg.wasm');
await initDefault(wasmUrl);
}
vault.setWasm(wasmBindings);
wasm = wasmBindings;