{"_id":"@alt-javascript/jsdbc-sqljs-localstorage","_rev":"2-8a14a47ed083fc3e1c017d4800bb1294","name":"@alt-javascript/jsdbc-sqljs-localstorage","dist-tags":{"latest":"1.2.0"},"versions":{"1.1.1":{"name":"@alt-javascript/jsdbc-sqljs-localstorage","version":"1.1.1","keywords":["jsdbc","jdbc","database","sqlite","sql.js","wasm","browser","localstorage","persistent","isomorphic","driver"],"author":{"name":"Craig Parravicini"},"license":"MIT","_id":"@alt-javascript/jsdbc-sqljs-localstorage@1.1.1","maintainers":[{"name":"craigparra","email":"craigparra@gmail.com"}],"contributors":[{"url":"Anthropic","name":"Claude"}],"homepage":"https://github.com/alt-javascript/jsdbc/tree/main/packages/sqljs-localstorage#readme","bugs":{"url":"https://github.com/alt-javascript/jsdbc/issues"},"dist":{"shasum":"e6d544743c4094554888c6ae324c979e426bba36","tarball":"https://registry.npmjs.org/@alt-javascript/jsdbc-sqljs-localstorage/-/jsdbc-sqljs-localstorage-1.1.1.tgz","fileCount":12,"integrity":"sha512-zIEDVC9V+6Voy/kYkJZV+xJlTde8Fq3Ax2BG7xG9hGiTJJkjp5Mkww62b1dY/D/E5H8G8hjwcMpQy9LLY5rj5Q==","signatures":[{"sig":"MEUCIQC0hh0a3f4u1uXgsnXIYj3LC3RVzfrAJtUNnNFWq1WCmwIgco18ZEeCU2XtsBM9q4+YXFzz1+6txhABgl56IYkrSS0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33849},"main":"index.js","type":"module","gitHead":"0769b436f75d65bb153cdb9cf00186f464416cff","scripts":{"test":"mocha --recursive test/**/*.spec.js"},"_npmUser":{"name":"craigparra","email":"craigparra@gmail.com"},"repository":{"url":"git+https://github.com/alt-javascript/jsdbc.git","type":"git","directory":"packages/sqljs-localstorage"},"_npmVersion":"11.12.0","description":"JSDBC driver for SQLite via sql.js with automatic localStorage persistence (browser)","directories":{},"_nodeVersion":"24.14.0","dependencies":{"sql.js":"^1.11.0","@alt-javascript/jsdbc-core":"*","@alt-javascript/jsdbc-sqljs":"*"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"chai":"^4.3.7","mocha":"^10.2.0"},"_npmOperationalInternal":{"tmp":"tmp/jsdbc-sqljs-localstorage_1.1.1_1774504406414_0.9504657529934701","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@alt-javascript/jsdbc-sqljs-localstorage","version":"1.2.0","description":"JSDBC driver for SQLite via sql.js with automatic localStorage persistence (browser)","keywords":["jsdbc","jdbc","database","sqlite","sql.js","wasm","browser","localstorage","persistent","isomorphic","driver"],"publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"homepage":"https://github.com/alt-javascript/jsdbc/tree/main/packages/sqljs-localstorage#readme","repository":{"type":"git","url":"git+https://github.com/alt-javascript/jsdbc.git","directory":"packages/sqljs-localstorage"},"type":"module","main":"index.js","scripts":{"test":"mocha --recursive test/**/*.spec.js"},"dependencies":{"@alt-javascript/jsdbc-core":"*","@alt-javascript/jsdbc-sqljs":"*","sql.js":"^1.11.0"},"devDependencies":{"chai":"^4.3.7","mocha":"^10.2.0"},"author":{"name":"Craig Parravicini"},"contributors":[{"name":"Claude","url":"Anthropic"}],"license":"MIT","gitHead":"29c62c831f3b9c6007b21904aba69c61281ffd41","_id":"@alt-javascript/jsdbc-sqljs-localstorage@1.2.0","bugs":{"url":"https://github.com/alt-javascript/jsdbc/issues"},"_nodeVersion":"24.14.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-DAA3aF7kxjCXob4RuL+f+aNSm1sVx2pwRwqD/iiwAt4LD4WDa4rbkrMLwAHoCwjnQ/t2cEduYEklBOAANnFCfg==","shasum":"a718f7d5efaa195b1522bd5f791b2b055c8e4f5b","tarball":"https://registry.npmjs.org/@alt-javascript/jsdbc-sqljs-localstorage/-/jsdbc-sqljs-localstorage-1.2.0.tgz","fileCount":12,"unpackedSize":33849,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHXlEukffctKoWWNW3lBhO3puMn97Qzq/dTxpzGV1HO2AiBzkqSiPBvBE05I2a776HWVUc3HNZvLjbs+rBBSVpsIXA=="}]},"_npmUser":{"name":"craigparra","email":"craigparra@gmail.com"},"directories":{},"maintainers":[{"name":"craigparra","email":"craigparra@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jsdbc-sqljs-localstorage_1.2.0_1774900899444_0.4645073429315545"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-26T05:53:26.307Z","modified":"2026-03-30T20:01:39.782Z","1.1.1":"2026-03-26T05:53:26.547Z","1.2.0":"2026-03-30T20:01:39.640Z"},"bugs":{"url":"https://github.com/alt-javascript/jsdbc/issues"},"author":{"name":"Craig Parravicini"},"license":"MIT","homepage":"https://github.com/alt-javascript/jsdbc/tree/main/packages/sqljs-localstorage#readme","keywords":["jsdbc","jdbc","database","sqlite","sql.js","wasm","browser","localstorage","persistent","isomorphic","driver"],"repository":{"type":"git","url":"git+https://github.com/alt-javascript/jsdbc.git","directory":"packages/sqljs-localstorage"},"description":"JSDBC driver for SQLite via sql.js with automatic localStorage persistence (browser)","contributors":[{"name":"Claude","url":"Anthropic"}],"maintainers":[{"name":"craigparra","email":"craigparra@gmail.com"}],"readme":"# @alt-javascript/jsdbc-sqljs-localstorage\n\n[![Language](https://img.shields.io/badge/language-JavaScript-yellow.svg)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)\n[![npm version](https://img.shields.io/npm/v/%40alt-javascript%2Fjsdbc-sqljs-localstorage)](https://www.npmjs.com/package/@alt-javascript/jsdbc-sqljs-localstorage)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![CI](https://github.com/alt-javascript/jsdbc/actions/workflows/node.js.yml/badge.svg)](https://github.com/alt-javascript/jsdbc/actions/workflows/node.js.yml)\n\nJSDBC driver for SQLite via [sql.js](https://github.com/sql-js/sql.js) (WebAssembly) with automatic `localStorage` persistence. Write SQL in the browser — data survives page reloads and cross-session navigation.\n\n**Part of the [@alt-javascript/jsdbc](https://github.com/alt-javascript/jsdbc) monorepo.**\n\n## Install\n\n```bash\nnpm install @alt-javascript/jsdbc-core @alt-javascript/jsdbc-sqljs-localstorage\n```\n\n## Usage\n\n```javascript\nimport { DataSource } from '@alt-javascript/jsdbc-core';\nimport '@alt-javascript/jsdbc-sqljs-localstorage'; // self-registers with DriverManager\n\n// 'myapp-db' is the localStorage key where the database binary is stored.\nconst ds = new DataSource({ url: 'jsdbc:sqljs:localstorage:myapp-db' });\n\n// First visit — empty database, table does not exist yet.\nconst conn = await ds.getConnection();\nconst stmt = await conn.createStatement();\nawait stmt.executeUpdate('CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, text TEXT)');\n\nconst ps = await conn.prepareStatement('INSERT INTO notes (text) VALUES (?)');\nps.setParameter(1, 'Hello, persistent world!');\nawait ps.executeUpdate();\nawait ps.close();\nawait stmt.close();\nawait conn.close();\n\n// ── Later (page reload / new session) ──────────────────────────────────────\n\n// Same URL, same key — database is restored from localStorage.\nconst conn2 = await ds.getConnection();\nconst stmt2 = await conn2.createStatement();\nconst rs = await stmt2.executeQuery('SELECT * FROM notes');\nconsole.log(rs.getRows()); // [{ id: 1, text: 'Hello, persistent world!' }]\nrs.close();\nawait stmt2.close();\nawait conn2.close();\n```\n\n## URL Scheme\n\n```\njsdbc:sqljs:localstorage:<key>\n```\n\n`<key>` is the `localStorage` key under which the serialised database is stored. Use a unique key per logical database in your application.\n\n## How it Works\n\n1. **On connect** — if `localStorage[key]` exists, the database is restored from the stored binary. Otherwise a fresh in-memory database is created.\n2. **On every write** (`executeUpdate`, `executePreparedUpdate`) — the sql.js database is serialised to Base64 via `db.export()` and written to `localStorage` immediately. No explicit save step required.\n3. **On commit** — the final committed state is flushed.\n4. **On rollback** — the pre-transaction `localStorage` snapshot is restored so the on-disk state rolls back along with the in-memory state.\n\n## Transactions\n\nTransactions work identically to the standard JSDBC interface. The snapshot-restore strategy ensures that a rolled-back transaction is invisible to future sessions:\n\n```javascript\nconst conn = await ds.getConnection();\nawait conn.setAutoCommit(false);\n\nconst stmt = await conn.createStatement();\nawait stmt.executeUpdate(\"INSERT INTO notes VALUES (99, 'draft')\");\n\nawait conn.rollback(); // rolls back both in-memory and localStorage state\nawait stmt.close();\nawait conn.close();\n\n// A fresh connection will NOT see row 99.\n```\n\n## Injecting a Custom Storage Backend (Testing)\n\nThe driver accepts a `LocalStorageStore` instance via `properties.store`. Use this to inject a `Map`-backed shim in Node.js tests without a real browser:\n\n```javascript\nimport { DataSource } from '@alt-javascript/jsdbc-core';\nimport { LocalStorageStore } from '@alt-javascript/jsdbc-sqljs-localstorage';\nimport '@alt-javascript/jsdbc-sqljs-localstorage';\n\nclass LocalStorageShim {\n  constructor() { this._map = new Map(); }\n  getItem(k)      { return this._map.has(k) ? this._map.get(k) : null; }\n  setItem(k, v)   { this._map.set(k, v); }\n  removeItem(k)   { this._map.delete(k); }\n}\n\nconst ds = new DataSource({\n  url: 'jsdbc:sqljs:localstorage:test-db',\n  properties: { store: new LocalStorageStore(new LocalStorageShim()) },\n});\n```\n\n## Storage Limits\n\n`localStorage` typically supports **5 MB per origin**. The sql.js database is serialised as Base64, which adds ~33% overhead over the raw binary. For example, a 3 MB database occupies ~4 MB in localStorage.\n\nIf the stored value exceeds the quota, a descriptive error is thrown:\n\n```\nError: localStorage quota exceeded for key \"myapp-db\" (~4800.0 KB).\n       Consider running VACUUM to compact the database.\n```\n\nAfter a quota error the in-memory database remains usable — only the persistence write failed.\n\n**To keep the database compact:** run `VACUUM` periodically to reclaim free pages left by deleted rows and dropped tables.\n\n## Browser Compatibility\n\n| Feature | Requirement |\n|---|---|\n| `localStorage` | All modern browsers |\n| `sql.js` Wasm | Any browser with WebAssembly support |\n| `btoa` / `atob` | All modern browsers |\n\n## When to Use\n\n- **Browser apps** needing persistent, queryable client-side storage\n- **Offline-first apps** where data must survive page reloads without a server\n- **Prototyping** a SQL-backed browser app without setting up a backend\n- **Testing** complex SQL logic that runs identically in Node.js and the browser\n\n## When NOT to Use\n\n- **Large datasets** — if your data exceeds ~3 MB, consider IndexedDB or server-side storage\n- **Multi-tab writes** — `localStorage` does not coordinate concurrent writes across tabs; the last writer wins\n- **Node.js server apps** — use [`@alt-javascript/jsdbc-sqlite`](https://www.npmjs.com/package/@alt-javascript/jsdbc-sqlite) (better-sqlite3) instead\n\n## License\n\nMIT\n","readmeFilename":"README.md"}