Unified SQLite storage layer that works identically across Bun, Node.js, and browser environments. Handles runtime detection, schema migrations, dirty tracking, and hierarchical ID generation.
Runtime Agnostic: Auto-detects Bun, Node.js, or browser and uses the appropriate backend.
import { createStorage, initializeSchema } from '@stoneforge/storage';// Auto-detects runtime (Bun or Node)const storage = createStorage({ path: './data.db' });// Run migrations to set up tablesinitializeSchema(storage);// Query rowsconst tasks = storage.query( 'SELECT * FROM elements WHERE type = ?', ['task']);// Insert a rowconst result = storage.run( 'INSERT INTO elements (id, type, data, created_at, updated_at, created_by) VALUES (?, ?, ?, ?, ?, ?)', ['el-1', 'task', '{}', new Date().toISOString(), new Date().toISOString(), 'system']);console.log(result.changes); // 1
import { createStorageAsync, initializeSchema } from '@stoneforge/storage';// Async factory required for browser (WASM loading)const storage = await createStorageAsync({ path: 'stoneforge.db' });initializeSchema(storage);// Same API as Bun/Node after initializationconst tasks = storage.query( 'SELECT * FROM elements WHERE type = ?', ['task']);
Every backend implements this interface. Methods are synchronous (SQLite is inherently sync); the browser backend wraps async WASM init but exposes the same sync API once initialized.
const stmt = storage.prepare<{ id: string; title: string }>( 'SELECT id, title FROM elements WHERE type = ? AND priority >= ?');const highPriorityTasks = stmt.all('task', 3);const oneTask = stmt.get('task', 2);stmt.finalize(); // Clean up
import { initializeSchema, CURRENT_SCHEMA_VERSION } from '@stoneforge/storage';initializeSchema(storage);console.log(`Schema at version ${CURRENT_SCHEMA_VERSION}`);
import type { Migration } from '@stoneforge/storage';const migration: Migration = { version: 1, name: 'initial-schema', up: (storage) => { storage.exec(` CREATE TABLE elements ( id TEXT PRIMARY KEY, type TEXT NOT NULL, data TEXT NOT NULL ); `); }, down: (storage) => { storage.exec('DROP TABLE elements;'); },};