A robust, drop-in IndexedDB wrapper for web apps. Use it for simple key-value storage or full offline-first data layers with indexes, migrations, and transactions.
- Simple KV API — get, set, delete, list, getAll, clear, setAll
- Schema & migrations — Declarative stores, indexes, version upgrades
- Store API — Multi-store, index queries, key ranges, cursor iteration
- Transactions — Batch operations across multiple stores
- Robust — Version change handling, retry, storage helpers, typed errors
- Zero dependencies — Browser-only, ESM + CJS builds
npm install @projectcarey/idbkitimport { DatabaseManager } from '@projectcarey/idbkit';
const db = new DatabaseManager('myDatabase', 1, 'myStore', 'id');
await db.init();
await db.set('username', 'johnDoe');
const value = await db.get('username'); // 'johnDoe'const db = new DatabaseManager({
databaseName: 'myApp',
version: 1,
storeName: 'cache',
keyPath: 'key',
});
await db.init();Define stores and indexes, then bump the version when the schema changes:
const db = new DatabaseManager({
databaseName: 'myApp',
version: 2,
schema: {
version: 2,
stores: [
{
name: 'users',
keyPath: 'id',
autoIncrement: true,
indexes: [
{ name: 'email', keyPath: 'email', unique: true },
{ name: 'createdAt', keyPath: 'createdAt', unique: false },
],
},
{
name: 'cache',
keyPath: 'key',
indexes: [{ name: 'expiresAt', keyPath: 'expiresAt', unique: false }],
},
],
},
migrations: [
(db, transaction, { fromVersion, toVersion }) => {
if (fromVersion < 2) {
const store = transaction.objectStore('users');
store.createIndex('email', 'email', { unique: true });
}
},
],
});
await db.init();Access any store with full CRUD, indexes, and iteration:
const store = db.store('users');
await store.set('u1', { name: 'Alice', email: 'alice@example.com' });
const user = await store.get('u1');
await store.index('email').get('alice@example.com');
const recent = await store.index('createdAt').getAll({ from: startDate, to: endDate });
for await (const [key, value] of store.iterate({ direction: 'prev' })) {
console.log(key, value);
}Batch operations in a single transaction:
await db.transaction(['users', 'sessions'], 'readwrite', async (tx) => {
await tx.store('users').set('u1', { name: 'Alice' });
await tx.store('sessions').set('s1', { userId: 'u1', token: 'abc' });
});DatabaseManager.isSupported(); // true if IndexedDB available
db.close(); // Close connection
db.getStorageEstimate(); // { usage, quota } or null
db.requestPersistence(); // Request persistent storagedb.onVersionChange(() => {
console.log('Another tab upgraded the database. Please reload.');
});
db.onBlocked(() => {
console.log('Close other tabs to upgrade.');
});| Option | Type | Description |
|---|---|---|
retries |
{ maxAttempts, backoffMs } |
Retry init on transient failures |
debug |
boolean |
Log operations to console |
Errors are DatabaseManagerError with a code property:
QUOTA_EXCEEDED— Storage fullCONSTRAINT_ERR— Unique index violationVERSION_ERR— Wrong DB versionBLOCKED— Upgrade blocked by other tabsNOT_FOUND— Store/index doesn't existUNKNOWN— Other errors
import { DatabaseManager, DatabaseManagerError, ErrorCodes } from '@projectcarey/idbkit';
try {
await db.set('key', value);
} catch (err) {
if (err.code === ErrorCodes.QUOTA_EXCEEDED) {
await db.clear();
}
}get(key)— Get value by keyset(key, value)— Set key-value pairdelete(key)— Delete by keylist()— All keysgetAll()— All recordsclear()— Clear storesetAll(entries)— Bulk set[{ key, value }, ...]
store(name)— Get store-scoped APIstore.get(key)— Get by primary keystore.set(key, value)— Put (upsert)store.put(value)— Put with auto keystore.delete(key)— Deletestore.count(range?)— Countstore.clear()— Clearstore.getAll(range?)— All recordsstore.getKeys(range?)— All keysstore.getRange(options)— Get by key rangestore.index(name)— Index APIstore.iterate(options?)— Async iterator
{ from: 'a', to: 'z' } // bound
{ from: 'a', to: 'z', inclusive: [true, false] }
{ from: 'a' } // lowerBound
{ to: 'z' } // upperBound
{ only: 'exact-key' } // onlynpm test # Run tests
npm run test:coverage # Run with coverage report75 tests cover the Simple KV API, Store API, index queries, transactions, schema, migrations, error handling, data types, edge cases, and key ranges.
Run the interactive demo:
npm run exampleThen open http://localhost:3000/example/ in your browser. The demo exercises all features: Simple KV, Store API, index queries, transactions, cursor iteration, and storage utilities.
MIT