Storage TTL / Expiry Zero Dependencies MIT

StorageManager.js

A lightweight wrapper around localStorage and sessionStorage that adds TTL expiration, LZString compression, namespacing, batch operations, and cross-tab sync — all async, all Promise-based.

Installation

npm / yarn

npm install web-storage-manager-js

ES module

import StorageManager from 'web-storage-manager-js';

CDN

<script src="https://cdn.jsdelivr.net/npm/web-storage-manager-js@1.0.1/StorageManager.js"></script>

Constructor

new StorageManager(useSession?, options?)
Option Type Default Description
useSession boolean false Use sessionStorage instead of localStorage.
namespace string "" Prefix prepended to every key to isolate modules sharing an origin.
defaultExpiration object {} Map of { keyName: seconds }. Auto-expires matching keys on set().
enableCompression boolean true Compress values via LZString before writing (lazy-loaded from CDN on first use).
// localStorage, no namespace, compression on (default)
const store = new StorageManager();

// sessionStorage
const session = new StorageManager(true);

// Namespaced with auto-expiration
const appStore = new StorageManager(false, {
  namespace: 'myApp',
  defaultExpiration: { authToken: 3600, userPrefs: 86400 },
  enableCompression: false,
});

API Reference

All methods are async and return Promises.

Method Description
set(key, value) Store a JSON-serializable value. Auto-expires if defaultExpiration includes the key.
get(key) Retrieve a value, or null if missing or expired. Expired items are removed on read.
remove(key) Delete a key and cancel any pending expiration timer.
has(key) Returns true if the key exists and has not expired.
expires(key, seconds) Set or update the TTL for an existing key.
keys() Array of all keys in the active namespace (without prefix).
getAll() All key-value pairs under the active namespace as a plain object.
batchSet(items) Write multiple { key, value, expiresIn? } pairs at once.
batchGet(keys) Read multiple keys at once. Returns an object mapping each key to its value or null.
batchRemove(keys) Remove an array of keys in one call.
onChange(key, cb) Register a listener called with (newValue, oldValue) on any change, including cross-tab.
offChange(key) Unsubscribe the listener registered for key.
cleanup() Scan and remove all expired keys. Called automatically on construction.
clear() Remove all entries from the underlying storage object.

Usage Patterns

Caching an API response

const cache = new StorageManager(false, {
  namespace: 'apiCache',
  defaultExpiration: { products: 300 }, // 5 min
});

async function getProducts() {
  if (await cache.has('products')) return cache.get('products');
  const data = await fetch('/api/products').then(r => r.json());
  await cache.set('products', data); // auto-expires
  return data;
}

Auth token with TTL

const auth = new StorageManager(false, {
  namespace: 'auth',
  enableCompression: false,
});

await auth.set('token', tokenValue);
await auth.expires('token', expiresInSeconds);

// Returns null if expired
const token = await auth.get('token');

Cross-tab sync

// Tab A — listen for changes
store.onChange('notifications', (count) => {
  updateBadge(count);
});

// Tab B — triggers Tab A's listener
await store.set('notifications', 5);

Features

  • TTL Expiration

    Per-key time-to-live with auto-removal and reactive onChange notification on expiry.

  • LZString Compression

    Transparent compression keeps large payloads well under the 5 MB storage limit.

  • Namespacing

    Prefix all keys to isolate modules sharing the same origin — no collisions.

  • Batch Operations

    batchSet, batchGet, and batchRemove for multi-key ops in one call.

Compression Guide

Enable when

  • Storing large objects like API responses or datasets
  • Approaching the ~5 MB storage quota

Disable when

  • Storing small flags or IDs
  • Running in Node.js / Jest (no CDN access)
  • Need human-readable values in DevTools

Data written with compression on cannot be read back with it off — pick one mode per namespace.