# wasm-driver ## Purpose Provides `createWasmDriver`, the browser-side SQLite driver for `@suaveplan/db-sqlite`. It spawns a Web Worker running `wasm-worker.ts`, which loads `@sqlite.org/sqlite-wasm` and manages a SQLite database instance. Communication between the caller and the worker uses a message-passing protocol with sequential IDs mapped to `Promise` resolve/reject pairs, giving a fully async interface without blocking the main thread. OPFS (Origin Private File System) persistence is attempted automatically when a non-`:memory:` filename is supplied and the worker context supports `sqlite3.oo1.OpfsDb`. When OPFS headers (`Cross-Origin-Opener-Policy: same-origin`, `Cross-Origin-Embedder-Policy: require-corp`) are absent, the worker falls back to in-memory storage with a console warning. ## Features - `createWasmDriver(options?, workerFactory?)` — spawns worker, awaits ready handshake, returns `{ db, close }` - Injectable `workerFactory` parameter for test isolation — avoids real Worker spawning in Vitest - `WasmProxyDb` — `{ query(sql, params?), execute(sql, params?) }` interface returned by the driver - `close()` is idempotent and drains all pending requests with rejection before terminating the worker - Worker init failure terminates the worker and throws `SqliteError(SQLITE.DRIVER_INIT_FAILED)` - Worker runtime errors reject all pending promises with `SqliteError(SQLITE.DRIVER_INIT_FAILED)` ## Usage: Basic Example ```ts import { createWasmDriver } from "@suaveplan/db-sqlite/drivers/wasm-driver"; const { db, close } = await createWasmDriver(); await db.execute("CREATE TABLE kv (key TEXT PRIMARY KEY, value TEXT)", []); await db.execute("INSERT INTO kv VALUES (?, ?)", ["hello", "world"]); const rows = await db.query("SELECT * FROM kv WHERE key = ?", ["hello"]); await close(); ``` ## Usage: Advanced Example ```ts import { createWasmDriver } from "@suaveplan/db-sqlite/drivers/wasm-driver"; // With OPFS persistence (requires COOP/COEP headers on the page) const { db, close } = await createWasmDriver({ filename: "app.db" }); try { await db.execute("BEGIN IMMEDIATE", []); await db.execute("INSERT INTO users VALUES (?, ?)", [1, "Alice"]); await db.execute("COMMIT", []); } catch (err) { await db.execute("ROLLBACK", []); throw err; } finally { await close(); } ``` ## API Reference ### `createWasmDriver(options?, workerFactory?): Promise>` Spawns the WASM worker and awaits the `ready` handshake before resolving. **Parameters** | Name | Type | Default | Description | |------|------|---------|-------------| | `options.filename` | `string` | `undefined` (→ `:memory:`) | OPFS file path or omit for in-memory | | `workerFactory` | `() => Worker` | `defaultWorkerFactory` | Injectable for testing | **Throws** `SqliteError(SQLITE.DRIVER_INIT_FAILED)` if the worker fails to initialise. ### `WasmProxyDb` ```ts interface WasmProxyDb { query(sql: string, params?: unknown[]): Promise; execute(sql: string, params?: unknown[]): Promise<{ rowsAffected: number }>; } ``` ### `WasmDriverResult` ```ts interface WasmDriverResult { db: WasmProxyDb; close: () => Promise; } ``` ## Implementation Notes The worker URL is constructed with `new URL("./wasm-worker.js", import.meta.url)` so bundlers (Vite, webpack) can resolve it as a worker entry point and emit the correct asset path. The `.js` extension (not `.ts`) is used because the compiled output is what the browser loads at runtime. The pending-promise map (`Map`) ensures that each in-flight request receives exactly one response, and that a stale response for a cancelled request is silently ignored. On `close()`, all pending promises are rejected before worker termination to prevent callers from hanging indefinitely. OPFS support requires `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` response headers. The worker automatically falls back to in-memory storage without these headers rather than crashing, since detecting header presence from inside a Worker is unreliable.