@grimoire-intel/clavicula-extras
v1.0.1
Published
Optional decorators for [Clavicula](https://github.com/grimoire-intelligence/clavicula) stores.
Readme
@grimoire-intel/clavicula-extras
Optional decorators for Clavicula stores.
Installation
npm install @grimoire-intel/clavicula @grimoire-intel/clavicula-extrasDecorators
withPersist
Syncs store state with localStorage.
import { createStore } from '@grimoire-intel/clavicula';
import { withPersist, withBatching } from '@grimoire-intel/clavicula-extras';
// Always wrap with withBatching to avoid excessive writes
const settings = withPersist(
withBatching(createStore({ theme: 'light' })),
'app-settings'
);withBatching
Batches multiple synchronous updates into a single notification. Includes built-in equality checking.
import { withBatching } from '@grimoire-intel/clavicula-extras';
const store = withBatching(createStore({ x: 0, y: 0 }));
// These three calls result in one notification
store.set({ x: 1 });
store.set({ y: 2 });
store.set({ x: 10 });
// Subscribers see: { x: 10, y: 2 }Note: React, Vue, Solid, and Angular batch renders internally, so withBatching provides less visible benefit for rendering. However, it's still valuable for:
- Reducing notification overhead (N calls → 1 notification)
- Filtering no-op updates via equality checking
- Protecting
withPersistfrom excessive localStorage writes
Most useful for vanilla JS, Svelte, and when composing with withPersist.
withHistory
Adds undo/redo capability.
import { withHistory } from '@grimoire-intel/clavicula-extras';
const store = withHistory(createStore({ text: '' }));
store.set({ text: 'hello' });
store.set({ text: 'hello world' });
store.undo(); // { text: 'hello' }
store.redo(); // { text: 'hello world' }
store.canUndo(); // true
store.canRedo(); // falsewithReset
Adds a reset method to restore initial state.
import { withReset } from '@grimoire-intel/clavicula-extras';
const store = withReset(createStore({ count: 0 }));
store.set({ count: 99 });
store.reset(); // { count: 0 }withFreeze
Deep freezes state after every update to catch accidental mutations. No-op in production.
import { withFreeze } from '@grimoire-intel/clavicula-extras';
const store = withFreeze(createStore({ items: [] }));
store.get().items.push('oops'); // Throws in developmentwithLogging
Logs state changes to console.
import { withLogging } from '@grimoire-intel/clavicula-extras';
const store = withLogging(createStore({ count: 0 }), 'counter');
// Logs: [counter] { count: 0 }
store.set({ count: 1 });
// Logs: [counter] { count: 1 }Composition Order
Decorators that use subscribe() internally must be outermost:
// Correct order
withPersist(
withBatching(
withHistory(
withFreeze(store)
)
),
'key'
)See Writing Decorators for details.
API
function withPersist<T>(store: Store<T>, key: string): Store<T>;
function withBatching<T>(store: Store<T>, isEqual?: (a: T, b: T) => boolean): Store<T>;
function withHistory<T>(store: Store<T>, maxSize?: number): HistoryStore<T>;
function withReset<T>(store: Store<T>): Store<T> & { reset(): void };
function withFreeze<T>(store: Store<T>): Store<T>;
function withLogging<T>(store: Store<T>, label?: string): Store<T>;See the main documentation for full API reference.
