/** * db-base — Reusable SQLite infrastructure for context-mode packages. * * Provides lazy-loading of better-sqlite3, WAL pragma setup, prepared * statement caching interface, and DB file cleanup helpers. Both * ContentStore and SessionDB build on top of these primitives. */ import type DatabaseConstructor from "better-sqlite3"; import type { Database as DatabaseInstance } from "better-sqlite3"; /** * Explicit interface for cached prepared statements that accept varying * parameter counts. better-sqlite3's generic `Statement` collapses under * `ReturnType` to a single-param signature, so we define our own. */ export interface PreparedStatement { run(...params: unknown[]): { changes: number; lastInsertRowid: number | bigint; }; get(...params: unknown[]): unknown; all(...params: unknown[]): unknown[]; iterate(...params: unknown[]): IterableIterator; } /** * Wraps a bun:sqlite Database to provide better-sqlite3-compatible API. * Bridges: .pragma(), multi-statement .exec(), .get() null→undefined. */ export declare class BunSQLiteAdapter { #private; constructor(rawDb: any); pragma(source: string): any; exec(sql: string): any; prepare(sql: string): any; transaction(fn: (...args: any[]) => any): any; close(): void; } /** * Wraps node:sqlite's DatabaseSync to provide better-sqlite3-compatible API. * Bridges: .pragma(), .transaction(). Everything else is passthrough. * Eliminates native addon SIGSEGV on Linux (nodejs/node#62515). */ export declare class NodeSQLiteAdapter { #private; constructor(rawDb: any); pragma(source: string): any; exec(sql: string): any; prepare(sql: string): any; transaction(fn: (...args: any[]) => any): any; close(): void; } /** * Lazy-load the SQLite driver for the current runtime. * Bun → bun:sqlite via BunSQLiteAdapter (issue #45). * Linux Node → node:sqlite via NodeSQLiteAdapter (issue #228). * Other Node → better-sqlite3 (native addon). */ export declare function loadDatabase(): typeof DatabaseConstructor; /** * Apply WAL mode and NORMAL synchronous pragma to a database instance. * Should be called immediately after opening a new database connection. * * WAL mode provides: * - Concurrent readers while a write is in progress * - Dramatically faster writes (no full-page sync on each commit) * NORMAL synchronous is safe under WAL and avoids an extra fsync per * transaction. */ export declare function applyWALPragmas(db: DatabaseInstance): void; /** * Remove orphaned WAL/SHM files when the main DB file doesn't exist. * On Windows, stale -wal/-shm files from crashed processes cause * "file is not a database" errors when creating a fresh DB. */ export declare function cleanOrphanedWALFiles(dbPath: string): void; /** * Delete all three SQLite files for a given db path (main, WAL, SHM). * Silently ignores individual deletion errors so a partial cleanup * does not abort the rest. */ export declare function deleteDBFiles(dbPath: string): void; /** * Safely close a database connection. Swallows errors so callers can * always call this in a finally/cleanup path without try/catch. */ export declare function closeDB(db: DatabaseInstance): void; /** * Return the default per-process DB path for context-mode databases. * Uses the OS temp directory and embeds the current PID so multiple * server instances never share a file. */ export declare function defaultDBPath(prefix?: string): string; /** * Retry a DB operation with exponential backoff on SQLITE_BUSY errors. * Catches errors containing "SQLITE_BUSY" or "database is locked" and * retries up to 3 times with delays: 100ms, 500ms, 2000ms. * If all retries fail, throws a descriptive error. * Pass custom delays for testing (e.g., [0, 0, 0] to skip waits). */ export declare function withRetry(fn: () => T, delays?: number[]): T; /** * Detect SQLite corruption errors that warrant a rename-and-recreate. * Matches SQLITE_CORRUPT, SQLITE_NOTADB, and their human-readable equivalents. */ export declare function isSQLiteCorruptionError(msg: string): boolean; /** * Rename a corrupt DB and its WAL/SHM files so a fresh DB can be created. * Best-effort — individual rename failures are silently ignored. */ export declare function renameCorruptDB(dbPath: string): void; export declare abstract class SQLiteBase { #private; constructor(dbPath: string); /** Called once after WAL pragmas are applied. Subclasses run CREATE TABLE/VIRTUAL TABLE here. */ protected abstract initSchema(): void; /** Called once after schema init. Subclasses compile and cache their prepared statements here. */ protected abstract prepareStatements(): void; /** Raw database instance — available to subclasses only. */ protected get db(): DatabaseInstance; /** The path this database was opened from. */ get dbPath(): string; /** Close the database connection without deleting files. */ close(): void; protected withRetry(fn: () => T): T; /** * Close the connection and delete all associated DB files (main, WAL, SHM). * Call on process exit or at end of session lifecycle. */ cleanup(): void; }