3.4 KiB
validateAbi — post-Javy module reflection
Purpose
validateAbi is step 5 of the TS->WASM compilation pipeline: it runs WebAssembly.compile(bytes) against Javy's output and reflects the resulting module to assert the WASI-stdio variant's surface contract. The contract has two halves: required exports (memory + _start) and required imports (wasi_snapshot_preview1.{fd_read, fd_write, environ_get, environ_sizes_get, proc_exit}).
Mirroring the host bridge's REQUIRED_WASI_STDIO_IMPORTS list intentionally: the bridge instantiates the module against its own snapshot of those imports, and any future divergence between the lists would cause one half of the system to ship validations the other cannot satisfy. Single-sourcing the list in spec ensures the bridge and compiler stay in lock-step; this module hard-codes its own copy because cycling the import via @suaveplan/api-sandbox-wasm-host-bridge would pull a 30+ file graph into the compiler's static surface.
Features
- One-shot
WebAssembly.compilereturns both the validation verdict AND a reusableModule— the orchestrator threads the sameModuleinto the route-extract step so we never compile twice. - Failure mode
compile_failed(WebAssembly.compilethrew) is separated fromABI_VALIDATION_FAILED(compile succeeded, exports/imports incomplete) viacontext.reason. - Per-missing-item
recordAbiFailureincrements thread through the optionalinstrumentsso dashboards can split the failure rate by which symbol vanished — useful when a Javy upgrade silently dropsclock_time_getor similar. - Missing list is sorted for diagnostic stability.
Usage: Basic
import { validateAbi } from "@suaveplan/wasm-compiler-javy";
import { readFile } from "node:fs/promises";
const bytes = await readFile("/tmp/plugin.wasm");
const { module } = await validateAbi({ wasmBytes: bytes });
Usage: Advanced
import { validateAbi, createWasmCompilerInstruments } from "@suaveplan/wasm-compiler-javy";
const instr = createWasmCompilerInstruments();
try {
const { module } = await validateAbi({ wasmBytes, instruments: instr });
// forward `module` to route-extract
} catch (err) {
// `recordAbiFailure` has already counted the missing exports for the dashboard.
throw err;
}
API Reference
validateAbi(options: ValidateAbiOptions): Promise<ValidateAbiResult>— entrypoint.ValidateAbiOptions: { wasmBytes: Uint8Array; instruments?: WasmCompilerInstruments }.ValidateAbiResult: { module: WebAssembly.Module }.REQUIRED_WASI_IMPORTS/REQUIRED_EXPORTS— frozen string-array registries.
Implementation Notes
WebAssembly.compile is the only piece of the validator that crosses the JS/WASM boundary. The reflection methods WebAssembly.Module.imports(module) and WebAssembly.Module.exports(module) are pure JS — they walk parsed metadata without touching memory or invoking the runtime. The compiled Module is opaque to the validator but the orchestrator hands it to the route-extract step, which instantiates it against a host-built WASI snapshot to fish the routes out. The implementation deliberately does NOT cycle through @suaveplan/api-sandbox-wasm-host-bridge so the compiler's static graph stays compact; the bridge re-validates anyway when its buildWasiStdioInstall runs, so a one-pass divergence cannot leak past the host's installPlugin call.