import { StoreMiddleware, StoreMiddlewareContext, StoreInstance } from '../types'; /** * Mark stores or fields as not persisted. * * When called without arguments, marks the entire store as not persisted. * When called with a field name, marks that specific field as not persisted. * * @example Store-level exclusion * ```ts * import { notPersisted } from 'storion/persist'; * * const tempStore = store({ * name: 'temp', * state: { sessionData: {} }, * setup: () => ({}), * meta: notPersisted(), // entire store skipped * }); * ``` * * @example Field-level exclusion * ```ts * import { notPersisted } from 'storion/persist'; * import { meta } from 'storion'; * * const userStore = store({ * name: 'user', * state: { name: '', password: '', token: '' }, * setup: () => ({}), * meta: meta.of( * notPersisted.for('password'), * notPersisted.for('token'), * ), * }); * ``` */ export declare const notPersisted: import('..').MetaType<[], true>; /** * Mark stores or fields as persisted. */ export declare const persisted: import('..').MetaType<[], true>; /** * Result from load function - can be sync or async */ export type PersistLoadResult = Record | null | undefined | PromiseLike | null | undefined>; /** * Context passed to the handler function. * Extends StoreMiddlewareContext with the created store instance. */ export interface PersistContext extends StoreMiddlewareContext { /** The store instance being persisted */ store: StoreInstance; } /** * Handler returned by the handler function. * Contains the load and save operations for a specific store. */ export interface PersistHandler { /** * Load persisted state for the store. * Can return sync or async result. * * @returns The persisted state, null/undefined if not found, or a Promise */ load?: () => PersistLoadResult; /** * Save state to persistent storage. * * @param state - The dehydrated state to save */ save?: (state: Record) => void; } /** * Options for persist middleware */ export interface PersistOptions { /** * Only persist stores and fields explicitly marked with `persisted` meta. * * When `false` (default), all stores and fields are persisted unless marked with `notPersisted`. * When `true`, only stores/fields with `persisted()` or `persisted.for(field)` are persisted. * * Note: `notPersisted` always takes priority over `persisted`. * * @example * ```ts * // With persistedOnly: true, only explicitly marked stores/fields are persisted * const userStore = store({ * name: 'user', * state: { name: '', email: '', temp: '' }, * meta: persisted(), // marks entire store for persistence * }); * * const settingsStore = store({ * name: 'settings', * state: { theme: '', fontSize: 14, cache: {} }, * meta: persisted.for(['theme', 'fontSize']), // only these fields persisted * }); * * persist({ * persistedOnly: true, * handler: (ctx) => ({ ... }), * }); * ``` * * @default false */ persistedOnly?: boolean; /** * Filter which stores should be persisted. * Called after `persistedOnly` filtering. * * @param context - The persist context with store instance * @returns true to persist, false to skip */ filter?: (context: PersistContext) => boolean; /** * Filter which fields should be persisted. * Called after `persistedOnly` and `notPersisted` filtering. * * @param context - The persist context with store instance * @returns the fields to persist */ fields?: (context: PersistContext) => string[]; /** * Handler factory that creates load/save operations for each store. * Receives context with store instance, returns handler with load/save. * Can be sync or async (e.g., for IndexedDB initialization). * * @param context - The persist context with store instance * @returns Handler with load/save operations, or Promise of handler * * @example Sync handler (localStorage) * ```ts * handler: (ctx) => { * const key = `app:${ctx.displayName}`; * return { * load: () => JSON.parse(localStorage.getItem(key) || 'null'), * save: (state) => localStorage.setItem(key, JSON.stringify(state)), * }; * } * ``` * * @example Async handler (IndexedDB) * ```ts * handler: async (ctx) => { * const db = await openDB('app-db'); * return { * load: () => db.get('stores', ctx.displayName), * save: (state) => db.put('stores', state, ctx.displayName), * }; * } * ``` */ handler: (context: PersistContext) => PersistHandler | PromiseLike; /** * Called when an error occurs during init, load, or save. * * @param error - The error that occurred * @param operation - Whether the error occurred during 'init', 'load', or 'save' */ onError?: (error: unknown, operation: "init" | "load" | "save") => void; /** * Force hydration to overwrite dirty (modified) state properties. * * By default (false), hydrate() skips properties that have been modified * since initialization to avoid overwriting fresh data with stale persisted data. * * Set to true to always apply persisted data regardless of dirty state. * * @default false */ force?: boolean; } /** * Creates a persist middleware that automatically saves and restores store state. * * @example localStorage (sync handler) * ```ts * import { container, forStores } from "storion"; * import { persist } from "storion/persist"; * * const app = container({ * middleware: forStores([ * persist({ * handler: (ctx) => { * const key = `app:${ctx.displayName}`; * return { * load: () => JSON.parse(localStorage.getItem(key) || 'null'), * save: (state) => localStorage.setItem(key, JSON.stringify(state)), * }; * }, * onError: (error, op) => console.error(`Persist ${op} failed:`, error), * }), * ]), * }); * ``` * * @example IndexedDB (async handler) * ```ts * persist({ * handler: async (ctx) => { * const db = await openDB('app-db', 1, { * upgrade(db) { db.createObjectStore('stores'); }, * }); * return { * load: () => db.get('stores', ctx.displayName), * save: (state) => db.put('stores', state, ctx.displayName), * }; * }, * }); * ``` * * @example With shared debounce * ```ts * persist({ * handler: (ctx) => { * const key = `app:${ctx.displayName}`; * const debouncedSave = debounce( * (s) => localStorage.setItem(key, JSON.stringify(s)), * 300 * ); * return { * load: () => JSON.parse(localStorage.getItem(key) || 'null'), * save: debouncedSave, * }; * }, * }); * ``` * * @example Multi-storage with meta * ```ts * const inSession = meta(); * const inLocal = meta(); * * // Session storage middleware * persist({ * filter: ({ meta }) => meta.any(inSession), * fields: ({ meta }) => meta.fields(inSession), * handler: (ctx) => { * const key = `session:${ctx.displayName}`; * return { * load: () => JSON.parse(sessionStorage.getItem(key) || 'null'), * save: (state) => sessionStorage.setItem(key, JSON.stringify(state)), * }; * }, * }); * ``` */ export declare function persist(options: PersistOptions): StoreMiddleware; //# sourceMappingURL=persist.d.ts.map