{"id":32862024,"url":"https://github.com/framersai/sql-storage-adapter","last_synced_at":"2026-04-02T17:20:50.892Z","repository":{"id":322154867,"uuid":"1087804114","full_name":"framersai/sql-storage-adapter","owner":"framersai","description":"Universal SQL storage manager for cross-platform builds.","archived":false,"fork":false,"pushed_at":"2026-03-14T16:58:27.000Z","size":1790,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-26T20:37:35.597Z","etag":null,"topics":["database-management","mobile","sql","sqlite"],"latest_commit_sha":null,"homepage":"https://framersai.github.io/sql-storage-adapter/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/framersai.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-01T17:18:35.000Z","updated_at":"2026-03-14T16:58:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/framersai/sql-storage-adapter","commit_stats":null,"previous_names":["wearetheframers/sql-storage-adapter","framersai/sql-storage-adapter"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/framersai/sql-storage-adapter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framersai%2Fsql-storage-adapter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framersai%2Fsql-storage-adapter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framersai%2Fsql-storage-adapter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framersai%2Fsql-storage-adapter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/framersai","download_url":"https://codeload.github.com/framersai/sql-storage-adapter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/framersai%2Fsql-storage-adapter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31172580,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-29T21:28:10.185Z","status":"online","status_checked_at":"2026-03-30T02:00:06.831Z","response_time":138,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database-management","mobile","sql","sqlite"],"created_at":"2025-11-08T22:01:11.889Z","updated_at":"2026-04-02T17:20:50.879Z","avatar_url":"https://github.com/framersai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- BRANDING-LOGOS --\u003e\n\n# SQL Storage Adapter\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://frame.dev\" target=\"_blank\" rel=\"noopener\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/framersai/sql-storage-adapter/master/logos/frame-square-black-1024x1024-transparent.png\" alt=\"Frame.dev\" width=\"120\"\u003e\n  \u003c/a\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n[![npm version](https://img.shields.io/npm/v/@framers/sql-storage-adapter.svg?logo=npm\u0026label=npm)](https://www.npmjs.com/package/@framers/sql-storage-adapter)\n[![CI](https://github.com/framersai/sql-storage-adapter/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/framersai/sql-storage-adapter/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/framersai/sql-storage-adapter/branch/master/graph/badge.svg)](https://codecov.io/gh/framersai/sql-storage-adapter)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)\n[![License](https://img.shields.io/npm/l/@framers/sql-storage-adapter.svg)](./LICENSE)\n\n\u003e Cross-platform SQL access for Node.js, web, and native runtimes with automatic adapter selection and consistent APIs.\n\nThe SQL Storage Adapter provides a single, ergonomic interface over SQLite (native and WASM), PostgreSQL, Capacitor, IndexedDB, and in-memory stores. It handles adapter discovery, capability detection, and advanced features like cloud backups so you can focus on your application logic.\n\n**🆕 NEW in v0.6.0:** SQL Dialect abstractions for SQLite/Postgres parity + Cross-platform BLOB codec + Full-text search interface!\n\n---\n\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Adapter Matrix](#adapter-matrix)\n- [Electron Adapter](#electron-adapter)\n- [Cross-Platform Sync](#cross-platform-sync)\n- [Configuration \u0026 Resolution](#configuration--resolution)\n- [Platform Strategy](#platform-strategy)\n- [SQL Dialect \u0026 Feature Abstractions](#sql-dialect--feature-abstractions)\n- [CI, Releases, and Badges](#ci-releases-and-badges)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- **Auto-detected adapters** – `createDatabase()` inspects environment signals and picks the best backend (native SQLite, PostgreSQL, Capacitor, sql.js, **IndexedDB**, memory, etc.).\n- **Capability-aware API** – consistent CRUD, transactions, batching, and event hooks across adapters with runtime capability introspection.\n- **🆕 IndexedDB** – sql.js + IndexedDB persistence wrapper for browser-native, offline-first web apps (uses sql.js for SQL execution, IndexedDB for storage).\n- **🆕 Electron Adapter** – Full IPC bridge with main/renderer process split, WAL management, auto-migrations, multi-window support.\n- **🆕 Cross-Platform Sync** – Real-time delta sync with vector clocks, WebSocket/HTTP transports, conflict resolution UI hooks, and device registry.\n- **🆕 Performance Tiers** – Configurable `fast`, `balanced`, `accurate`, `efficient` presets for cost/accuracy tradeoffs. See [Optimization Guide](./guides/OPTIMIZATION_GUIDE.md).\n- **🆕 Lifecycle Hooks** – Extensible hooks (`onBeforeQuery`, `onAfterQuery`, `onBeforeWrite`, `onAfterWrite`) for logging, analytics, caching, and custom extensions.\n- **Cloud backups \u0026 migrations** – built-in backup manager with compression, retention policies, and restore helpers plus migration utilities.\n- **Portable packaging** – optional native dependencies; falls back to pure TypeScript/WASM adapters when native modules are unavailable.\n- **Browser-friendly** – Dynamic imports prevent bundlers from including server-only dependencies (`pg`, `path`) in browser builds.\n- **Mobile/Offline Parity** – Same APIs work across desktop, mobile (Capacitor), and browser with automatic sync support.\n- **🆕 SQL Dialect** – Write cross-platform SQL with `SqlDialect` interface. Automatically translates `INSERT OR IGNORE`, `json_extract`, `ifnull`, `PRAGMA` between SQLite and PostgreSQL.\n- **🆕 Full-Text Search** – `IFullTextSearch` interface abstracts FTS5 (SQLite) and tsvector/GIN (PostgreSQL) with unified `createIndex`, `matchClause`, `rankExpression`, and `rebuildCommand` APIs.\n- **🆕 BLOB Codec** – `IBlobCodec` for cross-platform binary vector storage. `NodeBlobCodec` (Buffer) for server, `BrowserBlobCodec` (DataView) for web.\n- **🆕 Database Export** – `IDatabaseExporter` with `SqliteFileExporter` (VACUUM INTO) and `PostgresExporter` (pg_dump).\n- **CI-first design** – Vitest coverage, Codecov integration, and GitHub Actions workflows for linting, testing, releasing, and npm publish/tag automation.\n\n## Installation\n\n```bash\n# Core package\nnpm install @framers/sql-storage-adapter\n\n# Install only the adapters you plan to use\nnpm install better-sqlite3            # Native SQLite for Node/Electron\nnpm install pg                        # PostgreSQL\nnpm install @capacitor-community/sqlite  # Capacitor / mobile\nnpm install sql.js                    # WASM SQLite (auto-included for IndexedDB)\n# IndexedDB uses sql.js (no extra install needed)\n```\n\n\u003e Windows users: ensure the Visual Studio Build Tools (C++ workload) are installed before adding `better-sqlite3`. On Linux, install `python3`, `build-essential`, and `libssl-dev` prior to `npm install`.\n\n\u003e Note: If `better-sqlite3` cannot be required, install native build tools before `npm install`, ensure your Node version matches available prebuilt binaries, or fall back to `sql.js` or `indexeddb` by setting `STORAGE_ADAPTER=sqljs` or `STORAGE_ADAPTER=indexeddb`.\n\n## Quick Start\n\n```typescript\nimport { createDatabase } from '@framers/sql-storage-adapter';\n\nasync function main() {\n  // Automatically selects the best adapter for the current runtime\n  const db = await createDatabase();\n\n  await db.exec(`\n    CREATE TABLE IF NOT EXISTS todos (\n      id INTEGER PRIMARY KEY,\n      task TEXT NOT NULL,\n      done INTEGER DEFAULT 0\n    )\n  `);\n\n  await db.run('INSERT INTO todos (task) VALUES (?)', ['Ship cross-platform builds']);\n  const items = await db.all\u003c{ id: number; task: string; done: number }\u003e('SELECT * FROM todos');\n  console.log(items);\n\n  await db.close();\n}\n\nmain().catch((error) =\u003e {\n  console.error('Database bootstrap failed', error);\n  process.exit(1);\n});\n```\n\n## Platform-Specific Examples\n\n```typescript\nimport { createDatabase, IndexedDbAdapter } from '@framers/sql-storage-adapter';\n\n// Web (Browser): Uses IndexedDB\nconst webDb = await createDatabase({ priority: ['indexeddb', 'sqljs'] });\n\n// Desktop (Electron): Uses better-sqlite3\nconst desktopDb = await createDatabase({ priority: ['better-sqlite3', 'sqljs'] });\n\n// Mobile (Capacitor): Uses native SQLite\nconst mobileDb = await createDatabase({ priority: ['capacitor', 'indexeddb'] });\n\n// Cloud (Node): Uses PostgreSQL\nconst cloudDb = await createDatabase({ \n  postgres: { connectionString: process.env.DATABASE_URL }\n});\n```\n\nSee [Platform Strategy Guide](./PLATFORM_STRATEGY.md) for detailed pros/cons and architecture.\n\n## Adapter Matrix\n\n| Adapter | Package | Ideal for | Pros | Considerations |\n| --- | --- | --- | --- | --- |\n| **🆕 `electron`** | bundled | **Electron desktop apps** | IPC bridge, multi-window, WAL, auto-migrations, crash recovery | Requires Electron runtime |\n| **🆕 `indexeddb`** | bundled (sql.js) | **Browsers, PWAs** | sql.js + IndexedDB persistence wrapper, browser-native storage, 50MB-1GB+ quota, offline-first | IndexedDB quotas vary, WASM overhead (sql.js), not a separate SQL engine |\n| `better-sqlite3` | `better-sqlite3` | Node/Electron, CLI, CI | Native performance, transactional semantics, WAL support | Needs native toolchain; version must match Node ABI |\n| `postgres` | `pg` | Hosted or on-prem PostgreSQL | Connection pooling, rich SQL features, cloud friendly | Requires `DATABASE_URL`/credentials |\n| `sqljs` | bundled | Browsers, serverless edge, native fallback | Pure WASM SQLite, no native deps, optional filesystem persistence | Write performance limited vs native, in-memory by default |\n| `capacitor` | `@capacitor-community/sqlite` | Mobile (iOS/Android, Capacitor) | Native SQLite on mobile, encryption | Requires Capacitor runtime |\n| `memory` | built-in | Unit tests, storybooks, constrained sandboxes | Zero dependencies, instant startup | Non-durable, single-process only |\n\n### Platform Priorities\n\n| Platform | Primary Adapter | Fallback | Use Case |\n|----------|----------------|----------|----------|\n| **Web (Browser)** | IndexedDB | sql.js | PWAs, offline-first web apps |\n| **Electron (Desktop)** | electron | better-sqlite3 | Desktop apps, dev tools |\n| **Capacitor (Mobile)** | capacitor | IndexedDB | iOS/Android native apps |\n| **Node.js** | better-sqlite3 | Postgres, sql.js | CLI tools, local servers |\n| **Cloud (Serverless)** | Postgres | better-sqlite3 | Multi-tenant SaaS, APIs |\n\n## Electron Adapter\n\nThe Electron adapter provides a complete IPC bridge architecture for Electron apps with main/renderer process split.\n\n```typescript\n// Main process (main.ts)\nimport { createElectronMainAdapter } from '@framers/sql-storage-adapter/electron';\n\nconst db = await createElectronMainAdapter({\n  filePath: path.join(app.getPath('userData'), 'app.db'),\n  wal: { enabled: true, checkpointInterval: 30000 },\n  autoMigration: { enabled: true, migrationsPath: './migrations' },\n  multiWindow: { enabled: true, broadcastChanges: true },\n});\n\nawait db.open();\n```\n\n```typescript\n// Renderer process\nimport { createElectronRendererAdapter } from '@framers/sql-storage-adapter/electron';\n\nconst db = createElectronRendererAdapter();\nawait db.open();\n\nconst users = await db.all('SELECT * FROM users');\n```\n\n**Features:**\n- ✅ Type-safe IPC protocol with request/response correlation\n- ✅ WAL checkpoint management and corruption detection\n- ✅ Auto-migration on app version change\n- ✅ Multi-window database change broadcasting\n- ✅ Preload script with secure `contextBridge` API\n\n## Cross-Platform Sync\n\nReal-time delta synchronization across Electron, Capacitor, browser, and server platforms.\n\n```typescript\nimport { createCrossPlatformSync } from '@framers/sql-storage-adapter/sync';\n\nconst sync = await createCrossPlatformSync({\n  localAdapter: db,\n  endpoint: 'wss://sync.example.com',\n  authToken: 'bearer-token',\n  device: { name: 'MacBook Pro', type: 'electron' },\n  tables: {\n    notes: { priority: 'high', conflictStrategy: 'merge' },\n    settings: { priority: 'critical', conflictStrategy: 'local-wins' },\n  },\n  hooks: {\n    onConflictNeedsResolution: async (conflict) =\u003e {\n      // Show UI for manual conflict resolution\n      return showConflictDialog(conflict);\n    },\n    onSyncComplete: (result) =\u003e {\n      console.log(`Synced: ${result.changesPushed} pushed, ${result.changesPulled} pulled`);\n    },\n  },\n});\n\n// Manual sync\nawait sync.sync();\n\n// Or enable real-time sync\nawait sync.connect();\n```\n\n**Features:**\n- ✅ **Vector Clocks** – Distributed causality tracking for accurate conflict detection\n- ✅ **WebSocket Transport** – Real-time bidirectional sync with auto-reconnection\n- ✅ **HTTP Fallback** – Polling transport for firewalls that block WebSocket\n- ✅ **Conflict Resolution** – Strategies: `last-write-wins`, `local-wins`, `remote-wins`, `merge`, `manual`\n- ✅ **Device Registry** – Track syncing devices with presence status (online/offline/syncing)\n- ✅ **UI Hooks** – Custom conflict resolution dialogs\n\n**Conflict Strategies:**\n\n| Strategy | Description |\n|----------|-------------|\n| `last-write-wins` | Most recent change wins (by timestamp) |\n| `local-wins` | Local changes always take priority |\n| `remote-wins` | Remote changes always take priority |\n| `merge` | Field-level merge with custom mergers |\n| `manual` | Defer to UI hook for user decision |\n\n## Configuration \u0026 Resolution\n\n- `resolveStorageAdapter` inspects:\n  - explicit options (`priority`, `type`, adapter configs),\n  - environment variables (`STORAGE_ADAPTER`, `DATABASE_URL`),\n  - runtime hints (Capacitor detection, browser globals, IndexedDB availability).\n- Adapters are attempted in priority order until one opens successfully; a `StorageResolutionError` includes the full failure chain.\n- Provide `priority: ['indexeddb', 'sqljs']` for browser bundles or tests where native modules shouldn't load.\n- Use `createCloudBackupManager` for S3-compatible backups with gzip compression and retention limits.\n\n### IndexedDB-Specific Config\n\n```typescript\nimport { IndexedDbAdapter } from '@framers/sql-storage-adapter';\n\nconst adapter = new IndexedDbAdapter({\n  dbName: 'my-app-db',       // IndexedDB database name\n  storeName: 'sqliteDb',     // Object store name\n  autoSave: true,            // Auto-save to IndexedDB after writes\n  saveIntervalMs: 5000,      // Batch writes every 5s\n});\n\nawait adapter.open();\n```\n\n**Key Features:**\n- ✅ SQL execution via sql.js (WASM SQLite)\n- ✅ **Automatic persistence** via IndexedDB (stores SQLite database file as blob)\n- ✅ JSON support (SQLite JSON1 extension: json_extract, json_object, json_array, etc.)\n- ✅ Prepared statements for performance and security\n- ✅ Export/import (Uint8Array SQLite file format)\n- ✅ Auto-save with batching (reduce IDB overhead)\n\n**Why IndexedDB Adapter vs sql.js Adapter?**\n\n| Feature | IndexedDB Adapter | sql.js Adapter |\n|---------|------------------|----------------|\n| **SQL Engine** | sql.js (WASM) | sql.js (WASM) |\n| **Persistence** | ✅ **Automatic** (saves to IndexedDB after writes) | ⚠️ **Manual** (you must call `db.export()` and save yourself) |\n| **Data survives refresh** | ✅ Yes | ❌ No (unless you manually saved) |\n| **Use Case** | Production PWAs, offline-first apps | Edge functions, temporary data, prototyping |\n\n**Is IndexedDB Adapter Necessary?**\n\n**✅ YES, if you need:**\n- Data to survive page refreshes (production apps)\n- Offline-first functionality (PWAs)\n- Privacy-first apps (data never leaves browser)\n- Zero manual save logic (just works)\n\n**❌ NO, if you:**\n- Only need temporary/in-memory data (edge functions, Cloudflare Workers)\n- Are prototyping and don't care about persistence\n- Want to manually control when data is saved\n- Don't need data to survive refreshes\n\n**The Value:** IndexedDB adapter provides **automatic persistence** that sql.js doesn't have. With sql.js alone, your data is lost on page refresh unless you manually export and save it. IndexedDB adapter does this automatically, making it production-ready for persistent client-side storage.\n\n**Alternative:** You could use sql.js directly and manually save to IndexedDB yourself, but you'd lose:\n- Automatic batched saves (performance)\n- Reliable persistence (easy to forget manual saves)\n- Consistent API across platforms\n- Production-ready defaults\n\n**Bottom line:** IndexedDB adapter is **necessary for production web apps** that need persistence. For prototypes or edge functions, sql.js alone is fine.\n\n**Note:** IndexedDB adapter is a wrapper around sql.js that adds IndexedDB persistence. It's not a separate SQL engine—it uses sql.js for all SQL operations and IndexedDB only for storing the database file. Since sql.js is full SQLite WASM, it supports all SQLite features including JSON functions, BLOBs, and full-text search.\n\n## Platform Strategy\n\nSee [**PLATFORM_STRATEGY.md**](./PLATFORM_STRATEGY.md) for a comprehensive guide on:\n- Graceful degradation patterns\n- Platform-specific pros/cons\n- Performance benchmarks\n- Offline-first architectures\n- Browser-friendly bundling (dynamic imports prevent server-only dependencies from being bundled)\n\n**TL;DR:** Use IndexedDB for web, better-sqlite3 for desktop, capacitor for mobile, Postgres for cloud.\n\n## Performance Tiers \u0026 Cost Optimization\n\nThe adapter supports configurable performance tiers for different use cases:\n\n```typescript\nimport { createDatabase } from '@framers/sql-storage-adapter';\n\n// Development: Fast tier - prioritize speed\nconst devDb = await createDatabase({\n  type: 'memory',\n  performance: { tier: 'fast' }\n});\n\n// Production: Balanced tier (default)\nconst prodDb = await createDatabase({\n  priority: ['indexeddb', 'sqljs'],\n  performance: { tier: 'balanced' }\n});\n\n// Analytics/Reporting: Accurate tier - no caching, full validation\nconst analyticsDb = await createDatabase({\n  postgres: { connectionString: process.env.DATABASE_URL },\n  performance: { tier: 'accurate', trackMetrics: true }\n});\n\n// Mobile: Efficient tier - battery optimization\nconst mobileDb = await createDatabase({\n  priority: ['capacitor', 'indexeddb'],\n  performance: { tier: 'efficient', batchWrites: true }\n});\n```\n\n| Tier | Caching | Batching | Validation | Use Case |\n|------|---------|----------|------------|----------|\n| `fast` | Aggressive | Yes | Minimal | Development, testing |\n| `balanced` | Moderate | No | Standard | General production |\n| `accurate` | Disabled | No | Full | Analytics, reporting |\n| `efficient` | Moderate | Yes | Minimal | Mobile, IoT |\n\nSee [**guides/OPTIMIZATION_GUIDE.md**](./guides/OPTIMIZATION_GUIDE.md) for detailed configuration options.\n\n## Lifecycle Hooks\n\nThe adapter provides lifecycle hooks for extending behavior:\n\n```typescript\nimport { createDatabase, type StorageHooks } from '@framers/sql-storage-adapter';\n\nconst myHooks: StorageHooks = {\n  // Log all writes\n  onBeforeWrite: async (context) =\u003e {\n    console.log(`Write operation: ${context.statement}`);\n    return context;\n  },\n  \n  // Track metrics after writes\n  onAfterWrite: async (context, result) =\u003e {\n    if (result.changes \u003e 0) {\n      console.log(`Modified ${result.changes} rows`);\n    }\n  },\n  \n  // Log slow queries for optimization\n  onAfterQuery: async (context, result) =\u003e {\n    const duration = Date.now() - context.startTime;\n    if (duration \u003e 100) {\n      console.warn(`Slow query (${duration}ms):`, context.statement);\n    }\n    return result;\n  }\n};\n\nconst db = await createDatabase({\n  performance: { tier: 'balanced' },\n  hooks: myHooks\n});\n```\n\n### Available Hooks\n\n| Hook | Trigger | Use Cases |\n|------|---------|-----------|\n| `onBeforeQuery` | Before SELECT/exec | Query transformation, caching, logging |\n| `onAfterQuery` | After successful query | Result transformation, metrics |\n| `onBeforeWrite` | Before INSERT/UPDATE/DELETE | Validation, auditing, transformation |\n| `onAfterWrite` | After successful write | Cache invalidation, sync triggers |\n| `onError` | On any error | Error transformation, alerting |\n\nSee [**guides/OPTIMIZATION_GUIDE.md**](./guides/OPTIMIZATION_GUIDE.md) for complete configuration options.\n\n## SQL Dialect \u0026 Feature Abstractions\n\nWrite cross-platform SQL that works on both SQLite and PostgreSQL without changing your application code.\n\n### StorageFeatures Factory\n\n```typescript\nimport { resolveStorageAdapter, createStorageFeatures } from '@framers/sql-storage-adapter';\n\nconst adapter = await resolveStorageAdapter({ filePath: './app.db' });\nconst features = createStorageFeatures(adapter);\n// features.dialect  → SqliteDialect or PostgresDialect\n// features.fts      → SqliteFts5 or PostgresFts\n// features.blobCodec → NodeBlobCodec or BrowserBlobCodec\n// features.exporter → SqliteFileExporter or PostgresExporter\n```\n\n### SqlDialect — Cross-Platform SQL\n\n```typescript\nconst { dialect } = features;\n\n// INSERT OR IGNORE (SQLite) → ON CONFLICT DO NOTHING (Postgres)\nconst sql = dialect.insertOrIgnore('users', ['id', 'name'], ['?', '?']);\n\n// INSERT OR REPLACE (SQLite) → ON CONFLICT DO UPDATE (Postgres)\nconst upsert = dialect.insertOrReplace('users', ['id', 'name'], ['?', '?'], 'id');\n\n// json_extract(col, '$.key') (SQLite) → (col::jsonb)-\u003e\u003e'key' (Postgres)\nconst expr = dialect.jsonExtract('metadata', '$.theme');\n\n// ifnull(expr, fallback) (SQLite) → COALESCE(expr, fallback) (Postgres)\nconst safe = dialect.ifnull(dialect.jsonExtract('config', '$.lang'), \"'en'\");\n\n// PRAGMA (SQLite) → null/no-op (Postgres)\nconst pragma = dialect.pragma('journal_mode', 'WAL');\nif (pragma) await adapter.exec(pragma);\n```\n\n### IFullTextSearch — FTS5 \u0026 tsvector\n\n```typescript\nconst { fts } = features;\n\n// Create index: FTS5 virtual table (SQLite) or tsvector + GIN (Postgres)\nawait adapter.exec(fts.createIndex({\n  table: 'docs_fts',\n  columns: ['title', 'body'],\n  contentTable: 'documents',\n  tokenizer: 'porter ascii',\n}));\n\n// Search query\nconst sql = `\n  SELECT t.*\n  FROM ${fts.joinClause('documents', 't', 'fts', 'docs_fts')}\n  WHERE ${fts.matchClause('docs_fts', '?')}\n  ORDER BY ${fts.rankExpression('fts')}\n`;\n\n// Rebuild index\nawait adapter.exec(fts.rebuildCommand('docs_fts'));\n```\n\n### IBlobCodec — Cross-Platform Binary Encoding\n\n```typescript\nconst { blobCodec } = features;\n\n// Encode a float vector for storage\nconst blob = blobCodec.encode([0.1, 0.2, -0.5, 1.0]);\nawait adapter.run('INSERT INTO embeddings (vec) VALUES (?)', [blob]);\n\n// Decode a stored vector\nconst row = await adapter.get\u003c{ vec: Uint8Array }\u003e('SELECT vec FROM embeddings WHERE id = ?', [id]);\nconst vector = blobCodec.decode(row!.vec);\n\n// Cross-platform SHA-256\nconst hash = await blobCodec.sha256('content to hash');\n```\n\n### IDatabaseExporter — Portable Backups\n\n```typescript\nconst { exporter } = features;\n\n// Export to file (VACUUM INTO on SQLite, pg_dump on Postgres)\nawait exporter.exportToFile('/backups/snapshot.db');\n\n// Export to bytes (for browser download or cloud upload)\nconst bytes = await exporter.exportToBytes();\n```\n\nOn Postgres, `features.exporter` requires a Node runtime plus an adapter that was created with a connection string in `adapter.options.connectionString`, since `pg_dump` runs out-of-process.\n\n## CI, Releases, and Badges\n\n- GitHub Actions workflows:\n  - `ci.yml` runs lint, tests, and coverage on every branch.\n  - `release.yml` publishes new versions to npm, tags the commit (`vX.Y.Z`), and creates/updates the GitHub Release when `CHANGELOG.md` and `package.json` bump the version.\n- Check badge health whenever builds fail:\n  - CI badge should be green for `master`.\n  - Codecov badge updates after coverage reports upload.\n  - npm badge reflects the latest published version.\n- Manual verification commands:\n  ```bash\n  npm info @framers/sql-storage-adapter version\n  pnpm --filter sql-storage-adapter test\n  pnpm --filter sql-storage-adapter build\n  ```\n- See [RELEASING.md](./RELEASING.md) for the automated release flow, required secrets (`NPM_TOKEN`), and manual fallback steps.\n\n \n\n## Contributing\n\n- Read [CONTRIBUTING.md](./CONTRIBUTING.md) for coding standards, lint/test commands, and pull request guidelines.\n- Architecture notes live in [ARCHITECTURE.md](./ARCHITECTURE.md); API docs can be regenerated with `pnpm --filter sql-storage-adapter run docs`.\n\n## License\n\n[MIT](./LICENSE)\n\n---\n\n\u003cp align=\"center\"\u003e\n  Built and maintained by \u003ca href=\"https://frame.dev\" target=\"_blank\" rel=\"noopener\"\u003e\u003cstrong\u003eFrame.dev\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Links\n- Website: https://frame.dev\n- AgentOS: https://agentos.sh\n- Marketplace: https://vca.chat\n- GitHub: https://github.com/framersai/sql-storage-adapter\n- npm: https://www.npmjs.com/package/@framers/sql-storage-adapter\n## Contributing \u0026 Security\n- Contributing: ./\\.github/CONTRIBUTING.md\n- Code of Conduct: ./\\.github/CODE_OF_CONDUCT.md\n- Security Policy: ./\\.github/SECURITY.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframersai%2Fsql-storage-adapter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fframersai%2Fsql-storage-adapter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fframersai%2Fsql-storage-adapter/lists"}