IndexedDB-backed object storage for browsers and workers. Store structured-clone JS values (objects, arrays, and primitives limited to msgpack-compatible types) by key, read them back directly, and share data across tabs and workers without schema migrations.
- Simple
put/get/head/delete/listAPI in browser contexts. - Object storage for msgpack-safe structured-clone JS values: primitives, arrays, plain objects, Date, and typed arrays.
- Single object store keyed by string; no migrations to manage.
- Data shared per origin across tabs and workers (instance per JavaScript realm).
- Offline persistence via IndexedDB.
- TypeScript-first.
- Singleton-only API: one shared
storageinstance per JavaScript realm (per thread).
npm install offdeximport storage from "offdex";
await storage.put("profile:ada", { greeting: "hello from IndexedDB" });
const object = await storage.get("profile:ada");
if (object) {
console.log(object);
}
await storage.put("bytes", new Uint8Array([1, 2, 3]));
const bytes = await storage.get("bytes");
console.log(bytes instanceof Uint8Array, bytes);Singleton storage instance per JavaScript realm backed by the offdex database
and blobs object store. The underlying store is shared per origin across tabs
and workers.
put(key, value, options?)->Promise<void>get(key, options?)->Promise<unknown | null>head(key)->Promise<boolean>delete(key)->Promise<void>list(options?)->Promise<{ objects: { key: string }[] }>
valuemust be a structured-clone JS value encodable by@msgpack/msgpackwith default options.- Allowed:
null/undefined, booleans, numbers, strings, arrays, plain objects,Date, andArrayBufferView(typed arrays/DataView). - Not allowed:
BigInt,Map,Set,RegExp,Error,Blob/File,ArrayBuffer, functions, symbols, or circular references. putthrows aTypeErrorif a value is not msgpack-compatible.- MessagePack note:
undefineddecodes asnull, and binary decodes asUint8Array.
- Method names mirror Cloudflare R2 (
put/get/head/delete/list), but return values are simplified for direct value access. - Offdex does not use MessagePack internally; it just validates compatibility.
optionsarguments are accepted for signature compatibility but not used.listcurrently returns all keys; prefix/limit/cursor options are ignored.
npm run buildnpx playwright install
npm testPlaywright runs Chromium, Firefox, WebKit, plus mobile emulation projects.
npx playwright install
npm run benchThe benchmark runs in Chromium via Playwright and times a batch of msgpack-safe
put/head/get/list/delete operations.
[bench] put 200 items: 148.6ms
[bench] head 200 items: 101.6ms
[bench] get 200 items: 100.3ms
[bench] list 200 items: 2.7ms
[bench] delete 200 items: 123.8ms
- Run
npm run build, openin-browser-testing.html, then usestoragefrom the console with msgpack-compatible structured-clone values.
- Requires
indexedDB(modern browsers / worker runtimes). - Data is scoped per origin; all tabs/workers on the same origin share the same store.