{"version":3,"file":"runtime-config.mjs","sources":["../../../src/lib/config/runtime-config.ts"],"sourcesContent":["/**\n * @fileoverview Runtime configuration management with change tracking.\n *\n * Provides runtime configuration capabilities:\n * - Dynamic value updates\n * - Change tracking and history\n * - Event subscriptions\n * - Rollback support\n *\n * @module config/runtime-config\n *\n * @example\n * ```typescript\n * const runtime = new RuntimeConfig(initialConfig);\n *\n * // Subscribe to changes\n * runtime.subscribe((event) => {\n *   console.log('Config changed:', event.changes);\n * });\n *\n * // Update a value\n * runtime.set('feature.enabled', true);\n *\n * // Rollback last change\n * runtime.rollback();\n * ```\n */\n\nimport type {\n  ConfigRecord,\n  ConfigValue,\n  ConfigChange,\n  ConfigEvent,\n  ConfigEventListener,\n  ConfigSourceType,\n} from './types';\nimport { getValueAtPath, setValueAtPath, deleteValueAtPath, hasPath } from './config-merger';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Runtime config options.\n */\nexport interface RuntimeConfigOptions {\n  /** Maximum history entries to keep */\n  readonly maxHistory?: number;\n  /** Enable debug logging */\n  readonly debug?: boolean;\n  /** Whether changes trigger events immediately */\n  readonly immediateEvents?: boolean;\n}\n\n/**\n * History entry for rollback.\n */\ninterface HistoryEntry {\n  readonly changes: ConfigChange[];\n  readonly timestamp: Date;\n}\n\n// ============================================================================\n// Runtime Config\n// ============================================================================\n\n/**\n * Runtime configuration manager with change tracking.\n */\nexport class RuntimeConfig<T extends ConfigRecord = ConfigRecord> {\n  private config: T;\n  private listeners = new Set<ConfigEventListener>();\n  private history: HistoryEntry[] = [];\n  private options: Required<RuntimeConfigOptions>;\n  private pendingChanges: ConfigChange[] = [];\n  private batchMode = false;\n\n  constructor(initialConfig: T, options: RuntimeConfigOptions = {}) {\n    this.config = { ...initialConfig };\n    this.options = {\n      maxHistory: options.maxHistory ?? 50,\n      debug: options.debug ?? false,\n      immediateEvents: options.immediateEvents ?? true,\n    };\n  }\n\n  // ==========================================================================\n  // Getters\n  // ==========================================================================\n\n  /**\n   * Get the current configuration.\n   */\n  getConfig(): T {\n    return { ...this.config };\n  }\n\n  /**\n   * Get a value at a path.\n   */\n  get<V = ConfigValue>(path: string, defaultValue?: V): V {\n    return getValueAtPath<V>(this.config, path, defaultValue);\n  }\n\n  /**\n   * Check if a path exists.\n   */\n  has(path: string): boolean {\n    return hasPath(this.config, path);\n  }\n\n  // ==========================================================================\n  // Setters\n  // ==========================================================================\n\n  /**\n   * Set a value at a path.\n   */\n  set(path: string, value: ConfigValue, source: ConfigSourceType = 'runtime'): void {\n    const previousValue = getValueAtPath(this.config, path);\n\n    if (JSON.stringify(previousValue) === JSON.stringify(value)) {\n      return; // No change\n    }\n\n    this.config = setValueAtPath(this.config, path, value) as T;\n\n    const change: ConfigChange = {\n      path,\n      previousValue,\n      newValue: value,\n      source,\n      timestamp: new Date(),\n    };\n\n    if (this.batchMode) {\n      this.pendingChanges.push(change);\n    } else {\n      this.recordChange([change]);\n      if (this.options.immediateEvents) {\n        this.emitEvent({ type: 'change', changes: [change], timestamp: new Date() });\n      }\n    }\n\n    this.log(`Set ${path} = ${JSON.stringify(value)}`);\n  }\n\n  /**\n   * Delete a value at a path.\n   */\n  delete(path: string, source: ConfigSourceType = 'runtime'): void {\n    if (!hasPath(this.config, path)) {\n      return;\n    }\n\n    const previousValue = getValueAtPath(this.config, path);\n    this.config = deleteValueAtPath(this.config, path) as T;\n\n    const change: ConfigChange = {\n      path,\n      previousValue,\n      newValue: undefined as unknown as ConfigValue,\n      source,\n      timestamp: new Date(),\n    };\n\n    if (this.batchMode) {\n      this.pendingChanges.push(change);\n    } else {\n      this.recordChange([change]);\n      if (this.options.immediateEvents) {\n        this.emitEvent({ type: 'change', changes: [change], timestamp: new Date() });\n      }\n    }\n\n    this.log(`Deleted ${path}`);\n  }\n\n  /**\n   * Update multiple values at once.\n   */\n  update(updates: Record<string, ConfigValue>, source: ConfigSourceType = 'runtime'): void {\n    this.batch(() => {\n      for (const [path, value] of Object.entries(updates)) {\n        this.set(path, value, source);\n      }\n    });\n  }\n\n  /**\n   * Reset to a new configuration.\n   */\n  reset(config: T): void {\n    const previousConfig = this.config;\n    this.config = { ...config };\n\n    this.recordChange([\n      {\n        path: '',\n        previousValue: previousConfig,\n        newValue: config,\n        source: 'runtime',\n        timestamp: new Date(),\n      },\n    ]);\n\n    this.emitEvent({\n      type: 'reload',\n      changes: [\n        {\n          path: '',\n          previousValue: previousConfig,\n          newValue: config,\n          source: 'runtime',\n          timestamp: new Date(),\n        },\n      ],\n      timestamp: new Date(),\n    });\n\n    this.log('Configuration reset');\n  }\n\n  // ==========================================================================\n  // Batch Operations\n  // ==========================================================================\n\n  /**\n   * Start a batch of changes.\n   */\n  startBatch(): void {\n    this.batchMode = true;\n    this.pendingChanges = [];\n  }\n\n  /**\n   * Commit the current batch.\n   */\n  commitBatch(): void {\n    if (!this.batchMode) {\n      return;\n    }\n\n    const changes = [...this.pendingChanges];\n    this.batchMode = false;\n    this.pendingChanges = [];\n\n    if (changes.length > 0) {\n      this.recordChange(changes);\n      this.emitEvent({ type: 'change', changes, timestamp: new Date() });\n    }\n  }\n\n  /**\n   * Rollback the current batch.\n   */\n  rollbackBatch(): void {\n    if (!this.batchMode) {\n      return;\n    }\n\n    // Reverse the pending changes\n    for (let i = this.pendingChanges.length - 1; i >= 0; i--) {\n      const change = this.pendingChanges[i];\n      if (change == null) continue;\n      if (change.previousValue !== undefined) {\n        this.config = setValueAtPath(this.config, change.path, change.previousValue) as T;\n      } else {\n        this.config = deleteValueAtPath(this.config, change.path) as T;\n      }\n    }\n\n    this.batchMode = false;\n    this.pendingChanges = [];\n    this.log('Batch rolled back');\n  }\n\n  /**\n   * Execute a function in batch mode.\n   */\n  batch(fn: () => void): void {\n    this.startBatch();\n    try {\n      fn();\n      this.commitBatch();\n    } catch (error) {\n      this.rollbackBatch();\n      throw error;\n    }\n  }\n\n  // ==========================================================================\n  // History and Rollback\n  // ==========================================================================\n\n  /**\n   * Rollback the last change.\n   */\n  rollback(): boolean {\n    if (this.history.length === 0) {\n      return false;\n    }\n\n    const entry = this.history.pop();\n    if (entry == null) {\n      return false;\n    }\n\n    // Reverse the changes\n    for (let i = entry.changes.length - 1; i >= 0; i--) {\n      const change = entry.changes[i];\n      if (change == null) continue;\n      if (change.previousValue !== undefined) {\n        this.config = setValueAtPath(this.config, change.path, change.previousValue) as T;\n      } else {\n        this.config = deleteValueAtPath(this.config, change.path) as T;\n      }\n    }\n\n    this.log(`Rolled back ${entry.changes.length} changes`);\n    return true;\n  }\n\n  /**\n   * Get the change history.\n   */\n  getHistory(): readonly HistoryEntry[] {\n    return [...this.history];\n  }\n\n  /**\n   * Clear the change history.\n   */\n  clearHistory(): void {\n    this.history = [];\n  }\n\n  /**\n   * Subscribe to configuration events.\n   */\n  subscribe(listener: ConfigEventListener): () => void {\n    this.listeners.add(listener);\n    return () => {\n      this.listeners.delete(listener);\n    };\n  }\n\n  // ==========================================================================\n  // Subscriptions\n  // ==========================================================================\n\n  /**\n   * Subscribe to changes at a specific path.\n   */\n  subscribeToPath(\n    path: string,\n    listener: (value: ConfigValue, change: ConfigChange) => void\n  ): () => void {\n    const wrappedListener: ConfigEventListener = (event) => {\n      if (event.type !== 'change' || !event.changes) {\n        return;\n      }\n\n      for (const change of event.changes) {\n        if (change.path === path || change.path.startsWith(`${path}.`)) {\n          listener(getValueAtPath(this.config, path), change);\n        }\n      }\n    };\n\n    return this.subscribe(wrappedListener);\n  }\n\n  /**\n   * Create a snapshot of the current configuration.\n   */\n  snapshot(): T {\n    return JSON.parse(JSON.stringify(this.config)) as T;\n  }\n\n  /**\n   * Restore from a snapshot.\n   */\n  restore(snapshot: T): void {\n    this.reset(snapshot);\n  }\n\n  // ==========================================================================\n  // Utilities\n  // ==========================================================================\n\n  private recordChange(changes: ConfigChange[]): void {\n    this.history.push({\n      changes,\n      timestamp: new Date(),\n    });\n\n    // Trim history if needed\n    while (this.history.length > this.options.maxHistory) {\n      this.history.shift();\n    }\n  }\n\n  private emitEvent(event: ConfigEvent): void {\n    for (const listener of this.listeners) {\n      try {\n        listener(event);\n      } catch (error) {\n        this.log('Error in event listener:', error);\n      }\n    }\n  }\n\n  private log(message: string, ...args: unknown[]): void {\n    if (this.options.debug) {\n      console.info(`[RuntimeConfig] ${message}`, ...args);\n    }\n  }\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create a runtime config instance.\n */\nexport function createRuntimeConfig<T extends ConfigRecord>(\n  initialConfig: T,\n  options?: RuntimeConfigOptions\n): RuntimeConfig<T> {\n  return new RuntimeConfig(initialConfig, options);\n}\n\n// ============================================================================\n// Singleton Instance\n// ============================================================================\n\nlet instance: RuntimeConfig | null = null;\n\n/**\n * Get the singleton runtime config instance.\n */\nexport function getRuntimeConfig<T extends ConfigRecord = ConfigRecord>(): RuntimeConfig<T> {\n  instance ??= new RuntimeConfig({});\n  return instance as RuntimeConfig<T>;\n}\n\n/**\n * Initialize the singleton with a configuration.\n */\nexport function initRuntimeConfig<T extends ConfigRecord>(\n  config: T,\n  options?: RuntimeConfigOptions\n): RuntimeConfig<T> {\n  instance = new RuntimeConfig(config, options);\n  return instance as RuntimeConfig<T>;\n}\n\n/**\n * Reset the singleton instance.\n */\nexport function resetRuntimeConfig(): void {\n  instance = null;\n}\n"],"names":["RuntimeConfig","initialConfig","options","path","defaultValue","getValueAtPath","hasPath","value","source","previousValue","setValueAtPath","change","deleteValueAtPath","updates","config","previousConfig","changes","i","fn","error","entry","listener","wrappedListener","event","snapshot","message","args","createRuntimeConfig","instance","getRuntimeConfig","initRuntimeConfig","resetRuntimeConfig"],"mappings":"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"}