UNPKG

@tanstack/persister

Version:

Utilities for persisting state to local storage, session storage, indexedDB, and more.

143 lines (142 loc) 6.15 kB
import { Persister } from './persister.cjs'; import { RequiredKeys } from './types.cjs'; export interface PersistedStorage<TState, TSelected extends Partial<TState> = TState> { buster?: string; state: TSelected | undefined; timestamp: number; } /** * Configuration options for creating a browser-based state persister. * * The persister can use either localStorage (persists across browser sessions) or * sessionStorage (cleared when browser tab/window closes) to store serialized state. */ export interface StoragePersisterOptions<TState, TSelected extends Partial<TState> = TState> { /** * A version string used to invalidate cached state. When changed, any existing * stored state will be considered invalid and cleared. */ buster?: string; /** * The default state to use if no state is found in storage. */ defaultState?: TState; /** * Optional function to customize how state is deserialized after loading from storage. * By default, JSON.parse is used. * * Optionally, consider using SuperJSON for better deserialization of complex objects. See https://github.com/flightcontrolhq/superjson */ deserializer?: (state: string) => PersistedStorage<TSelected>; /** * Unique identifier used as the storage key for persisting state. */ key: string; /** * Maximum age in milliseconds before stored state is considered expired. * When exceeded, the state will be cleared and treated as if it doesn't exist. */ maxAge?: number; /** * Optional callback that runs after state is successfully loaded. */ onLoadState?: (state: TSelected | undefined, storagePersister: StoragePersister<TState, TSelected>) => void; /** * Optional callback that runs after state is unable to be loaded. */ onLoadStateError?: (error: Error, storagePersister: StoragePersister<TState, TSelected>) => void; /** * Optional callback that runs after state is successfully saved. */ onSaveState?: (state: TSelected, storagePersister: StoragePersister<TState, TSelected>) => void; /** * Optional callback that runs after state is unable to be saved. * For example, if the storage is full (localStorage >= 5MB) */ onSaveStateError?: (error: Error, storagePersister: StoragePersister<TState, TSelected>) => void; /** * Optional function to customize how state is serialized before saving to storage. * By default, JSON.stringify is used. * * Optionally, consider using SuperJSON for better serialization of complex objects. See https://github.com/flightcontrolhq/superjson */ serializer?: (state: PersistedStorage<TSelected>) => string; /** * Optional function to filter which parts of the state are persisted and loaded. * When provided, only the filtered state will be saved to storage and returned when loading. * This is useful for excluding sensitive or temporary data from persistence. * * Note: Don't use this to replace the serialization. Use the `serializer` option instead for that. */ select?: (state: TState) => TSelected; /** * The browser storage implementation to use for persisting state. * Typically window.localStorage or window.sessionStorage. * * Defaults to window.localStorage. */ storage?: Storage | null; } type DefaultOptions = RequiredKeys<Partial<StoragePersisterOptions<any>>, 'deserializer' | 'serializer' | 'storage'>; /** * A persister that saves state to browser local/session storage. * * The persister can use either localStorage (persists across browser sessions) or * sessionStorage (cleared when browser tab/window closes). State is automatically * serialized to JSON when saving and deserialized when loading. * * Optionally, a `buster` string can be provided to force cache busting by storing it in the value. * Optionally, a `maxAge` (in ms) can be provided to expire the stored state after a certain duration. * Optionally, callbacks can be provided to run after state is saved or loaded. * * @example * ```ts * const persister = new StoragePersister({ * key: 'my-rate-limiter', // required * storage: window.localStorage, * buster: 'v2', * maxAge: 1000 * 60 * 60, // 1 hour * stateTransform: (state) => ({ * // Only persist specific parts of the state * count: state.count, * lastReset: state.lastReset, * // Exclude sensitive or temporary data * }), * onSaveState: (key, state) => console.log('State saved:', key, state), * onLoadState: (key, state) => console.log('State loaded:', key, state), * onLoadStateError: (key, error) => console.error('Error loading state:', key, error), * onSaveStateError: (key, error) => console.error('Error saving state:', key, error) * }) * ``` */ export declare class StoragePersister<TState, TSelected extends Partial<TState> = TState> extends Persister<TState, TSelected> { options: StoragePersisterOptions<TState, TSelected> & DefaultOptions; constructor(initialOptions: StoragePersisterOptions<TState, TSelected>); /** * Updates the persister options */ setOptions: (newOptions: Partial<StoragePersisterOptions<TState, TSelected>>) => void; /** * Saves the state to storage */ saveState: (state: TState | TSelected) => void; /** * Loads the state from storage */ loadState: () => TSelected | undefined; /** * Handles the storage event and ignores events triggered by the current tab. * * The storage event is only fired in other tabs/windows, not the one that made the change. * However, some browsers or environments may fire it in the same tab, so we check if the event's storageArea * matches the persister's storage and ignore if not. */ private handleStorageChange; subscribeToStorage: () => void; unsubscribeFromStorage: () => void; /** * Clears the state from storage or sets the default state if provided and specified to be used */ clearState: (useDefaultState?: boolean) => void; } export {};