# IndexSyncFile — IndexedDB Variant Local-first key-value and document store using **IndexedDB** as the local cache, syncing with a user-selected folder via the File System Access API. ## Why IndexedDB - **Zero dependencies** — uses the browser's built-in IndexedDB API directly - **Persistent by default** — IndexedDB data survives page reloads and browser restarts without any extra work - **No WASM loading** — instant startup, no async module initialization - **Battle-tested** — IndexedDB is the most widely supported browser storage API ## Architecture ``` Write: app ---> IndexedDB (immediate) ---> /events/timestamp_hash.json Sync: /events/*.json ---> sort by timestamp ---> skip applied ---> apply to IndexedDB ``` IndexedDB serves as both the fast query layer and the local persistence layer. The folder's event log is the sync mechanism that keeps multiple browsers converged. ### IDB schema (5 object stores) | Store | Key | Purpose | |-------|-----|---------| | `kv` | `key` | Key-value records | | `docs` | `[store, id]` | Document collection records | | `idx` | `[store, indexName, id]` | Secondary index entries | | `applied` | `filename` | Tracks which event files have been processed | | `meta` | `key` | Client ID, directory handle persistence | The `FileSystemDirectoryHandle` is stored directly in the `meta` IDB store via structured clone, so the user doesn't need to re-select the folder on every page load. ## Install and build ```bash npm install npm run build ``` ## Usage ```ts import { FolderSyncDB } from './dist/index.js'; const db = await FolderSyncDB.open({ dbName: 'MyApp', autoSyncIntervalMs: 5000, }); await db.selectFolder(); // KV await db.kv.set('user', { name: 'Alice' }); // Collections const notes = db.collection({ name: 'notes', indexes: [{ name: 'byTag', fields: ['tag'] }], }); await notes.put({ id: 'n1', title: 'Hello', tag: 'work' }); // Exact match const workNotes = await notes.findByIndex('byTag', 'work'); // Range query (IDB compound key ranges) const recent = await notes.queryByIndex('byDate', { gte: '2024-01-01' }); ``` ## Index implementation Secondary indexes are maintained in a dedicated `idx` IDB object store using compound keys `[store, indexName, id]`. An IDB index on `[store, indexName, value]` enables efficient exact-match and range queries via `IDBKeyRange`. Index entries are updated atomically with document writes inside a single IDB transaction. On first use of a collection, indexes are rebuilt from existing documents. ## Variant-specific notes - Directory handle is persisted in IDB (no separate storage needed) - IDB transactions are used for atomic document + index updates - No external dependencies