{"version":3,"file":"createFeatureStore.mjs","sources":["../../../../src/lib/state/core/createFeatureStore.ts"],"sourcesContent":["/**\n * @file Feature Store Factory\n * @description Create isolated feature stores with registration and lifecycle management\n *\n * Feature stores are scoped to specific features/modules and provide:\n * - Isolation from the global store\n * - Optional persistence with feature-specific keys\n * - Auto-registration with global registry for debugging\n * - Lazy initialization support for code-split features\n */\n\nimport { create, type StateCreator } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { immer } from 'zustand/middleware/immer';\nimport type { EnhancedStore } from './types';\nimport { isDev, devWarn } from '@/lib/core/config/env-helper';\n\n// ============================================================================\n// Feature Store Registry (Global)\n// ============================================================================\n\n/**\n * Global registry for feature stores\n * Enables debugging and cross-feature communication\n */\nclass FeatureStoreRegistryImpl {\n  private stores = new Map<string, unknown>();\n  private metadata = new Map<string, { registeredAt: number; version?: number }>();\n\n  /**\n   * Register a feature store\n   */\n  register<T>(name: string, store: T, version?: number): void {\n    if (this.stores.has(name)) {\n      devWarn(`[FeatureStore] Store \"${name}\" already registered. Replacing.`);\n    }\n    this.stores.set(name, store);\n    this.metadata.set(name, { registeredAt: Date.now(), version });\n  }\n\n  /**\n   * Unregister a feature store\n   */\n  unregister(name: string): boolean {\n    this.metadata.delete(name);\n    return this.stores.delete(name);\n  }\n\n  /**\n   * Get a registered store\n   */\n  getStore<T>(name: string): T | undefined {\n    return this.stores.get(name) as T | undefined;\n  }\n\n  /**\n   * Check if a store is registered\n   */\n  has(name: string): boolean {\n    return this.stores.has(name);\n  }\n\n  /**\n   * Get all registered store names\n   */\n  getNames(): string[] {\n    return Array.from(this.stores.keys());\n  }\n\n  /**\n   * Get metadata for a store\n   */\n  getMetadata(name: string): { version?: number; registeredAt: number } | undefined {\n    return this.metadata.get(name);\n  }\n\n  /**\n   * Reset all feature stores (call their _reset if available)\n   */\n  resetAll(): void {\n    this.stores.forEach((store) => {\n      const typedStore = store as { getState?: () => { _reset?: () => void } };\n      if (typeof typedStore.getState === 'function') {\n        const state = typedStore.getState();\n        if (typeof state._reset === 'function') {\n          state._reset();\n        }\n      }\n    });\n  }\n\n  /**\n   * Clear the registry (does not reset stores)\n   */\n  clear(): void {\n    this.stores.clear();\n    this.metadata.clear();\n  }\n}\n\n/** Global feature store registry instance */\nexport const featureStoreRegistry = new FeatureStoreRegistryImpl();\n\n// ============================================================================\n// Feature Store Configuration\n// ============================================================================\n\n/**\n * Feature store configuration options\n */\nexport interface CreateFeatureStoreConfig<TState> {\n  /** Feature name (used in DevTools and registry) */\n  name: string;\n  /** Persist to storage */\n  persist?: {\n    /** Storage key (defaults to `feature-${name}`) */\n    key?: string;\n    /** State to persist (whitelist) */\n    partialize?: (state: TState) => Partial<TState>;\n    /** Storage version for migrations */\n    version?: number;\n  };\n  /** Register with global store registry (default: true) */\n  register?: boolean;\n  /** Enable DevTools (default: development only) */\n  devtools?: boolean;\n}\n\n// ============================================================================\n// Feature Store Factory\n// ============================================================================\n\n/**\n * Create a feature-scoped store\n *\n * Features:\n * - Immer for immutable updates\n * - DevTools integration with feature namespace\n * - Optional persistence with versioning\n * - Auto-registration with global registry\n *\n * @example\n * ```typescript\n * interface TasksState {\n *   tasks: Task[];\n *   selectedId: string | null;\n * }\n *\n * interface TasksActions {\n *   addTask: (task: Task) => void;\n *   selectTask: (id: string | null) => void;\n * }\n *\n * export const useTasksStore = createFeatureStore<TasksState & TasksActions>(\n *   (set) => ({\n *     tasks: [],\n *     selectedId: null,\n *     addTask: (task) => {\n *       set((state) => { state.tasks.push(task) }, false, { type: 'tasks/addTask' });\n *     },\n *     selectTask: (id) => {\n *       set((state) => { state.selectedId = id }, false, { type: 'tasks/selectTask' });\n *     },\n *   }),\n *   { name: 'tasks', persist: { partialize: (s) => ({ tasks: s.tasks }) } }\n * );\n * ```\n */\nexport function createFeatureStore<TState extends object>(\n  initializer: StateCreator<\n    TState,\n    [['zustand/immer', never], ['zustand/devtools', never]],\n    [],\n    TState\n  >,\n  config: CreateFeatureStoreConfig<TState>\n): EnhancedStore<TState> {\n  const {\n    name,\n    persist: persistConfig,\n    register = true,\n    devtools: enableDevtools = isDev(),\n  } = config;\n\n  const devtoolsName = `Feature/${name}`;\n\n  // Store will be properly typed after creation\n  let store: unknown;\n\n  if (persistConfig !== undefined) {\n    const storageKey = persistConfig.key ?? `feature-${name}`;\n\n    store = create<TState>()(\n      immer(\n        devtools(\n          persist(\n            initializer as StateCreator<\n              TState,\n              [['zustand/immer', never], ['zustand/devtools', never], ['zustand/persist', unknown]],\n              [],\n              TState\n            >,\n            {\n              name: storageKey,\n              partialize: persistConfig.partialize as (state: TState) => Partial<TState>,\n              version: persistConfig.version ?? 1,\n            }\n          ),\n          {\n            name: devtoolsName,\n            enabled: enableDevtools,\n          }\n        )\n      )\n    );\n  } else {\n    store = create<TState>()(\n      immer(\n        devtools(initializer, {\n          name: devtoolsName,\n          enabled: enableDevtools,\n        })\n      )\n    );\n  }\n\n  // Enhance store with feature-specific methods\n  const enhancedStore = store as EnhancedStore<TState>;\n  enhancedStore.featureName = name;\n  enhancedStore.unregister = (): void => {\n    if (register) {\n      featureStoreRegistry.unregister(name);\n    }\n  };\n\n  // Register with global registry\n  if (register) {\n    featureStoreRegistry.register(name, enhancedStore, persistConfig?.version);\n  }\n\n  return enhancedStore;\n}\n\n// ============================================================================\n// Lazy Feature Store\n// ============================================================================\n\n/**\n * Lazy feature store handle\n */\nexport interface LazyFeatureStore<TState extends object> {\n  /** Get or create the store */\n  getStore: () => EnhancedStore<TState>;\n  /** Check if store is initialized */\n  isInitialized: () => boolean;\n  /** Destroy the store and clean up */\n  destroy: () => void;\n  /** Feature name */\n  featureName: string;\n}\n\n/**\n * Create a lazy feature store (only created when first accessed)\n *\n * Use this for code-split features where you don't want to create\n * the store until the feature is actually used.\n *\n * @example\n * ```typescript\n * export const tasksStoreLazy = createLazyFeatureStore<TasksState & TasksActions>(\n *   (set) => ({\n *     tasks: [],\n *     addTask: (task) => set((state) => { state.tasks.push(task) }, false, { type: 'tasks/add' }),\n *   }),\n *   { name: 'tasks' }\n * );\n *\n * // Later, when feature is needed:\n * const store = tasksStoreLazy.getStore();\n * const tasks = store((s) => s.tasks);\n * ```\n */\nexport function createLazyFeatureStore<TState extends object>(\n  initializer: StateCreator<\n    TState,\n    [['zustand/immer', never], ['zustand/devtools', never]],\n    [],\n    TState\n  >,\n  config: CreateFeatureStoreConfig<TState>\n): LazyFeatureStore<TState> {\n  let store: EnhancedStore<TState> | null = null;\n\n  return {\n    featureName: config.name,\n\n    getStore: () => {\n      store ??= createFeatureStore(initializer, config);\n      return store;\n    },\n\n    isInitialized: () => store !== null,\n\n    destroy: () => {\n      if (store) {\n        store.unregister?.();\n        store = null;\n      }\n    },\n  };\n}\n\n// ============================================================================\n// Feature Store Utilities\n// ============================================================================\n\n/**\n * Hook factory for feature store with proper typing\n *\n * @example\n * ```typescript\n * const { useStore, useSelector, useActions } = createFeatureStoreHooks(useTasksStore);\n *\n * // In component:\n * const tasks = useSelector((s) => s.tasks);\n * const { addTask } = useActions();\n * ```\n */\nexport function createFeatureStoreHooks<TState extends object>(\n  useStore: EnhancedStore<TState>\n): {\n  useStore: EnhancedStore<TState>;\n  useSelector: <T>(selector: (state: TState) => T) => T;\n  useActions: <TActions extends Record<string, (...args: never[]) => unknown>>() => TActions;\n} {\n  // Create a stable selector for actions that uses shallow equality\n  // to prevent returning new object references on every render\n  let cachedActions: Record<string, unknown> | null = null;\n  let cachedActionKeys: string[] = [];\n\n  const actionsSelector = (state: TState): Record<string, unknown> => {\n    const actions: Record<string, unknown> = {};\n    const actionKeys: string[] = [];\n\n    for (const key in state) {\n      if (typeof state[key] === 'function') {\n        actions[key] = state[key];\n        actionKeys.push(key);\n      }\n    }\n\n    // Check if actions have changed (same keys and same function references)\n    if (\n      cachedActions !== null &&\n      actionKeys.length === cachedActionKeys.length &&\n      actionKeys.every((key, i) => {\n        const currentCachedActions = cachedActions;\n        return (\n          key === cachedActionKeys[i] &&\n          currentCachedActions != null &&\n          actions[key] === currentCachedActions[key]\n        );\n      })\n    ) {\n      return cachedActions;\n    }\n\n    cachedActions = actions;\n    cachedActionKeys = actionKeys;\n    return actions;\n  };\n\n  return {\n    /** The raw store hook */\n    useStore,\n\n    /** Select a slice of state */\n    useSelector: <T>(selector: (state: TState) => T): T => {\n      return useStore(selector);\n    },\n\n    /** Get all actions (assumes actions are functions on state) */\n    useActions: <TActions extends Record<string, (...args: never[]) => unknown>>(): TActions => {\n      return useStore(actionsSelector) as TActions;\n    },\n  };\n}\n\n/**\n * Subscribe to a feature store outside of React\n *\n * @example\n * ```typescript\n * const unsubscribe = subscribeToFeatureStore(\n *   useTasksStore,\n *   (s) => s.tasks.length,\n *   (count) => console.log(`Task count: ${count}`)\n * );\n * ```\n */\nexport function subscribeToFeatureStore<TState extends object, TSlice>(\n  store: EnhancedStore<TState>,\n  selector: (state: TState) => TSlice,\n  callback: (value: TSlice, prevValue: TSlice) => void\n): () => void {\n  let prevValue = selector(store.getState());\n\n  return store.subscribe((state) => {\n    const nextValue = selector(state);\n    if (!Object.is(nextValue, prevValue)) {\n      callback(nextValue, prevValue);\n      prevValue = nextValue;\n    }\n  });\n}\n"],"names":["FeatureStoreRegistryImpl","name","store","version","devWarn","typedStore","state","featureStoreRegistry","createFeatureStore","initializer","config","persistConfig","register","enableDevtools","isDev","devtoolsName","storageKey","create","immer","devtools","persist","enhancedStore","createLazyFeatureStore","createFeatureStoreHooks","useStore","cachedActions","cachedActionKeys","actionsSelector","actions","actionKeys","key","i","currentCachedActions","selector","subscribeToFeatureStore","callback","prevValue","nextValue"],"mappings":"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"}