import { WrStorage } from 'ngwr/storage';WrStorage
Typed, reactive key-value storage over localStorage or any engine, safe under SSR.
Installation
Import the class. This entry point has no stylesheet.
Usage
private readonly store = inject(WrStorage);
this.store.set('user', { name: 'Ada' });
this.store.get<{ name: string }>('user'); // { name: 'Ada' }
this.store.set('cart', items, { ttl: 60_000 }); // gone after 60 s
this.store.has('cart'); // ignores expiry
const theme = this.store.watch<'light' | 'dark'>('theme', 'light');
effect(() => console.log('theme is', theme()));Live demo
Swap the engine
Pass an engine to withStorage() at bootstrap; WrStorage reads it once.
provideWr(withStorage({ engine: sessionStorage }))
// A factory, for a wrapper such as encrypted storage:
provideWr(withStorage({ engine: () => new EncryptedStorage(localStorage, key) }))
// Or the token, at bootstrap only:
providers: [{ provide: WR_STORAGE_ENGINE, useValue: sessionStorage }]What lands in storage
set() stores a JSON envelope: the value under v, plus an expiry e in epoch ms when a TTL applies.
import type { WrStorageEnvelope } from 'ngwr/storage';
// provideWr(withStorage({ prefix: 'myapp:' }))
store.set('theme', 'dark');
// localStorage['myapp:theme'] === '{"v":"dark"}'
store.set('cart', [{ sku: 'a1' }], { ttl: 60_000 });
// localStorage['myapp:cart'] === '{"v":[{"sku":"a1"}],"e":1767225600000}'
// Reading it outside Angular:
const raw = localStorage.getItem('myapp:theme');
const env = raw === null ? null : (JSON.parse(raw) as WrStorageEnvelope<string>);
const value = env && (env.e === undefined || env.e >= Date.now()) ? env.v : null;- The raw key is
prefix + key; code outside Angular has to add the prefix too. - A key that holds no envelope is returned as stored.
json: falsestoresString(value)and drops TTL.
API
| Name | Description | Type | Default |
|---|---|---|---|
get(key, fallback?) | Read a value. Returns fallback (default null) when absent or expired. | <T>(k: string, f?: T) => T | null | — |
set(key, value, opts?) | Write a value. ttl (ms) overrides the configured default. | <T>(k: string, v: T, opts?: { ttl?: number }) => void | — |
remove(key) | Remove the value at key. | (k: string) => void | — |
clear() | Clear every key under the prefix, or every key when there is none. | () => void | — |
has(key) | Whether the key exists, ignoring expiry. | (k: string) => boolean | — |
keys() | All known keys with the prefix stripped. | () => readonly string[] | — |
watch(key, fallback?) | Read as a signal. Follows writes from this tab and others. | <T>(k: string, f?: T) => Signal<T | null> | — |
withStorage(options?) | The provideWr() feature: prefix, json, ttl and engine. | (options?: WrStorageOptions) => WrFeature<'storage'> | — |
WR_STORAGE_ENGINE | The active Storage engine. Provide it at bootstrap; a route or component provider is ignored unless it also provides WrStorage. | InjectionToken<Storage> | localStorage / memory fallback |
createMemoryStorage() | An in-memory Storage, for tests. | () => Storage | — |
WrStorageEnvelope | The stored format while json is on: value v, expiry e in epoch ms. | { readonly v: T; readonly e?: number } | — |