From 2d368f5c4ea6aef12287e6d5b709cbd68837d76d Mon Sep 17 00:00:00 2001 From: deadronos Date: Sun, 18 Jan 2026 16:22:40 +0100 Subject: [PATCH] Refactor: Improve WASM module loading and validation logic --- src/lib/wasmLoader.ts | 54 +++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/lib/wasmLoader.ts b/src/lib/wasmLoader.ts index d01aca6..4e16159 100644 --- a/src/lib/wasmLoader.ts +++ b/src/lib/wasmLoader.ts @@ -1,5 +1,6 @@ import type { StoreSnapshot } from '../state/types'; import { buildRustSimBridge, type RustSimBridge, type WasmSimExports } from './wasmSimBridge'; +import type { InitOutput } from '../gen/rust_engine'; import { normalizeSnapshot, validateSnapshotForWasm } from '../state/serialization/store'; import { parityDebugEnabled } from './parityDebug'; @@ -27,25 +28,44 @@ export async function loadWasmBridge( try { // Dynamic import to allow tree-shaking when WASM is not used - const wasmModule = await import('../gen/rust_engine'); - const initOutput = await wasmModule.default(); - const memory = (initOutput as { memory?: WebAssembly.Memory }).memory; - if (!memory) { - throw new Error('WASM init missing memory'); - } + const mod = (await import('../gen/rust_engine')) as unknown; - if ( - parityDebugEnabled && - typeof (wasmModule as { set_parity_debug?: (enabled: boolean) => void }).set_parity_debug === - 'function' - ) { - (wasmModule as { set_parity_debug?: (enabled: boolean) => void }).set_parity_debug?.(true); - } + type RustEngineModule = WasmSimExports & { + default: (...args: unknown[]) => Promise; + set_parity_debug?: (enabled: boolean) => void; + }; - const exports: WasmSimExports = { - memory, - WasmGameState: wasmModule.WasmGameState, - }; + const isRustEngineModule = (m: unknown): m is RustEngineModule => { + if (typeof m !== 'object' || m === null) return false; + const r = m as Record; + return ( + typeof r.default === 'function' && + typeof r.WasmGameState === 'function' && + // `memory` is returned from the init output rather than being a top-level export + true + ); + }; + + if (!isRustEngineModule(mod)) { + throw new Error('Imported rust_engine module has an unexpected shape'); + } + + const wasmModule = mod; + const initOutput = await wasmModule.default(); + const memory = initOutput.memory; + const hasMemoryBuffer = Boolean(memory && (memory as { buffer?: unknown }).buffer); + if (!hasMemoryBuffer && !(memory instanceof WebAssembly.Memory)) { + throw new Error('WASM init missing memory'); + } + + if (parityDebugEnabled && typeof wasmModule.set_parity_debug === 'function') { + wasmModule.set_parity_debug(true); + } + + const exports: WasmSimExports = { + memory, + WasmGameState: wasmModule.WasmGameState, + }; // Pre-validate the original snapshot and provide friendly messages // if it looks incomplete. We still normalize and proceed because