{"version":3,"file":"statePersistence.mjs","sources":["../../../src/lib/utils/statePersistence.ts"],"sourcesContent":["/**\n * @file State Persistence\n * @description Safe state persistence utilities for Redux/Zustand with\n * memory-safety, PHI protection, and migration support\n */\n\nimport { logger } from './logging';\nimport { StorageManager, localStorageManager, StorageQuotaError } from './storage';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Persistence configuration\n */\nexport interface PersistConfig<T> {\n  /** Storage key */\n  key: string;\n  /** Storage manager to use */\n  storage?: StorageManager;\n  /** Version for migrations */\n  version?: number;\n  /** Time-to-live in milliseconds */\n  ttl?: number;\n  /** State transformer before persisting */\n  serialize?: (state: T) => unknown;\n  /** State transformer after loading */\n  deserialize?: (persisted: unknown) => T;\n  /** Whitelist of keys to persist (if not provided, persist all) */\n  whitelist?: Array<keyof T>;\n  /** Blacklist of keys to exclude from persistence */\n  blacklist?: Array<keyof T>;\n  /** Migration functions by version */\n  migrations?: Record<number, (state: unknown) => unknown>;\n  /** Whether state contains PHI (will skip persistence) */\n  containsPHI?: boolean;\n  /** Merge strategy for hydration */\n  merge?: 'shallow' | 'deep' | 'replace';\n  /** Throttle persistence writes (ms) */\n  throttle?: number;\n  /** Debug mode */\n  debug?: boolean;\n}\n\n/**\n * Persisted state wrapper\n */\ninterface PersistedState<T> {\n  state: T;\n  version: number;\n  timestamp: number;\n}\n\n/**\n * Rehydrate result\n */\nexport interface RehydrateResult<T> {\n  state: T | null;\n  error: Error | null;\n  migrated: boolean;\n  fromVersion: number | null;\n}\n\n// ============================================================================\n// State Persister\n// ============================================================================\n\n/**\n * State persistence manager\n */\nexport class StatePersister<T extends object> {\n  private config: Required<PersistConfig<T>> & { storage: StorageManager };\n  private lastPersistTime = 0;\n  private pendingPersist: ReturnType<typeof setTimeout> | null = null;\n\n  constructor(config: PersistConfig<T>) {\n    this.config = {\n      key: config.key,\n      storage: config.storage ?? localStorageManager,\n      version: config.version ?? 1,\n      ttl: config.ttl ?? 0,\n      serialize: config.serialize ?? ((state) => state),\n      deserialize: config.deserialize ?? ((persisted) => persisted as T),\n      whitelist: config.whitelist ?? ([] as Array<keyof T>),\n      blacklist: config.blacklist ?? ([] as Array<keyof T>),\n      migrations: config.migrations ?? {},\n      containsPHI: config.containsPHI ?? false,\n      merge: config.merge ?? 'shallow',\n      throttle: config.throttle ?? 100,\n      debug: config.debug ?? false,\n    };\n\n    if (this.config.containsPHI) {\n      logger.warn('[StatePersister] PHI flag set, persistence disabled', {\n        key: this.config.key,\n      });\n    }\n  }\n\n  /**\n   * Persist state to storage\n   */\n  async persist(state: T): Promise<void> {\n    // Skip PHI data\n    if (this.config.containsPHI) {\n      return;\n    }\n\n    // Throttle persistence\n    const now = Date.now();\n    const timeSinceLastPersist = now - this.lastPersistTime;\n\n    if (timeSinceLastPersist < this.config.throttle) {\n      // Schedule delayed persist\n      if (this.pendingPersist) {\n        clearTimeout(this.pendingPersist);\n      }\n\n      this.pendingPersist = setTimeout(() => {\n        void this.persistImmediate(state);\n        this.pendingPersist = null;\n      }, this.config.throttle - timeSinceLastPersist);\n\n      return;\n    }\n\n    await this.persistImmediate(state);\n  }\n\n  /**\n   * Rehydrate state from storage\n   */\n  async rehydrate(): Promise<RehydrateResult<Partial<T>>> {\n    // Skip PHI data\n    if (this.config.containsPHI) {\n      return {\n        state: {} as Partial<T>,\n        error: null,\n        migrated: false,\n        fromVersion: null,\n      };\n    }\n\n    // Outer try-catch for overall rehydration process\n    let persisted: PersistedState<unknown> | null | undefined = null;\n\n    // Inner try-catch specifically for storage.get() to handle parse errors gracefully\n    try {\n      persisted = await this.config.storage.get<PersistedState<unknown> | null>(\n        this.config.key\n      );\n    } catch (storageError) {\n      // Handle corrupted storage data (e.g., invalid JSON, parse errors)\n      logger.error('[StatePersister] Failed to read from storage, clearing corrupted data', {\n        key: this.config.key,\n        error: storageError,\n      });\n\n      // Clear the corrupted entry to prevent repeated failures\n      this.config.storage.remove(this.config.key);\n\n      return {\n        state: {} as Partial<T>,\n        error: storageError instanceof Error ? storageError : new Error(String(storageError)),\n        migrated: false,\n        fromVersion: null,\n      };\n    }\n\n    try {\n      if (persisted === null || persisted === undefined) {\n        return {\n          state: {} as Partial<T>,\n          error: null,\n          migrated: false,\n          fromVersion: null,\n        };\n      }\n\n      // Check TTL\n      if (\n        this.config.ttl > 0 &&\n        Date.now() - persisted.timestamp > this.config.ttl\n      ) {\n        this.config.storage.remove(this.config.key);\n        return {\n          state: {} as Partial<T>,\n          error: new Error('Persisted state expired'),\n          migrated: false,\n          fromVersion: persisted.version,\n        };\n      }\n\n      // Run migrations if needed\n      let migratedState = persisted.state;\n      let migrated = false;\n      const fromVersion = persisted.version;\n\n      if (persisted.version < this.config.version) {\n        migratedState = this.runMigrations(\n          persisted.state,\n          persisted.version,\n          this.config.version\n        );\n        migrated = true;\n\n        if (this.config.debug) {\n          logger.debug('[StatePersister] State migrated', {\n            key: this.config.key,\n            from: persisted.version,\n            to: this.config.version,\n          });\n        }\n      }\n\n      // Deserialize\n      const state = this.config.deserialize(migratedState);\n\n      return {\n        state: state as Partial<T>,\n        error: null,\n        migrated,\n        fromVersion,\n      };\n    } catch (error) {\n      logger.error('[StatePersister] Failed to rehydrate state', { error });\n      return {\n        state: null,\n        error: error as Error,\n        migrated: false,\n        fromVersion: null,\n      };\n    }\n  }\n\n  /**\n   * Merge persisted state with initial state\n   */\n  mergeStates(initial: T, persisted: Partial<T> | null): T {\n    if (!persisted) return initial;\n\n    switch (this.config.merge) {\n      case 'replace':\n        return { ...initial, ...persisted };\n\n      case 'deep':\n        return deepMerge(initial, persisted);\n\n      case 'shallow':\n      default:\n        return { ...initial, ...persisted };\n    }\n  }\n\n  /**\n   * Clear persisted state\n   */\n  clear(): void {\n    this.config.storage.remove(this.config.key);\n\n    if (this.pendingPersist) {\n      clearTimeout(this.pendingPersist);\n      this.pendingPersist = null;\n    }\n  }\n\n  /**\n   * Force immediate persistence\n   */\n  async flush(state: T): Promise<void> {\n    if (this.pendingPersist) {\n      clearTimeout(this.pendingPersist);\n      this.pendingPersist = null;\n    }\n    await this.persistImmediate(state);\n  }\n\n  /**\n   * Filter state based on whitelist/blacklist\n   */\n  private filterState(state: T): Partial<T> {\n    const filtered: Partial<T> = {};\n    const keys = Object.keys(state) as Array<keyof T>;\n\n    for (const key of keys) {\n      // Skip blacklisted keys\n      if (this.config.blacklist.includes(key)) {\n        continue;\n      }\n\n      // If whitelist exists and key is not in it, skip\n      if (\n        this.config.whitelist.length > 0 &&\n        !this.config.whitelist.includes(key)\n      ) {\n        continue;\n      }\n\n      filtered[key] = state[key];\n    }\n\n    return filtered;\n  }\n\n  /**\n   * Persist state immediately\n   */\n  private async persistImmediate(state: T): Promise<void> {\n    try {\n      const filteredState = this.filterState(state);\n      const serialized = this.config.serialize(filteredState as T);\n\n      const persisted: PersistedState<unknown> = {\n        state: serialized,\n        version: this.config.version,\n        timestamp: Date.now(),\n      };\n\n      await this.config.storage.set(this.config.key, persisted, {\n        ttl: this.config.ttl,\n      });\n\n      this.lastPersistTime = Date.now();\n\n      if (this.config.debug) {\n        logger.debug('[StatePersister] State persisted', {\n          key: this.config.key,\n          version: this.config.version,\n        });\n      }\n    } catch (error) {\n      if (error instanceof StorageQuotaError) {\n        logger.warn('[StatePersister] Storage quota exceeded, clearing old data');\n        this.config.storage.cleanup();\n      } else {\n        logger.error('[StatePersister] Failed to persist state', { error });\n      }\n    }\n  }\n\n  /**\n   * Run migrations\n   */\n  private runMigrations(\n    state: unknown,\n    fromVersion: number,\n    toVersion: number\n  ): unknown {\n    let migratedState = state;\n\n    for (let v = fromVersion + 1; v <= toVersion; v++) {\n      const migration = this.config.migrations[v];\n      if (migration) {\n        migratedState = migration(migratedState);\n      }\n    }\n\n    return migratedState;\n  }\n}\n\n// ============================================================================\n// Deep Merge Utility\n// ============================================================================\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n  const result = { ...target };\n\n  for (const key in source) {\n    if (Object.prototype.hasOwnProperty.call(source, key)) {\n      const sourceValue = source[key];\n      const targetValue = result[key];\n\n      if (\n        isPlainObject(sourceValue) &&\n        isPlainObject(targetValue)\n      ) {\n        result[key] = deepMerge(\n          targetValue as object,\n          sourceValue as object\n        ) as T[Extract<keyof T, string>];\n      } else if (sourceValue !== undefined) {\n        result[key] = sourceValue as T[Extract<keyof T, string>];\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Check if value is a plain object\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    !Array.isArray(value) &&\n    Object.getPrototypeOf(value) === Object.prototype\n  );\n}\n\n// ============================================================================\n// Zustand Middleware\n// ============================================================================\n\n/**\n * Zustand persist middleware options\n */\nexport interface ZustandPersistOptions<T> extends Omit<PersistConfig<T>, 'key'> {\n  name: string;\n}\n\n/**\n * Create Zustand persist middleware\n */\nexport function createZustandPersist<T extends object>(\n  options: ZustandPersistOptions<T>\n): {\n  persist: StatePersister<T>;\n  onFinishHydration: (fn: () => void) => () => void;\n  hasHydrated: () => boolean;\n  rehydrate: () => Promise<void>;\n  onHydrate: (listener: () => void) => () => void;\n  clearStorage: () => void;\n  getPersister: () => StatePersister<T>;\n} {\n  const persister = new StatePersister<T>({\n    ...options,\n    key: options.name,\n  });\n\n  let isHydrated = false;\n  const hydrationListeners: Array<() => void> = [];\n\n  return {\n    /**\n     * Persist middleware\n     */\n    persist: persister as unknown as StatePersister<T>,\n\n    /**\n     * Rehydrate store\n     */\n    rehydrate: async (): Promise<void> => {\n      // Rehydration is handled internally by the persist middleware\n      isHydrated = true;\n      hydrationListeners.forEach((listener) => listener());\n      return Promise.resolve();\n    },\n\n    /**\n     * Check if hydrated\n     */\n    hasHydrated: () => isHydrated,\n\n    /**\n     * Subscribe to hydration finish\n     */\n    onFinishHydration: (fn: () => void) => {\n      hydrationListeners.push(fn);\n      if (isHydrated) fn();\n      return () => {\n        const index = hydrationListeners.indexOf(fn);\n        if (index > -1) hydrationListeners.splice(index, 1);\n      };\n    },\n\n    /**\n     * Subscribe to hydration\n     */\n    onHydrate: (listener: () => void) => {\n      hydrationListeners.push(listener);\n      if (isHydrated) listener();\n      return () => {\n        const index = hydrationListeners.indexOf(listener);\n        if (index > -1) hydrationListeners.splice(index, 1);\n      };\n    },\n\n    /**\n     * Clear persisted state\n     */\n    clearStorage: () => persister.clear(),\n\n    /**\n     * Get persister instance\n     */\n    getPersister: () => persister,\n  };\n}\n\n// ============================================================================\n// Redux Persist Adapter\n// ============================================================================\n\n/**\n * Redux persist storage adapter\n */\nexport function createReduxPersistStorage(storage: StorageManager = localStorageManager): {\n  getItem: (key: string) => Promise<string | null>;\n  setItem: (key: string, value: string) => Promise<void>;\n  removeItem: (key: string) => void;\n} {\n  return {\n    getItem: async (key: string): Promise<string | null> => {\n      const value = await storage.get<string>(key);\n      return value ?? null;\n    },\n\n    setItem: async (key: string, value: string): Promise<void> => {\n      await storage.set(key, value);\n    },\n\n    removeItem: (key: string): void => {\n      storage.remove(key);\n    },\n  };\n}\n\n/**\n * Create PHI-safe transform for redux-persist\n */\nexport function createPHISafeTransform(phiKeys: string[]): {\n  in: (state: Record<string, unknown>, key: string) => Record<string, unknown> | undefined;\n  out: (state: Record<string, unknown>) => Record<string, unknown>;\n} {\n  return {\n    in: (state: Record<string, unknown>, key: string) => {\n      if (phiKeys.includes(key)) {\n        return undefined;\n      }\n      return state;\n    },\n    out: (state: Record<string, unknown>) => state,\n  };\n}\n\n// ============================================================================\n// Session State Manager\n// ============================================================================\n\n/**\n * Session-scoped state that clears on tab close\n */\nexport class SessionStatePersister<T extends object> extends StatePersister<T> {\n  constructor(config: Omit<PersistConfig<T>, 'storage'>) {\n    super({\n      ...config,\n      // Use session storage instead of local storage\n      storage: new StorageManager(\n        typeof sessionStorage !== 'undefined'\n          ? sessionStorage\n          : {\n              length: 0,\n              key: () => null,\n              getItem: () => null,\n              setItem: () => {},\n              removeItem: () => {},\n              clear: () => {},\n            },\n        { prefix: 'session' }\n      ),\n    });\n  }\n}\n\n// ============================================================================\n// State Snapshot Manager\n// ============================================================================\n\n/**\n * State snapshot for undo/redo or debugging\n */\nexport interface StateSnapshot<T> {\n  id: string;\n  state: T;\n  timestamp: number;\n  label?: string;\n}\n\n/**\n * State snapshot manager for undo/redo functionality\n */\nexport class StateSnapshotManager<T extends object> {\n  private snapshots: StateSnapshot<T>[] = [];\n  private currentIndex = -1;\n  private readonly maxSnapshots: number;\n  private readonly persister: StatePersister<{ snapshots: StateSnapshot<T>[]; currentIndex: number }> | null;\n\n  constructor(\n    key: string,\n    options: {\n      maxSnapshots?: number;\n      persist?: boolean;\n    } = {}\n  ) {\n    this.maxSnapshots = options.maxSnapshots ?? 50;\n\n    if (options.persist === true) {\n      this.persister = new StatePersister({\n        key: `${key}-snapshots`,\n        version: 1,\n      });\n    } else {\n      this.persister = null;\n    }\n  }\n\n  /**\n   * Take a snapshot\n   */\n  snapshot(state: T, label?: string): void {\n    // Remove any snapshots after current index (for redo)\n    if (this.currentIndex < this.snapshots.length - 1) {\n      this.snapshots = this.snapshots.slice(0, this.currentIndex + 1);\n    }\n\n    const snapshot: StateSnapshot<T> = {\n      id: `snapshot-${Date.now()}`,\n      state: structuredClone(state),\n      timestamp: Date.now(),\n      label,\n    };\n\n    this.snapshots.push(snapshot);\n    this.currentIndex = this.snapshots.length - 1;\n\n    // Trim if over max\n    if (this.snapshots.length > this.maxSnapshots) {\n      this.snapshots = this.snapshots.slice(-this.maxSnapshots);\n      this.currentIndex = this.snapshots.length - 1;\n    }\n\n    // Persist if enabled\n    if (this.persister !== null) {\n      void this.persister.persist({\n        snapshots: this.snapshots,\n        currentIndex: this.currentIndex,\n      });\n    }\n  }\n\n  /**\n   * Undo to previous snapshot\n   */\n  undo(): T | null {\n    if (this.currentIndex <= 0) return null;\n\n    this.currentIndex--;\n    const snapshot = this.snapshots[this.currentIndex];\n    return snapshot ? structuredClone(snapshot.state) : null;\n  }\n\n  /**\n   * Redo to next snapshot\n   */\n  redo(): T | null {\n    if (this.currentIndex >= this.snapshots.length - 1) return null;\n\n    this.currentIndex++;\n    const snapshot = this.snapshots[this.currentIndex];\n    return snapshot ? structuredClone(snapshot.state) : null;\n  }\n\n  /**\n   * Check if can undo\n   */\n  canUndo(): boolean {\n    return this.currentIndex > 0;\n  }\n\n  /**\n   * Check if can redo\n   */\n  canRedo(): boolean {\n    return this.currentIndex < this.snapshots.length - 1;\n  }\n\n  /**\n   * Get current snapshot\n   */\n  getCurrent(): StateSnapshot<T> | null {\n    return this.snapshots[this.currentIndex] ?? null;\n  }\n\n  /**\n   * Get all snapshots\n   */\n  getSnapshots(): StateSnapshot<T>[] {\n    return [...this.snapshots];\n  }\n\n  /**\n   * Clear all snapshots\n   */\n  clear(): void {\n    this.snapshots = [];\n    this.currentIndex = -1;\n\n    if (this.persister !== null) {\n      this.persister.clear();\n    }\n  }\n\n  /**\n   * Restore from storage\n   */\n  async restore(): Promise<void> {\n    if (this.persister === null) return;\n\n    const result = await this.persister.rehydrate();\n    if (result.state) {\n      this.snapshots = result.state.snapshots ?? [];\n      this.currentIndex = result.state.currentIndex ?? -1;\n    }\n  }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create a state persister\n */\nexport function createStatePersister<T extends object>(\n  config: PersistConfig<T>\n): StatePersister<T> {\n  return new StatePersister(config);\n}\n\n/**\n * Create a session state persister\n */\nexport function createSessionPersister<T extends object>(\n  config: Omit<PersistConfig<T>, 'storage'>\n): SessionStatePersister<T> {\n  return new SessionStatePersister(config);\n}\n\n/**\n * Create a snapshot manager\n */\nexport function createSnapshotManager<T extends object>(\n  key: string,\n  options?: { maxSnapshots?: number; persist?: boolean }\n): StateSnapshotManager<T> {\n  return new StateSnapshotManager(key, options);\n}\n"],"names":["StatePersister","config","localStorageManager","state","persisted","logger","timeSinceLastPersist","storageError","migratedState","migrated","fromVersion","error","initial","deepMerge","filtered","keys","key","filteredState","StorageQuotaError","toVersion","v","migration","target","source","result","sourceValue","targetValue","isPlainObject","value","createZustandPersist","options","persister","isHydrated","hydrationListeners","listener","fn","index","createReduxPersistStorage","storage","createPHISafeTransform","phiKeys","SessionStatePersister","StorageManager","StateSnapshotManager","label","snapshot","createStatePersister","createSessionPersister","createSnapshotManager"],"mappings":"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"}