zustand-debounce
Version:
**Lightweight** and **powerful** extension for [Zustand](https://github.com/pmndrs/zustand) providing debounced JSON state storage.
200 lines (195 loc) • 7.03 kB
TypeScript
import * as zustand_middleware from 'zustand/middleware';
import { StateStorage } from 'zustand/middleware';
type JsonStorageOptions = {
reviver?: (key: string, value: unknown) => unknown;
replacer?: (key: string, value: unknown) => unknown;
};
/**
* Configuration options for the enhanced JSON storage with debounce functionality.
* Extends the base JSON storage options with additional features for debouncing,
* throttling, retry mechanisms, and event callbacks.
*
* @example
* ```ts
* const storage = createDebouncedJSONStorage('localStorage', {
* debounceTime: 1000,
* maxRetries: 3,
* retryDelay: 1000,
* onRetry: (key, attempt, error, delay) => {
* console.log(`Retry attempt ${attempt} for ${key}`);
* }
* });
* ```
*
* @interface EnhancedJsonStorageOptions
* @extends {JsonStorageOptions}
*/
interface EnhancedJsonStorageOptions extends JsonStorageOptions {
/**
* The time in milliseconds to wait before writing changes to storage.
* Multiple changes within this time window will be grouped into a single write operation.
* @default 0
*/
debounceTime?: number;
/**
* The minimum time in milliseconds between write operations.
* Ensures write operations are not performed more frequently than this interval.
* @default 0
*/
throttleTime?: number;
/**
* If true, changes will be written to storage immediately without debouncing.
* Useful for critical updates that need to be persisted right away.
* @default false
*/
immediately?: boolean;
/**
* The maximum number of retry attempts for failed write operations.
* @default 0
*/
maxRetries?: number;
/**
* The base delay in milliseconds between retry attempts.
* This delay will be multiplied by the backoffMultiplier for each subsequent retry.
* @default 0
*/
retryDelay?: number;
/**
* Callback function triggered immediately when setItem is invoked.
* Called before any debounce delay is applied.
* @param key - The storage key being written
* @param value - The value being stored
*/
onWrite?: (key: string, value: string) => void;
/**
* Callback function triggered after the debounce delay when the data is actually saved.
* @param key - The storage key that was written
* @param value - The value that was stored
*/
onSave?: (key: string, value: string) => void;
/**
* Callback function triggered when a manual flush operation is executed.
* @param key - The storage key being flushed
* @param value - The value being flushed
*/
onFlush?: (key: string, value: string) => void;
/**
* Callback function triggered before each retry attempt.
* Provides information about the retry attempt, the error that occurred,
* and the delay before the next attempt.
* @param key - The storage key being retried
* @param attempt - The current retry attempt number
* @param error - The error that triggered the retry
* @param delay - The delay in milliseconds before the next retry attempt
*/
onRetry?: (key: string, attempt: number, error: any, delay: number) => void;
/**
* Callback function triggered when all retry attempts have failed.
* @param key - The storage key that failed
* @param error - The last error that occurred
*/
onError?: (key: string, error: any) => void;
/**
* Custom function to serialize the state before saving to storage.
* @default JSON.stringify
* @param state - The state to serialize
* @returns The serialized state string
*/
serialize?: (state: unknown) => string;
/**
* Custom function to deserialize the state after retrieving from storage.
* @default JSON.parse
* @param str - The serialized state string
* @returns The deserialized state
*/
deserialize?: (str: string) => unknown;
/**
* Time-to-live in milliseconds for stored data.
* After this period, the data will be considered expired and removed from storage.
* @default 0 - No expiration
*/
ttl?: number;
/**
* Array of plugins to extend storage functionality.
* Plugins are executed in the order they are provided in the array.
* Each plugin can transform data before writing to storage and after reading from storage.
*
* @example
* ```ts
* import { compress } from 'zustand-debounce-compress';
*
* const storage = createDebouncedJSONStorage('localStorage', {
* debounceTime: 1000,
* plugins: [
* compress({ algorithm: 'lz-string' })
* ]
* });
* ```
*/
plugins?: Plugin[];
}
/**
* Plugin interface for extending storage functionality.
* Plugins can intercept and transform data during storage operations.
* All hooks are synchronous to maintain performance and simplicity.
*
* @example
* ```ts
* const myPlugin: Plugin = {
* name: 'my-custom-plugin',
* beforeSetItem: (value) => {
* // Transform value before saving
* return transformedValue;
* },
* afterGetItem: (value) => {
* // Transform value after reading
* return transformedValue;
* }
* };
* ```
*/
interface Plugin {
/**
* Unique name identifier for the plugin.
* Used for debugging and error messages.
*/
name: string;
/**
* Hook called before writing a value to storage.
* Receives the serialized value and can return a transformed version.
* Plugins are executed in array order (first to last).
*
* @param value - The serialized value about to be written to storage
* @returns Transformed value or undefined to skip transformation
*
* @example
* ```ts
* beforeSetItem: (value) => {
* // Compress the value before storage
* return LZString.compress(value);
* }
* ```
*/
beforeSetItem?: (value: string) => string | undefined;
/**
* Hook called after reading a value from storage.
* Receives the raw value from storage and can return a transformed version.
* Plugins are executed in array order (first to last).
*
* @param value - The raw value read from storage (or null if not found)
* @returns Transformed value, null, or undefined to skip transformation
*
* @example
* ```ts
* afterGetItem: (value) => {
* if (!value) return null;
* // Decompress the value after reading
* return LZString.decompress(value);
* }
* ```
*/
afterGetItem?: (value: string | null) => string | null | undefined;
}
type AdapterIdentifier = StateStorage | 'localStorage' | 'sessionStorage' | 'memoryStorage';
declare function createDebouncedJSONStorage(storageApi: AdapterIdentifier, options?: EnhancedJsonStorageOptions): zustand_middleware.PersistStorage<unknown, unknown>;
export { type EnhancedJsonStorageOptions, type Plugin, createDebouncedJSONStorage };