A persistence plugin for comes — the lightweight address-based event system.
comes-storage automatically saves and restores event values to a storage backend (browser localStorage by default). When your app starts, the last saved value for each tracked event is replayed into the event system so all listeners receive it immediately upon registration — no manual rehydration needed.
npm install comes comes-storage
comesis a peer dependency and must be installed alongside this package.
import { es } from 'comes';
import { setupStorage } from 'comes-storage';
// Persist the 'theme' and 'language' events under a single storage key
setupStorage('app/settings', ['theme', 'language']);
// The last saved value is replayed immediately to any listener
es.listen('theme', (value) => {
console.log('Theme:', value); // restored from localStorage on page reload
});
// Saving is automatic — just send events normally
await es.send('theme', 'dark'); // persisted
await es.send('language', 'en'); // persistedAfter a page reload, both 'dark' and 'en' are automatically restored and delivered to listeners.
setupStorage registers an interceptor on each tracked event address. Every time a value is sent to one of those addresses, the interceptor serializes and saves the updated state to storage under the storageName key.
All tracked events share a single storage entry structured as:
{
"theme": "dark",
"language": "en"
}On setup, setupStorage reads this entry and calls es.send() for each event with its last known value, so every listener registered afterward receives the restored value immediately (via comes's built-in value caching).
Special case: if storageName is also listed in the events array, its value is stored directly at the root key (not nested inside the object).
import { setupStorage } from 'comes-storage';
setupStorage(
storageName: string,
events: string[],
storage?: Storage,
es?: EventSystem
): void| Parameter | Type | Default | Description |
|---|---|---|---|
storageName |
string |
— | The key used to read/write all event data in storage |
events |
string[] |
— | Event addresses to track and persist |
storage |
Storage |
new LocalStorageStorage() |
Storage backend to use |
es |
EventSystem |
global es from comes |
The event system instance to attach to |
The default storage backend. Uses globalThis.localStorage to persist data as JSON. Falls back to an empty object {} if the stored value is missing or cannot be parsed.
import { LocalStorageStorage } from 'comes-storage';
const storage = new LocalStorageStorage();
storage.save('my-key', { count: 1 });
const data = storage.load('my-key'); // { count: 1 }Implement this interface to use a custom storage backend (e.g. sessionStorage, IndexedDB, AsyncStorage for React Native, or a server-side store).
import type { Storage } from 'comes-storage';
const myStorage: Storage = {
load(address: string) {
const raw = sessionStorage.getItem(address);
return raw ? JSON.parse(raw) : {};
},
save(address: string, data: any) {
sessionStorage.setItem(address, JSON.stringify(data));
},
};import { es } from 'comes';
import { setupStorage } from 'comes-storage';
setupStorage('checkout/form', ['checkout/name', 'checkout/email', 'checkout/address']);
// Bind to inputs
es.listen('checkout/name', (v) => (nameInput.value = v ?? ''));
es.listen('checkout/email', (v) => (emailInput.value = v ?? ''));
es.listen('checkout/address', (v) => (addressInput.value = v ?? ''));
// Save on change
nameInput.addEventListener('input', () => es.send('checkout/name', nameInput.value));
emailInput.addEventListener('input', () => es.send('checkout/email', emailInput.value));
addressInput.addEventListener('input', () => es.send('checkout/address', addressInput.value));import { EventSystem } from 'comes';
import { setupStorage } from 'comes-storage';
import type { Storage } from 'comes-storage';
const memoryStorage: Storage = {
store: {} as Record<string, any>,
load(address) { return this.store[address] ?? {}; },
save(address, data) { this.store[address] = data; },
};
const es = new EventSystem();
setupStorage('app', ['app/user', 'app/prefs'], memoryStorage, es);import { EventSystem } from 'comes';
import { setupStorage } from 'comes-storage';
const es = new EventSystem();
setupStorage('ui/state', ['ui/sidebar', 'ui/theme'], undefined, es);
await es.send('ui/theme', 'light'); // persisted to localStorage under 'ui/state'ISC