import { EventObject, EventPayloadMap, StoreContext, StoreExtension } from "./types.js"; /** * Storage interface compatible with `localStorage`, `sessionStorage`, and async * storage adapters (React Native AsyncStorage, IndexedDB, etc.). */ export interface StateStorage { getItem: (name: string) => string | null | Promise; setItem: (name: string, value: string) => void | Promise; removeItem: (name: string) => void | Promise; } /** The envelope persisted to storage for snapshot strategy. @public */ export interface PersistStorageValue { context: Partial; version: string | number; } /** The envelope persisted to storage for event strategy. @public */ export interface PersistEventStorageValue { events: TEvent[]; /** * Snapshot checkpoint from which to replay events. When events are truncated * by `maxEvents`, this stores the context at the truncation point so replay * produces the correct state. */ checkpoint?: unknown; version: string | number; } /** Base options shared by both persist strategies. @public */ export interface PersistBaseOptions { /** Storage key (required). */ name: string; /** Storage adapter. Defaults to `localStorage`. */ storage?: StateStorage; /** Schema version. Defaults to 0. */ version?: string | number; /** Minimum milliseconds between storage writes. Defaults to 0 (immediate). */ throttle?: number; /** Called after a successful storage write. */ onDone?: (data: any) => void; /** Called when a storage read or write fails. */ onError?: (error: unknown) => void; /** Skip automatic hydration on store creation. Defaults to `false`. */ skipHydration?: boolean; } /** Options for the snapshot persist strategy (default). @public */ export interface PersistSnapshotOptions extends PersistBaseOptions { /** Persist strategy. Defaults to `'snapshot'`. */ strategy?: 'snapshot'; /** * Controls whether an event should trigger a storage write. Return `false` to * skip persisting for that event. */ filter?: (event: TEvent) => boolean; /** Select which parts of context to persist. Defaults to full context. */ pick?: (context: TContext) => Partial; /** Migration function for version upgrades. */ migrate?: (persistedContext: any, version: string | number) => TContext; /** * Custom merge strategy when rehydrating. Defaults to shallow merge (`{ * ...currentContext, ...persistedContext }`). */ merge?: (persistedContext: Partial, currentContext: TContext) => TContext; /** Custom serializer. Defaults to `JSON.stringify`. */ serialize?: (value: PersistStorageValue) => string; /** Custom deserializer. Defaults to `JSON.parse`. */ deserialize?: (str: string) => PersistStorageValue; } /** Options for the event persist strategy. @public */ export interface PersistEventOptions<_TContext = StoreContext, TEvent extends EventObject = EventObject> extends PersistBaseOptions { /** Persist strategy. */ strategy: 'event'; /** * Maximum number of events to keep. When exceeded, a snapshot checkpoint is * saved and oldest events are dropped. Replay starts from the checkpoint. * Defaults to Infinity. */ maxEvents?: number; /** Migration function for version upgrades. Receives the stored events array. */ migrate?: (persistedEvents: any[], version: string | number) => any[]; /** Custom serializer. Defaults to `JSON.stringify`. */ serialize?: (value: PersistEventStorageValue) => string; /** Custom deserializer. Defaults to `JSON.parse`. */ deserialize?: (str: string) => PersistEventStorageValue; } /** Options for the `persist` store extension. @public */ export type PersistOptions = PersistSnapshotOptions | PersistEventOptions; /** * Creates a store extension that persists context to storage. * * @example * * ```ts * import { persist } from '@xstate/store/persist'; * * const store = createStore({ * context: { count: 0 }, * on: { inc: (ctx) => ({ count: ctx.count + 1 }) } * }).with(persist({ name: 'my-store' })); * ``` * * @example * * ```ts * // Throttled writes with callbacks * const store = createStore({ * context: { count: 0 }, * on: { inc: (ctx) => ({ count: ctx.count + 1 }) } * }).with( * persist({ * name: 'my-store', * throttle: 1000, * onDone: (ctx) => console.log('Persisted:', ctx), * onError: (err) => console.error('Persist failed:', err) * }) * ); * ``` * * @example * * ```ts * // Async storage with manual rehydration * import { * persist, * rehydrateStore, * createJSONStorage * } from '@xstate/store/persist'; * * const store = createStore({ * context: { count: 0 }, * on: { inc: (ctx) => ({ count: ctx.count + 1 }) } * }).with( * persist({ * name: 'my-store', * storage: createJSONStorage(() => AsyncStorage), * skipHydration: true * }) * ); * * await rehydrateStore(store); * ``` */ export declare function persist(options: PersistOptions>): StoreExtension; /** * Creates a storage adapter with error handling and SSR safety. * * @example * * ```ts * import { createJSONStorage } from '@xstate/store/persist'; * * // Safe for SSR — returns noop storage if localStorage is unavailable * const storage = createJSONStorage(() => localStorage); * * // Async storage (React Native) * const asyncStorage = createJSONStorage(() => AsyncStorage); * ``` */ export declare function createJSONStorage(getStorage: () => StateStorage): StateStorage; /** * Removes persisted data from storage for a store that uses the `persist` * extension. * * @example * * ```ts * import { clearStorage } from '@xstate/store/persist'; * * clearStorage(store); * ``` */ export declare function clearStorage(store: { getSnapshot: () => any; }): void; /** * Forces an immediate write of any pending throttled context to storage. * * @example * * ```ts * import { flushStorage } from '@xstate/store/persist'; * * // Force write before page unload * window.addEventListener('beforeunload', () => { * flushStorage(store); * }); * ``` */ export declare function flushStorage(store: { getSnapshot: () => any; }): void; /** * Returns whether the store has been hydrated from storage. * * @example * * ```ts * import { isHydrated } from '@xstate/store/persist'; * * if (isHydrated(store)) { * // Safe to read persisted state * } * ``` */ export declare function isHydrated(store: { getSnapshot: () => any; }): boolean; /** * Reads persisted state from (potentially async) storage and rehydrates the * store. Use this for async storage adapters or when `skipHydration` is * `true`. * * @example * * ```ts * import { rehydrateStore } from '@xstate/store/persist'; * * const store = createStore({ ... }).with(persist({ * name: 'my-store', * storage: createJSONStorage(() => AsyncStorage), * skipHydration: true * })); * * await rehydrateStore(store); * ``` */ export declare function rehydrateStore(store: { getSnapshot: () => any; send: (event: any) => void; }): Promise;