{"version":3,"file":"ConfigProvider.mjs","sources":["../../../src/lib/config/ConfigProvider.tsx"],"sourcesContent":["/**\n * @fileoverview React configuration provider component.\n *\n * Provides configuration context to the React component tree with:\n * - Async configuration loading\n * - Error handling\n * - Hot reload support\n * - SSR compatibility\n *\n * @module config/ConfigProvider\n *\n * @example\n * ```tsx\n * <ConfigProvider\n *   config={defaultConfig}\n *   schema={configSchema}\n *   envPrefix=\"REACT_APP_\"\n * >\n *   <App />\n * </ConfigProvider>\n * ```\n */\n\nimport React, {\n  createContext,\n  useContext,\n  useState,\n  useEffect,\n  useCallback,\n  useMemo,\n  type ReactNode,\n} from 'react';\nimport type { ConfigRecord, ConfigValue, ConfigSchema } from './types';\nimport { ConfigLoader } from './config-loader';\nimport { RuntimeConfig } from './runtime-config';\nimport { getValueAtPath, hasPath } from './config-merger';\n\n// ============================================================================\n// Context\n// ============================================================================\n\n/**\n * Config context value type\n */\nexport interface ConfigContextValue<T extends ConfigRecord = ConfigRecord> {\n  config: T;\n  get: <V = ConfigValue>(path: string, defaultValue?: V) => V;\n  set: (path: string, value: ConfigValue) => void;\n  has: (path: string) => boolean;\n  reset: () => void;\n  reload: () => Promise<void>;\n  subscribe: (\n    listener: (event: import('../contexts/ConfigContext').ConfigChangeEvent) => void\n  ) => () => void;\n  isLoading: boolean;\n  error: Error | null;\n}\n\nconst ConfigContext = createContext<ConfigContextValue | null>(null);\n\n// ============================================================================\n// Provider Props\n// ============================================================================\n\n/**\n * Props for ConfigProvider component.\n */\nexport interface ConfigProviderProps<T extends ConfigRecord = ConfigRecord> {\n  /** Child components */\n  children: ReactNode;\n  /** Default configuration values */\n  config: T;\n  /** Configuration schema for validation */\n  schema?: ConfigSchema;\n  /** Environment variable prefix */\n  envPrefix?: string;\n  /** Remote configuration URL */\n  remoteUrl?: string;\n  /** Loading component */\n  loadingComponent?: ReactNode;\n  /** Error component */\n  errorComponent?: (error: Error) => ReactNode;\n  /** Enable debug logging */\n  debug?: boolean;\n  /** Called when configuration is loaded */\n  onLoad?: (config: T) => void;\n  /** Called when configuration changes */\n  onChange?: (config: T) => void;\n  /** Called on configuration error */\n  onError?: (error: Error) => void;\n}\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\n/**\n * Configuration provider component.\n */\nexport function ConfigProvider<T extends ConfigRecord = ConfigRecord>({\n  children,\n  config: defaultConfig,\n  schema,\n  envPrefix,\n  remoteUrl,\n  loadingComponent,\n  errorComponent,\n  debug = false,\n  onLoad,\n  onChange,\n  onError,\n}: ConfigProviderProps<T>): React.JSX.Element {\n  const [config, setConfig] = useState<T>(defaultConfig);\n  const [isLoading, setIsLoading] = useState(true);\n  const [error, setError] = useState<Error | null>(null);\n\n  // Create runtime config for dynamic updates\n  const runtimeConfig = useMemo(\n    () => new RuntimeConfig(defaultConfig, { debug }),\n    [defaultConfig, debug]\n  );\n\n  // Load configuration\n  useEffect(() => {\n    const loadConfig = async (): Promise<void> => {\n      setIsLoading(true);\n      setError(null);\n\n      try {\n        const loader = new ConfigLoader({\n          envPrefix,\n          remoteUrl,\n          debug,\n        });\n\n        loader.addDefaultSource(defaultConfig);\n\n        if (envPrefix != null && envPrefix !== '') {\n          loader.addEnvSource();\n        }\n\n        if (remoteUrl != null && remoteUrl !== '') {\n          await loader.addRemoteSource({ url: remoteUrl });\n        }\n\n        if (schema) {\n          loader.setSchema(schema);\n        }\n\n        const loadedConfig = await loader.load();\n        setConfig(loadedConfig as T);\n        runtimeConfig.reset(loadedConfig as T);\n        onLoad?.(loadedConfig as T);\n\n        if (debug === true) {\n          console.info('[ConfigProvider] Configuration loaded:', loadedConfig);\n        }\n      } catch (err) {\n        const error = err instanceof Error ? err : new Error(String(err));\n        setError(error);\n        onError?.(error);\n\n        if (debug) {\n          console.error('[ConfigProvider] Failed to load configuration:', error);\n        }\n      } finally {\n        setIsLoading(false);\n      }\n    };\n\n    void loadConfig();\n  }, [defaultConfig, envPrefix, remoteUrl, schema, debug, onLoad, onError, runtimeConfig]);\n\n  // Subscribe to runtime config changes\n  useEffect(() => {\n    return runtimeConfig.subscribe((event) => {\n      if (event.type === 'change' || event.type === 'reload') {\n        const newConfig = runtimeConfig.getConfig();\n        setConfig(newConfig);\n        onChange?.(newConfig);\n      }\n    });\n  }, [runtimeConfig, onChange]);\n\n  // Get value at path\n  const get = useCallback(\n    <V = ConfigValue,>(path: string, defaultValue?: V): V => {\n      return getValueAtPath<V>(config, path, defaultValue);\n    },\n    [config]\n  );\n\n  // Check if path exists\n  const has = useCallback(\n    (path: string): boolean => {\n      return hasPath(config, path);\n    },\n    [config]\n  );\n\n  // Set value at path\n  const set = useCallback(\n    (path: string, value: ConfigValue): void => {\n      runtimeConfig.set(path, value);\n    },\n    [runtimeConfig]\n  );\n\n  // Reset to defaults\n  const reset = useCallback(() => {\n    runtimeConfig.reset(defaultConfig);\n  }, [runtimeConfig, defaultConfig]);\n\n  // Reload configuration\n  const reload = useCallback(async (): Promise<void> => {\n    setIsLoading(true);\n    setError(null);\n\n    try {\n      const loader = new ConfigLoader({ envPrefix, remoteUrl, debug });\n      loader.addDefaultSource(defaultConfig);\n\n      if (envPrefix != null && envPrefix !== '') {\n        loader.addEnvSource();\n      }\n\n      if (remoteUrl != null && remoteUrl !== '') {\n        await loader.addRemoteSource({ url: remoteUrl });\n      }\n\n      if (schema) {\n        loader.setSchema(schema);\n      }\n\n      const loadedConfig = await loader.load();\n      setConfig(loadedConfig as T);\n      runtimeConfig.reset(loadedConfig as T);\n    } catch (err) {\n      const error = err instanceof Error ? err : new Error(String(err));\n      setError(error);\n      onError?.(error);\n    } finally {\n      setIsLoading(false);\n    }\n  }, [defaultConfig, envPrefix, remoteUrl, schema, debug, onError, runtimeConfig]);\n\n  // Subscribe to changes\n  const subscribe = useCallback(\n    (\n      listener: (event: import('../contexts/ConfigContext').ConfigChangeEvent) => void\n    ): (() => void) => {\n      return runtimeConfig.subscribe((event) => {\n        // Convert ConfigEvent to ConfigChangeEvent\n        // Map event types: 'error' events are not exposed to the context listener\n        if (event.type === 'change' || event.type === 'reload') {\n          const mappedChanges =\n            event.type === 'change' && event.changes\n              ? event.changes.map((c) => ({\n                  path: c.path,\n                  oldValue: c.previousValue ?? null,\n                  newValue: c.newValue,\n                }))\n              : undefined;\n          listener({\n            type: event.type === 'reload' ? 'reload' : 'change',\n            changes: mappedChanges,\n          });\n        }\n      });\n    },\n    [runtimeConfig]\n  );\n\n  // Context value\n  const value: ConfigContextValue<T> = useMemo(\n    () => ({\n      config,\n      isLoading,\n      error,\n      get,\n      has,\n      set,\n      reset,\n      reload,\n      subscribe,\n    }),\n    [config, isLoading, error, get, has, set, reset, reload, subscribe]\n  );\n\n  // Render loading state\n  if (isLoading && loadingComponent != null) {\n    return <>{loadingComponent}</>;\n  }\n\n  // Render error state\n  if (error != null && errorComponent != null) {\n    return <>{errorComponent(error)}</>;\n  }\n\n  return (\n    <ConfigContext.Provider value={value as ConfigContextValue}>{children}</ConfigContext.Provider>\n  );\n}\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to access the configuration context.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useConfigContext<T extends ConfigRecord = ConfigRecord>(): ConfigContextValue<T> {\n  const context = useContext(ConfigContext);\n  if (context == null) {\n    throw new Error('useConfigContext must be used within a ConfigProvider');\n  }\n  return context as ConfigContextValue<T>;\n}\n\n/**\n * Hook to access configuration context optionally.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useOptionalConfigContext<\n  T extends ConfigRecord = ConfigRecord,\n>(): ConfigContextValue<T> | null {\n  return useContext(ConfigContext) as ConfigContextValue<T> | null;\n}\n\n// ============================================================================\n// HOC\n// ============================================================================\n\n/**\n * HOC to inject configuration as props.\n */\n// eslint-disable-next-line react-refresh/only-export-components\nexport function withConfig<P extends object, T extends ConfigRecord = ConfigRecord>(\n  Component: React.ComponentType<P & { config: ConfigContextValue<T> }>\n): React.FC<P> {\n  return function WithConfig(props: P) {\n    const config = useConfigContext<T>();\n    return <Component {...props} config={config} />;\n  };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport { ConfigContext };\n"],"names":["ConfigContext","createContext","ConfigProvider","children","defaultConfig","schema","envPrefix","remoteUrl","loadingComponent","errorComponent","debug","onLoad","onChange","onError","config","setConfig","useState","isLoading","setIsLoading","error","setError","runtimeConfig","useMemo","RuntimeConfig","useEffect","loader","ConfigLoader","loadedConfig","err","event","newConfig","get","useCallback","path","defaultValue","getValueAtPath","has","hasPath","set","value","reset","reload","subscribe","listener","mappedChanges","c","jsx","Fragment","useConfigContext","context","useContext","useOptionalConfigContext","withConfig","Component","props"],"mappings":"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"}