Jason Tudisco 6ebe02ad56 Initial commit: local-first browser sync library experiment
Four variants of the same sync library (IndexedDB, NeDB, SQLite WASM, sql.js)
plus a paste-bin demo app for testing multi-browser sync via shared folders.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 22:04:08 -06:00
..

Paste -- Demo App

A minimal paste-bin app used to test and compare all four IndexSyncFile storage variants. Each version compiles to a single self-contained HTML file.

What it does

  1. You type or paste text into a text area
  2. It saves automatically to a local database
  3. You pick a sync folder on disk
  4. Open the same HTML file in another browser window, point it at the same folder
  5. Both windows stay in sync (auto-sync every 3 seconds)

That's it. No server, no accounts, no network. Just two browser windows and a folder.

Four versions

File Storage engine Opens from file://? Size
paste-indexeddb.html IndexedDB (browser built-in) Yes ~23 KB
paste-nedb.html NeDB (in-memory, MongoDB-style) Yes ~115 KB
paste-sql-js.html sql.js (SQLite via asm.js) Yes ~1.9 MB
paste-sqlite.html SQLite WASM (official build) No (needs HTTP) ~1.4 MB

paste-indexeddb.html

Uses the browser's built-in IndexedDB. Smallest file, fastest startup, zero dependencies. The best choice for most use cases.

paste-nedb.html

Uses NeDB (@seald-io/nedb) running in-memory. Persists NDJSON snapshots to /data/ in the selected folder for fast reload. Useful if you need MongoDB-style query operators ($gt, $in, $regex).

paste-sql-js.html

Uses sql.js, which is SQLite compiled to pure JavaScript (asm.js, not WebAssembly). The full SQLite database is exported as a binary file to /data/store.sqlite in the selected folder. You can open that file with any SQLite tool. Larger bundle but works from file:// with no special setup.

paste-sqlite.html

Uses the official @sqlite.org/sqlite-wasm package. Requires an HTTP server because the browser must fetch() the .wasm binary at runtime. May also need COOP/COEP headers for OPFS persistence. Run bun run serve.ts to test this variant.

How to test

Quick (three variants)

Double-click or drag any of these into Chrome:

dist/paste-indexeddb.html
dist/paste-nedb.html
dist/paste-sql-js.html

They work directly from file://.

SQLite WASM variant (needs HTTP)

bun run serve.ts

Then open http://localhost:4040/paste-sqlite.html.

Multi-browser sync test

  1. Open paste-indexeddb.html in Chrome
  2. Click "Select sync folder" and pick an empty folder
  3. Type something
  4. Open the same paste-indexeddb.html in a second Chrome window
  5. Click "Select sync folder" and pick the same folder
  6. Wait a few seconds -- the text should appear in the second window
  7. Edit in either window -- changes propagate both ways

Building

Requires Bun 1.3.10+.

bun run build.ts

This produces four single-file HTMLs in dist/. The build script:

  1. Runs Bun.build() for each variant (bundles TypeScript, minifies)
  2. Inlines all JS and CSS chunks into the HTML
  3. Copies sqlite3.wasm to dist/ for the WASM variant

Project structure

paste/
  indexeddb/          source for IndexedDB paste app
    app.ts
    index.html
  nedb/               source for NeDB paste app
    app.ts
    index.html
  sql-js/             source for sql.js paste app
    app.ts
    index.html
  sqlite/             source for SQLite WASM paste app
    app.ts
    index.html
  shared.ts           shared UI logic (all variants import this)
  styles.css          shared styles
  build.ts            bun build script
  serve.ts            dev server for SQLite WASM variant
  dist/               built output (single HTML files)

Folder layout on disk

After selecting a sync folder, you'll see:

your-folder/
  events/
    1710000000000_a1b2c3d4e5f6.json
    1710000001000_f6e5d4c3b2a1.json
  data/                                 (nedb and sql-js only)
    kv.db                               (nedb: NDJSON)
    docs.db                             (nedb: NDJSON)
    store.sqlite                        (sql-js: SQLite binary)

The events/ folder is shared by all variants. If you point two different variant HTMLs at the same folder, they will sync with each other (the event format is identical across all four).