# `bunSqliteReader` _(no submodules)_ ## Purpose Production-grade `SqliteReader` backed by Bun's built-in `bun:sqlite` driver. The reader is the single seam through which `IMessageWatcher` reaches Apple's `chat.db` SQLite database; replacing upstream's `require("bun:sqlite") as any` cast with a typed, swappable factory lets tests inject a reader pointing at a real temp chat.db without re-implementing the SQL layer. ## Features - Lazy module resolution via `createRequire(import.meta.url)` — the `bun:sqlite` import is not added to the static graph, so vite and vitest do not attempt to resolve it on non-Bun runners during build / type-check / lint passes. - Errors thrown from the load step or the `new Database(...)` call are wrapped in `IMessageDbOpenFailedError` carrying the offending path on `context.path`, so the watcher can surface a stable error code to consumers. - Returns a `SqliteHandle` whose `execScript` member maps to `Database.run` (Bun's bulk-SQL entry point) and whose `prepare` member returns a `SqliteStatement` wrapping Bun's per-statement `all` / `get` / `run` methods structurally — production and test code share the exact same call shape. - Read-only by default: `open(path, { readonly: true })` opens the database read-only as required for `~/Library/Messages/chat.db`, while tests open with `readonly: false` to populate the fixture. ## Usage: Basic ```ts import { bunSqliteReader } from "@suaveplan/imessage-adapter"; const handle = bunSqliteReader.open("/path/to/chat.db", { readonly: true }); const rows = handle.prepare("SELECT ROWID FROM message LIMIT 1").all(); handle.close(); ``` ## Usage: Advanced ```ts import { createBunSqliteReader } from "@suaveplan/imessage-adapter"; // Inject a custom loader (e.g. for vitest under WSL2 where bun:sqlite is // reached through a different worker bridge). const reader = createBunSqliteReader(() => require("bun:sqlite")); const handle = reader.open(path, { readonly: false }); handle.execScript("CREATE TABLE foo (id INTEGER PRIMARY KEY)"); ``` ## API Reference - `bunSqliteReader: SqliteReader` — default reader, ready for production wiring. - `createBunSqliteReader(loader?: BunSqliteLoader): SqliteReader` — factory accepting a custom loader; defaults to a `createRequire`-based one that resolves `bun:sqlite` against the module's own URL. - `BunSqliteLoader = () => BunSqliteModule` — the loader contract. ## Implementation Notes `createRequire(import.meta.url)` is the documented Node + Bun bridge for resolving CommonJS / built-in modules from ESM without statically declaring them. We use it because static `import "bun:sqlite"` would make vite resolve the specifier at build time and fail on non-Bun hosts (CI, lint). The `BunDatabase` interface is intentionally minimal — it only declares the methods the watcher actually calls, so changes to Bun's broader Database surface cannot bleed into the package.