/**
 * WASM Loader with Inline Binary
 *
 * This module handles loading the WASM binary that is embedded as base64.
 * No external file serving or webpack configuration required.
 *
 * The WASM binary is embedded at build time by scripts/inline-wasm.mjs
 */
/** @internal Secret source type enum */
export var SecretSourceType;
(function (SecretSourceType) {
    SecretSourceType[SecretSourceType["Mnemonic"] = 0] = "Mnemonic";
    SecretSourceType[SecretSourceType["WalletSignature"] = 1] = "WalletSignature";
    SecretSourceType[SecretSourceType["Custom"] = 2] = "Custom";
})(SecretSourceType || (SecretSourceType = {}));
/** @internal Unlock method type enum */
export var UnlockMethodType;
(function (UnlockMethodType) {
    UnlockMethodType[UnlockMethodType["None"] = 0] = "None";
    UnlockMethodType[UnlockMethodType["Pin"] = 1] = "Pin";
    UnlockMethodType[UnlockMethodType["Password"] = 2] = "Password";
    UnlockMethodType[UnlockMethodType["Passkey"] = 3] = "Passkey";
    UnlockMethodType[UnlockMethodType["Biometric"] = 4] = "Biometric";
    UnlockMethodType[UnlockMethodType["Custom"] = 5] = "Custom";
})(UnlockMethodType || (UnlockMethodType = {}));
/** @internal Storage type enum */
export var StorageType;
(function (StorageType) {
    StorageType[StorageType["Memory"] = 0] = "Memory";
    StorageType[StorageType["LocalStorage"] = 1] = "LocalStorage";
    StorageType[StorageType["IndexedDb"] = 2] = "IndexedDb";
})(StorageType || (StorageType = {}));
// Module state
let wasmModule = null;
let initPromise = null;
let isInitialized = false;
let refCount = 0;
/**
 * @internal Check if we're in a browser environment
 */
export function isClient() {
    return typeof window !== 'undefined';
}
/**
 * @internal Check if WASM is supported in current environment
 */
export function isWasmSupported() {
    return typeof WebAssembly !== 'undefined' && typeof WebAssembly.instantiate === 'function';
}
/**
 * @internal Load and initialize the WASM module using embedded binary
 *
 * This function:
 * 1. Dynamically imports the wasm-binary module (for code splitting)
 * 2. Decodes the base64 WASM binary
 * 3. Initializes the wasm-bindgen module with the decoded bytes
 *
 * @returns The initialized WASM module
 * @throws Error if called on server or if WASM is not supported
 */
