{"version":3,"file":"store.mjs","sources":["../../../src/lib/state/store.ts"],"sourcesContent":["/**\n * @file Main Store\n * @description Global Zustand store with enterprise-grade middleware stack\n *\n * This is the main store composition file that combines all slices with\n * the production middleware stack: Immer + DevTools + SubscribeWithSelector + Persist\n *\n * Middleware Order (inside-out):\n * 1. immer - Enables immutable updates with mutable syntax\n * 2. devtools - Redux DevTools integration with named actions\n * 3. subscribeWithSelector - Granular subscriptions for performance\n * 4. persist - State persistence to localStorage\n */\n\nimport { create, type StateCreator } from 'zustand';\nimport { devtools, subscribeWithSelector, persist } from 'zustand/middleware';\nimport { immer } from 'zustand/middleware/immer';\nimport { uiSlice, type UISlice } from './slices/uiSlice';\nimport { sessionSlice, type SessionSlice } from './slices/sessionSlice';\nimport { settingsSlice, type SettingsSlice } from './slices/settingsSlice';\nimport { isDebugModeEnabled } from '../flags/debug-mode';\n\n// ============================================================================\n// Store Types\n// ============================================================================\n\n/**\n * Combined store state type\n */\nexport type StoreState = UISlice & SessionSlice & SettingsSlice & HydrationState;\n\n/**\n * Hydration state for SSR compatibility\n */\ninterface HydrationState {\n  _hasHydrated: boolean;\n  _setHasHydrated: (hydrated: boolean) => void;\n}\n\n/**\n * Store selector type helper\n */\nexport type StoreSelector<T> = (state: StoreState) => T;\n\n// ============================================================================\n// Persistence Configuration\n// ============================================================================\n\n/**\n * Current store version (increment when making breaking changes)\n */\nconst STORE_VERSION = 4;\n\n/**\n * State to persist (whitelist approach for security and performance)\n *\n * DO NOT persist:\n * - Session data (security - should be re-validated on reload)\n * - Modal state (transient UI)\n * - Loading state (transient UI)\n * - Toasts (transient UI)\n */\nconst persistedState = (state: StoreState): Partial<StoreState> => ({\n  // UI preferences (user experience)\n  sidebarOpen: state.sidebarOpen,\n  sidebarCollapsed: state.sidebarCollapsed,\n  layoutDensity: state.layoutDensity,\n  animationsEnabled: state.animationsEnabled,\n\n  // Settings (all persisted for user preferences)\n  locale: state.locale,\n  timezone: state.timezone,\n  dateFormat: state.dateFormat,\n  timeFormat: state.timeFormat,\n  numberFormat: state.numberFormat,\n  theme: state.theme,\n  notificationsEnabled: state.notificationsEnabled,\n  soundEnabled: state.soundEnabled,\n  desktopNotifications: state.desktopNotifications,\n  emailNotifications: state.emailNotifications,\n  reducedMotion: state.reducedMotion,\n  highContrast: state.highContrast,\n  fontSize: state.fontSize,\n  keyboardShortcutsEnabled: state.keyboardShortcutsEnabled,\n  features: state.features,\n  analyticsEnabled: state.analyticsEnabled,\n  crashReportingEnabled: state.crashReportingEnabled,\n});\n\n/**\n * State migrations for version upgrades\n */\nconst migrations: Record<number, (state: unknown) => unknown> = {\n  // Version 1 -> 2: Add layoutDensity\n  2: (state: unknown) => ({\n    ...(state as object),\n    layoutDensity: 'comfortable',\n  }),\n\n  // Version 2 -> 3: Add keyboard shortcuts and animations\n  3: (state: unknown) => ({\n    ...(state as object),\n    keyboardShortcutsEnabled: true,\n    animationsEnabled: true,\n  }),\n\n  // Version 3 -> 4: Add theme and email notifications\n  4: (state: unknown) => ({\n    ...(state as object),\n    theme: 'system',\n    emailNotifications: true,\n    analyticsEnabled: true,\n    crashReportingEnabled: true,\n  }),\n};\n\n/**\n * Run migrations from persisted version to current version\n */\nfunction migrate(persistedState: unknown, version: number): StoreState {\n  let state = persistedState;\n\n  // Run each migration in sequence\n  for (let v = version + 1; v <= STORE_VERSION; v++) {\n    const migration = migrations[v];\n    if (migration) {\n      state = migration(state);\n    }\n  }\n\n  return state as StoreState;\n}\n\n// ============================================================================\n// Middleware Type Definitions\n// ============================================================================\n\n/**\n * Full middleware stack type for proper TypeScript inference\n */\ntype FullMiddleware = [\n  ['zustand/immer', never],\n  ['zustand/devtools', never],\n  ['zustand/subscribeWithSelector', never],\n  ['zustand/persist', unknown],\n];\n\n// ============================================================================\n// Store Creation\n// ============================================================================\n\n/**\n * Slice creator arguments type for composing store slices\n */\ntype SliceCreatorArgs = Parameters<StateCreator<StoreState, FullMiddleware>>;\n\n/**\n * Combined store creator that composes all slices\n */\nconst storeCreator: StateCreator<StoreState, FullMiddleware> = (...args: SliceCreatorArgs) => {\n  // Cast args to the expected slice parameters - this is safe as all slices\n  // use the same StateCreator pattern with compatible argument types\n  const sliceArgs = args as unknown as Parameters<typeof uiSlice>;\n  const ui = uiSlice(...sliceArgs);\n  const session = sessionSlice(...(sliceArgs as unknown as Parameters<typeof sessionSlice>));\n  const settings = settingsSlice(...(sliceArgs as unknown as Parameters<typeof settingsSlice>));\n\n  return {\n    // Compose slices\n    ...ui,\n    ...session,\n    ...settings,\n\n    // Hydration tracking (for SSR compatibility)\n    _hasHydrated: false,\n    _setHasHydrated: (hydrated: boolean) => {\n      const [set] = args;\n      set(\n        (state) => {\n          state._hasHydrated = hydrated;\n        },\n        false,\n        { type: '@@HYDRATION/SET_HYDRATED' }\n      );\n    },\n  };\n};\n\n/**\n * Global store instance\n *\n * The middleware stack (applied inside-out):\n * 1. immer: Enables writing \"mutating\" logic in reducers\n * 2. devtools: Connects to Redux DevTools for debugging\n * 3. subscribeWithSelector: Enables selector-based subscriptions\n * 4. persist: Persists state to localStorage with migrations\n */\nexport const useStore = create<StoreState>()(\n  immer(\n    devtools(\n      subscribeWithSelector(\n        persist(storeCreator, {\n          name: 'app-store',\n          version: STORE_VERSION,\n          partialize: persistedState,\n          migrate,\n          onRehydrateStorage: () => (state) => {\n            // Called when hydration completes\n            if (state) {\n              state._setHasHydrated(true);\n            }\n          },\n        })\n      ),\n      {\n        name: 'AppStore',\n        enabled: isDebugModeEnabled(),\n        trace: true,\n        traceLimit: 25,\n      }\n    )\n  )\n);\n\n// ============================================================================\n// Store Utilities\n// ============================================================================\n\n/**\n * Get a snapshot of the current store state (for use outside React)\n *\n * @example\n * ```typescript\n * const currentLocale = getStoreState().locale;\n * ```\n */\nexport function getStoreState(): StoreState {\n  return useStore.getState();\n}\n\n/**\n * Subscribe to store changes with selector (for use outside React)\n *\n * @example\n * ```typescript\n * const unsubscribe = subscribeToStore(\n *   (state) => state.locale,\n *   (newLocale, prevLocale) => {\n *     console.log('Locale changed:', prevLocale, '->', newLocale);\n *   }\n * );\n * ```\n */\nexport function subscribeToStore<T>(\n  selector: StoreSelector<T>,\n  callback: (value: T, prevValue: T) => void\n): () => void {\n  return useStore.subscribe(selector, callback);\n}\n\n/**\n * Check if store has hydrated from persistence\n */\nexport function hasStoreHydrated(): boolean {\n  return useStore.getState()._hasHydrated;\n}\n\n/**\n * Wait for store hydration to complete\n *\n * @param timeoutMs - Maximum time to wait for hydration (default: 5000ms)\n * @returns true if hydration completed, false if timeout occurred\n *\n * @example\n * ```typescript\n * const hydrated = await waitForHydration();\n * if (hydrated) {\n *   // Store is now hydrated, safe to read persisted values\n * } else {\n *   // Timeout occurred, handle gracefully\n * }\n * ```\n */\nexport async function waitForHydration(timeoutMs = 5000): Promise<boolean> {\n  return new Promise((resolve) => {\n    if (hasStoreHydrated()) {\n      resolve(true);\n      return;\n    }\n\n    let timeoutId: ReturnType<typeof setTimeout> | null = null;\n    let unsubscribe: (() => void) | null = null;\n\n    const cleanup = (): void => {\n      if (timeoutId !== null) {\n        clearTimeout(timeoutId);\n        timeoutId = null;\n      }\n      if (unsubscribe !== null) {\n        unsubscribe();\n        unsubscribe = null;\n      }\n    };\n\n    // Set up timeout to prevent infinite hanging\n    timeoutId = setTimeout(() => {\n      cleanup();\n      console.warn(\n        `[Store] waitForHydration timed out after ${timeoutMs}ms. ` +\n          'This may indicate a persistence configuration issue.'\n      );\n      resolve(false);\n    }, timeoutMs);\n\n    unsubscribe = useStore.subscribe(\n      (state) => state._hasHydrated,\n      (hydrated) => {\n        if (hydrated) {\n          cleanup();\n          resolve(true);\n        }\n      }\n    );\n  });\n}\n\n/**\n * Reset store to initial state (useful for logout)\n *\n * This will:\n * - End the session\n * - Close all modals\n * - Clear toasts\n * - Stop any loading states\n *\n * Note: Settings are preserved by default (user preferences)\n *\n * @param clearSettings - Also reset settings to defaults\n */\nexport function resetStore(clearSettings = false): void {\n  const state = useStore.getState();\n\n  // End session\n  state.endSession();\n\n  // Reset UI state\n  state.closeAllModals();\n  state.clearToasts();\n  state.setGlobalLoading(false);\n\n  // Optionally reset settings\n  if (clearSettings) {\n    state.resetSettings();\n  }\n}\n\n/**\n * Clear persisted store data from localStorage\n *\n * Use with caution - this removes all persisted state\n */\nexport function clearPersistedStore(): void {\n  if (typeof localStorage !== 'undefined') {\n    localStorage.removeItem('app-store');\n  }\n}\n\n// ============================================================================\n// Feature Store Registry\n// ============================================================================\n\ntype FeatureStore = ReturnType<typeof create>;\n\nconst featureStores = new Map<string, FeatureStore>();\n\n/**\n * Register a feature store with the global registry\n *\n * @example\n * ```typescript\n * const useReportsStore = createFeatureStore(...);\n * registerFeatureStore('reports', useReportsStore);\n * ```\n */\nexport function registerFeatureStore(name: string, store: FeatureStore): void {\n  if (featureStores.has(name)) {\n    console.warn(`[Store] Feature store \"${name}\" already registered, replacing...`);\n  }\n  featureStores.set(name, store);\n}\n\n/**\n * Unregister a feature store from the global registry\n */\nexport function unregisterFeatureStore(name: string): void {\n  featureStores.delete(name);\n}\n\n/**\n * Get a feature store by name\n */\nexport function getFeatureStore<T>(name: string): T | undefined {\n  return featureStores.get(name) as T | undefined;\n}\n\n/**\n * Get all registered feature store names\n */\nexport function getFeatureStoreNames(): string[] {\n  return Array.from(featureStores.keys());\n}\n\n/**\n * Reset all feature stores that have a reset method\n *\n * @param clearRegistry - Also clear the feature store registry (default: true)\n *                       Set to false if you want to keep stores registered but reset\n */\nexport function resetAllFeatureStores(clearRegistry = true): void {\n  featureStores.forEach((store, _name) => {\n    // Type the store's getState method properly\n    type StoreWithReset = { reset?: () => void; _reset?: () => void };\n    const state = (store as unknown as { getState: () => StoreWithReset }).getState();\n    if (typeof state.reset === 'function') {\n      state.reset();\n    } else if (typeof state._reset === 'function') {\n      state._reset();\n    }\n  });\n\n  // Clear the registry to prevent memory leaks from orphaned store references\n  if (clearRegistry) {\n    featureStores.clear();\n  }\n}\n\n// ============================================================================\n// Development Helpers\n// ============================================================================\n\n// Expose store to window when debug mode is enabled for debugging\nif (isDebugModeEnabled() && typeof window !== 'undefined') {\n  (window as unknown as { __STORE__: typeof useStore }).__STORE__ = useStore;\n}\n"],"names":["STORE_VERSION","persistedState","state","migrations","migrate","version","v","migration","storeCreator","args","sliceArgs","ui","uiSlice","session","sessionSlice","settings","settingsSlice","hydrated","set","useStore","create","immer","devtools","subscribeWithSelector","persist","isDebugModeEnabled","getStoreState","subscribeToStore","selector","callback","hasStoreHydrated","waitForHydration","timeoutMs","resolve","timeoutId","unsubscribe","cleanup","resetStore","clearSettings","clearPersistedStore","featureStores","registerFeatureStore","name","store","unregisterFeatureStore","getFeatureStore","getFeatureStoreNames","resetAllFeatureStores","clearRegistry","_name"],"mappings":"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"}