Documentation
Storage & Hydration
Persistent signals, SSR data hydration, and zero-flash boot.
Persistence in Alwatr is layered: a low-level provider for versioned JSON storage, a reactive signal that wraps it, and a separate SSR bridge for hydrating state that the server already knows on first paint.
Storage providers
@alwatr/local-storage and @alwatr/session-storage provide versioned JSON persistence behind an identical provider API:
import {createLocalStorageProvider} from '@alwatr/flux';
const storage = createLocalStorageProvider<{name: string}>({
name: 'user-data',
schemaVersion: 1,
});
storage.write({name: 'Ali'});
const data = storage.read(); // {name: string} | null
storage.remove();Bump schemaVersion whenever the stored shape changes — the provider auto-clears older-versioned data on the next read, which is the whole migration story. Custom parse/stringify functions let you persist non-JSON-native types like Map, Set, or Date.
Reactive persistence
PersistentStateSignal and SessionStateSignal (see Signals) wrap these providers: every .set() auto-persists, debounced (saveDebounceDelay, roughly 1 second by default) so rapid updates don't thrash storage, with full BFCache lifecycle integration so state survives a page freeze/resume cycle correctly.
SSR hydration
Initial state should never be fetched via an async call during boot — it should already be on the page. EmbeddedDataCollector<T> extracts, parses, and validates JSON from a <script type="application/json"> tag the server rendered, so the client can synchronously seed state with zero extra round-trips and no flash of empty content.
<script type="application/json" id="app-config">{"theme":"dark"}</script>import {EmbeddedDataCollector} from '@alwatr/flux';
interface AppConfig { theme: 'dark' | 'light'; }
const isAppConfig = (value: unknown): value is AppConfig =>
typeof value === 'object' && value !== null && 'theme' in value;
const collector = new EmbeddedDataCollector<AppConfig>('app-config', isAppConfig);
const config = collector.collect(); // AppConfig | null — SSR-safeThe pipeline is: locate the script tag by attribute → read textContent then clear it (a GC hint) → JSON.parse → run the validator → return T | null on any failure. Wrap it in Lazy so extraction only happens on first access:
import {lazy} from '@alwatr/core';
export const appConfig = lazy(
() => new EmbeddedDataCollector<AppConfig>('app-config', isAppConfig).collect(),
);Page-ready
@alwatr/page-ready is a lightweight page-identity signal for multi-page apps — it reads the page-id attribute on <body>.
import {onPageReady, subscribePageReady, dispatchPageReady} from '@alwatr/flux';
onPageReady('home', () => initHomePage());
subscribePageReady((pageId) => analytics.trackPageView(pageId));
dispatchPageReady(); // call once, at the end of bootstrap