store-thing
v0.3.1
Published
A reactive store backed by localStorage/sessionStorage, with immutable updates, typed events, and cross-tab sync
Readme
store-thing
A reactive store persisted to localStorage or sessionStorage: immutable draft-style updates, typed change events, and cross-tab sync. State must be JSON-serializable — that is what survives the storage round-trip.
npm install store-thingimport { Store } from "store-thing";
const store = new Store("counter", { count: 0 });
// persisted under localStorage key "store-counter"; an existing value wins over the initial one
// subscribe: immediate call with current state, then every change
const sub = store.subscribe((state) => console.log(state.count));
// update a draft copy; the store persists and emits the result
store.update((draft) => { draft.count += 1; });
store.get(); // { count: 1 } — treat as read-only; change via update()
store.reset(); // back to the initial value
sub.dispose(); // or `using sub = store.subscribe(…)`API
new Store(id, initValue, { storage? })—storageis"local"(default) or"session". The value in storage wins overinitValue, which is only written when the key is empty.get(): T— the current state, from an in-memory cache (storage is only read at construction and on cross-tab events).update(draft => void)— mutate astructuredCloneof the state; the result is persisted and emitted. The previous state object is never mutated.reset()— persist and emit a fresh copy ofinitValue.on("change", state => void)/subscribe(state => void)— listen for changes;subscribealso calls back immediately with the current state. Both return a handle withdispose()and[Symbol.dispose](see @rupertsworld/disposable).Storeis a typedEventTarget(via @rupertsworld/event-target):store.addEventListener("change", (e) => e.state)works, with full typing and native options (once,signal, …).- Cross-tab sync — for localStorage-backed stores, a write from another tab updates the store and emits
change(via the windowstorageevent; sessionStorage is per-tab, so no sync there).dispose()detaches the window listener — only needed for stores that don't live as long as the page.
Changes in 0.3.0
Rebuilt on @rupertsworld/event-target and @rupertsworld/disposable; Immer replaced by structuredClone (same update(draft => …) API, one less dependency); get() returns T (not T | undefined) from an in-memory cache; cross-tab sync added; ESM only, CommonJS build dropped.
