2.9 KiB
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)— thebun:sqliteimport 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 inIMessageDbOpenFailedErrorcarrying the offending path oncontext.path, so the watcher can surface a stable error code to consumers. - Returns a
SqliteHandlewhoseexecScriptmember maps toDatabase.run(Bun's bulk-SQL entry point) and whosepreparemember returns aSqliteStatementwrapping Bun's per-statementall/get/runmethods 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 withreadonly: falseto populate the fixture.
Usage: Basic
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
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 acreateRequire-based one that resolvesbun:sqliteagainst 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.