export async function loadWasm() {
    // Check environment
    if (!isClient()) {
        throw new Error('WASM can only be loaded in browser environment. ' +
            'Ensure this code runs on the client side.');
    }
    if (!isWasmSupported()) {
        throw new Error('WebAssembly is not supported in this environment. ' +
            'Please use a modern browser that supports WebAssembly.');
    }
    // Return cached module if already loaded
    if (wasmModule && isInitialized) {
        refCount++;
        return wasmModule;
    }
    if (!initPromise) {
        // Start loading
        initPromise = (async () => {
            try {
                // Dynamically import both modules in parallel
                const [wasmBindingsModule, wasmBinaryModule] = await Promise.all([
                    import('../wasm/privacy_boost_wasm'),
                    import('./wasm-binary'),
                ]);
                // Decode the base64 binary
                const wasmBytes = wasmBinaryModule.decodeWasmBinary();
                // Manual init: replace wasm-bindgen's default()/initSync entirely.
                //
                // Background: under SES/lockdown (MetaMask's lockdown-install.js,
                // Agoric SES) or sandboxed cross-origin iframes, both `initSync`
                // and `__wbg_init` raise:
                //
                //   LinkError: "function import requires a callable" on `__wbg_fetch_<hash>`
                //
                // even though the wasm-bindgen-generated wrapper is a plain function.
                // We've reproduced this with `new WebAssembly.Instance` (sync) and
                // `WebAssembly.instantiate` (async), so it's not specific to either
                // entry point — the wbg property assignments on the imports object
                // don't satisfy V8's import-validation `IsCallable` check after the
                // realm's intrinsics are hardened.
                //
                // Workaround: own the imports object ourselves. `__wbg_get_imports`
                // populates `imports.wbg.<name> = function...` via plain assignment;
                // we walk every property and re-define it via Object.defineProperty
                // as an explicit data descriptor, on a fresh object whose prototype
                // is null. The function values are unchanged, but the descriptor is
                // unambiguous and the prototype chain has no inherited setters or
                // hardened slots that could intercept the lookup.
                //
                // Once linked, we install the instance using __wbg_finalize_init —
                // the same helper wasm-bindgen would have called — so the module's
                // internal `wasm` cache + `__wbindgen_start` run identically to the
                // happy path.
                //
                // Both helpers are added by scripts/patch-wasm-bindgen.sh.
                const glue = wasmBindingsModule;
                if (typeof glue.__wbg_get_imports !== 'function' ||
                    typeof glue.__wbg_finalize_init !== 'function') {
                    throw new Error('wasm-bindgen glue is missing __wbg_get_imports / __wbg_finalize_init. ' +
                        'Rerun `make wasm` so scripts/patch-wasm-bindgen.sh adds the exports.');
                }
                const compiled = await WebAssembly.compile(wasmBytes);
                const rawImports = glue.__wbg_get_imports();
                const hardenedImports = {};
                for (const moduleName of Object.keys(rawImports)) {
                    const submodule = rawImports[moduleName] ?? {};
                    const hardenedSub = Object.create(null);
                    for (const fieldName of Object.keys(submodule)) {
                        Object.defineProperty(hardenedSub, fieldName, {
                            value: submodule[fieldName],
                            writable: true,
                            configurable: true,
                            enumerable: true,
                        });
                    }
                    hardenedImports[moduleName] = hardenedSub;
                }
                const instance = await WebAssembly.instantiate(compiled, hardenedImports);
                glue.__wbg_finalize_init(instance, compiled);
                // Cast to our WasmModule interface
                wasmModule = wasmBindingsModule;
                isInitialized = true;
                return wasmModule;
            }
            catch (error) {
                // Clear state on error to allow retry
                initPromise = null;
                isInitialized = false;
                // Intentionally log to console.error — WASM load failure is fatal and happens
                // before the SDK logger is available.
                console.error('[WASM] Failed to load WASM module:', error); // eslint-disable-line no-console
                throw new WasmLoadError('Failed to load WASM module', error);
            }
        })();
    }
    const module = await initPromise;
    // Every successful caller owns a reference and must eventually release it.
    refCount++;
    return module;
}
/**
 * @internal Get the loaded WASM module (synchronous)
 *
 * @throws Error if module hasn't been loaded yet
 */
export function getWasmModule() {
    if (!wasmModule || !isInitialized) {
        throw new Error('WASM module not loaded. Call loadWasm() first and await its completion.');
    }
    return wasmModule;
}
/**
 * @internal Check if the WASM module is loaded and ready
 */
export function isWasmLoaded() {
    return isInitialized && wasmModule !== null;
}
/**
 * @internal Decrement the WASM reference count.
 * Only resets the module state when no SDK instances remain.
 * Used by PrivacyBoost.dispose() to avoid breaking other instances.
 */
export function releaseWasm() {
    if (refCount <= 0) {
        if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
            console.warn('[WASM] releaseWasm() called with no active references');
        }
        return;
    }
    refCount--;
    if (refCount === 0) {
        wasmModule = null;
        initPromise = null;
        isInitialized = false;
    }
}
/**
 * @internal Force-reset the WASM module state (for testing only).
 * Ignores reference counting.
 */
export function resetWasm() {
    wasmModule = null;
    initPromise = null;
    isInitialized = false;
    refCount = 0;
}
/**
 * @internal Custom error class for WASM loading failures
 */
export class WasmLoadError extends Error {
    cause;
    constructor(message, cause) {
        super(message);
        this.name = 'WasmLoadError';
        this.cause = cause;
        // Maintain proper stack trace
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, WasmLoadError);
        }
    }
}
//# sourceMappingURL=wasm-loader.js.map