Local DB
A small SQLite store on node:sqlite, for the side-tables a deployment keeps next to its application data: sessions, the cluster's own bookkeeping, a job ledger. It is deliberately thin, and it is not encrypted, so application data belongs in b.db instead.
The pragmas that decide durability and SQL trust are fixed rather than configurable: write-ahead logging, foreign keys, secure delete, untrusted schema and cell-size checking are set at open, and a config naming any of them is refused instead of quietly ignored. What remains adjustable is the part that is a tuning decision, the synchronous level and the busy timeout.
The integrity check runs at open, and what happens next is the operator's choice: refuse and keep the file for inspection, or move it aside and start clean while reporting where the old one went.
b.localDb.thin(opts) #
{
file: string, // required; no NUL bytes
schemaSql: string, // required; run at open
recovery: string, // refuse | rename-and-recreate; default "refuse"
pragmas: object, // extra pragmas; the fixed five are refused
limits: object, // node:sqlite SQLITE_LIMIT_* caps
audit: boolean, // false silences the open and recover audit events
}
Open a small SQLite file through node:sqlite with the store's pragmas already applied, run schemaSql, and return the handle plus cached statement helpers. It is the store behind the framework's own side-tables, and it is unencrypted: b.db is what holds application data.
journal_mode=WAL, foreign_keys=ON, secure_delete=ON, trusted_schema=OFF and cell_size_check=ON are fixed. Naming one of them in pragmas raises localdb-thin/pragma-not-overridable rather than being ignored, so a config that believes it changed them fails at open. synchronous=NORMAL and busy_timeout=5000 are defaults that pragmas may replace.
The integrity check runs at open. recovery: "refuse", the default, raises on a corrupt file and leaves it in place; "rename-and-recreate" moves it aside and starts a new one, reporting the move as recovered and recoveredTo, so a caller can tell the data is gone rather than assume an empty database was always empty.
The returned object carries db (the raw DatabaseSync), prepare, run, query, close and file. run and query take their bind values as further arguments rather than as an array. Prepared statements are cached, up to 256.
The configuration refusals name what is wrong: localdb-thin/bad-opts for opts that are not an object, localdb-thin/bad-file for a missing path or one carrying a NUL byte, localdb-thin/bad-schema-sql for a missing schema, localdb-thin/bad-recovery for a recovery outside the two above, localdb-thin/bad-pragmas and localdb-thin/bad-limits for a non-object, and localdb-thin/bad-pragma-name or localdb-thin/bad-pragma-value for a pragma this store will not send. Naming one of the five fixed pragmas raises localdb-thin/pragma-not-overridable.
Opening raises localdb-thin/sqlite-missing when the Node build has no node:sqlite (24.14 or newer is needed), localdb-thin/open-failed when the file cannot be opened, localdb-thin/corrupt when the integrity check reports the file as damaged under the refusing recovery, localdb-thin/integrity-check-failed when the check could not run at all while the file still answers ordinary queries, which is not recovered from under either recovery, and localdb-thin/recovery-failed when the rename-and-recreate recovery cannot move the old file aside. Afterwards, localdb-thin/bad-sql refuses a statement that is not a string and localdb-thin/closed answers any call made after close().
var b = require("@blamejs/core");
var store = b.localDb.thin({
file: "./data/notes.db",
schemaSql: "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)",
});
store.run("INSERT INTO notes (body) VALUES (?)", "first");
store.query("SELECT body FROM notes")[0].body; // → "first"
store.close();