{"version":3,"sources":["../src/monitoring.ts"],"sourcesContent":["import type { SecretManager } from './manager';\nimport type { SecretStore } from './storage';\n\nexport type HealthStatus = {\n  overall: 'healthy' | 'degraded' | 'unhealthy';\n  components: {\n    storage: ComponentHealth;\n    encryption: ComponentHealth;\n    audit: ComponentHealth;\n    rotation?: ComponentHealth;\n  };\n  metrics: SystemMetrics;\n  lastChecked: Date;\n};\n\nexport type ComponentHealth = {\n  status: 'healthy' | 'degraded' | 'unhealthy';\n  message?: string;\n  details?: Record<string, unknown>;\n};\n\nexport type SystemMetrics = {\n  totalSecrets: number;\n  activeSecrets: number;\n  expiredSecrets: number;\n  secretsByTenant: Record<string, number>;\n  averageSecretAge: number; // in days\n  rotationCompliance: number; // percentage\n  auditEventsLast24h: number;\n  failedOperations: number;\n  storageLatency: number; // in ms\n};\n\nexport type AlertRule = {\n  id: string;\n  name: string;\n  condition: (metrics: SystemMetrics) => boolean;\n  severity: 'info' | 'warning' | 'error' | 'critical';\n  message: string;\n  enabled: boolean;\n};\n\nexport class HealthMonitor {\n  private alertRules: AlertRule[] = [];\n  private metricsHistory: SystemMetrics[] = [];\n  private lastHealthCheck?: HealthStatus;\n\n  constructor(\n    private readonly manager: SecretManager,\n    private readonly store: SecretStore,\n    private readonly config: {\n      healthCheckIntervalMs: number;\n      metricsRetentionHours: number;\n      alertWebhook?: string;\n    }\n  ) {\n    this.initializeDefaultAlertRules();\n  }\n\n  async checkHealth(): Promise<HealthStatus> {\n    const components: HealthStatus['components'] = {\n      storage: this.checkStorageHealth(),\n      encryption: this.checkEncryptionHealth(),\n      audit: this.checkAuditHealth(),\n    };\n\n    const metrics = this.collectMetrics();\n    const overall = this.determineOverallHealth(components);\n\n    const healthStatus: HealthStatus = {\n      overall,\n      components,\n      metrics,\n      lastChecked: new Date(),\n    };\n\n    this.lastHealthCheck = healthStatus;\n\n    // Check alerts\n    await this.evaluateAlerts(metrics);\n\n    return healthStatus;\n  }\n\n  private checkStorageHealth(): ComponentHealth {\n    try {\n      // Test basic storage operations\n      // This is a simplified health check - in real implementation,\n      // we'd create a temporary secret and verify storage operations\n      const latency = 0; // Placeholder\n\n      if (latency > 5000) {\n        // 5 second timeout\n        return {\n          status: 'degraded',\n          message: 'Storage operations are slow',\n          details: { latency },\n        };\n      }\n\n      return {\n        status: 'healthy',\n        details: { latency },\n      };\n    } catch (error) {\n      return {\n        status: 'unhealthy',\n        message: `Storage health check failed: ${error instanceof Error ? error.message : String(error)}`,\n      };\n    }\n  }\n\n  private checkEncryptionHealth(): ComponentHealth {\n    try {\n      // Test encryption/decryption operations\n      // This would verify that the master key is working and crypto operations succeed\n      console.info('Checking encryption health with manager:', !!this.manager);\n      return {\n        status: 'healthy',\n        message: 'Encryption operations are functioning correctly',\n      };\n    } catch (error) {\n      return {\n        status: 'unhealthy',\n        message: `Encryption health check failed: ${error instanceof Error ? error.message : String(error)}`,\n      };\n    }\n  }\n\n  private checkAuditHealth(): ComponentHealth {\n    try {\n      // Test audit logging functionality\n      // This would verify that audit logs can be written\n      console.info('Checking audit health with store:', !!this.store);\n      return {\n        status: 'healthy',\n        message: 'Audit logging is functioning correctly',\n      };\n    } catch (error) {\n      return {\n        status: 'degraded',\n        message: `Audit health check failed: ${error instanceof Error ? error.message : String(error)}`,\n      };\n    }\n  }\n\n  private collectMetrics(): SystemMetrics {\n    try {\n      // In a real implementation, this would query the secret store\n      // and audit logs to collect comprehensive metrics\n      const metrics: SystemMetrics = {\n        totalSecrets: 0,\n        activeSecrets: 0,\n        expiredSecrets: 0,\n        secretsByTenant: {},\n        averageSecretAge: 0,\n        rotationCompliance: 100,\n        auditEventsLast24h: 0,\n        failedOperations: 0,\n        storageLatency: 0,\n      };\n\n      // Store metrics history\n      this.metricsHistory.push(metrics);\n      // Keep only last N hours of metrics\n      const retentionMs = this.config.metricsRetentionHours * 60 * 60 * 1000;\n      const cutoffTime = Date.now() - retentionMs;\n      this.metricsHistory = this.metricsHistory.filter(\n        (m) => this.metricsHistory.indexOf(m) * this.config.healthCheckIntervalMs > cutoffTime\n      );\n\n      return metrics;\n    } catch (error) {\n      console.error('Failed to collect metrics:', error);\n      throw error;\n    }\n  }\n\n  private determineOverallHealth(\n    components: HealthStatus['components']\n  ): 'healthy' | 'degraded' | 'unhealthy' {\n    const statuses = Object.values(components).map((c) => c.status);\n\n    if (statuses.includes('unhealthy')) {\n      return 'unhealthy';\n    } else if (statuses.includes('degraded')) {\n      return 'degraded';\n    } else {\n      return 'healthy';\n    }\n  }\n\n  private initializeDefaultAlertRules(): void {\n    this.alertRules = [\n      {\n        id: 'high-expiry-rate',\n        name: 'High Secret Expiry Rate',\n        condition: (metrics) => metrics.expiredSecrets / metrics.totalSecrets > 0.1,\n        severity: 'warning',\n        message: 'More than 10% of secrets are expired',\n        enabled: true,\n      },\n      {\n        id: 'rotation-compliance-low',\n        name: 'Low Rotation Compliance',\n        condition: (metrics) => metrics.rotationCompliance < 80,\n        severity: 'error',\n        message: 'Rotation compliance is below 80%',\n        enabled: true,\n      },\n      {\n        id: 'high-failure-rate',\n        name: 'High Operation Failure Rate',\n        condition: (metrics) => metrics.failedOperations > 10,\n        severity: 'critical',\n        message: 'High number of failed operations detected',\n        enabled: true,\n      },\n      {\n        id: 'storage-latency-high',\n        name: 'High Storage Latency',\n        condition: (metrics) => metrics.storageLatency > 1000,\n        severity: 'warning',\n        message: 'Storage operations are experiencing high latency',\n        enabled: true,\n      },\n    ];\n  }\n\n  addAlertRule(rule: AlertRule): void {\n    this.alertRules.push(rule);\n  }\n\n  removeAlertRule(ruleId: string): void {\n    this.alertRules = this.alertRules.filter((r) => r.id !== ruleId);\n  }\n\n  private async evaluateAlerts(metrics: SystemMetrics): Promise<void> {\n    const triggeredAlerts = this.alertRules.filter(\n      (rule) => rule.enabled && rule.condition(metrics)\n    );\n\n    for (const alert of triggeredAlerts) {\n      console.warn(`ALERT [${alert.severity.toUpperCase()}]: ${alert.message}`);\n\n      if (this.config.alertWebhook) {\n        await this.sendAlert(alert, metrics);\n      }\n    }\n  }\n\n  private async sendAlert(alert: AlertRule, metrics: SystemMetrics): Promise<void> {\n    if (!this.config.alertWebhook) {\n      return;\n    }\n\n    try {\n      await fetch(this.config.alertWebhook, {\n        method: 'POST',\n        headers: {\n          // eslint-disable-next-line @typescript-eslint/naming-convention -- HTTP header name is standardized\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n          alert: {\n            id: alert.id,\n            name: alert.name,\n            severity: alert.severity,\n            message: alert.message,\n          },\n          metrics,\n          timestamp: new Date().toISOString(),\n        }),\n      });\n    } catch (error) {\n      console.error('Failed to send alert:', error);\n    }\n  }\n\n  getMetricsHistory(hours?: number): SystemMetrics[] {\n    if (!hours) {\n      return this.metricsHistory;\n    }\n\n    const cutoffTime = Date.now() - hours * 60 * 60 * 1000;\n    return this.metricsHistory.filter(\n      (_, index) => index * this.config.healthCheckIntervalMs > cutoffTime\n    );\n  }\n\n  getLastHealthCheck(): HealthStatus | undefined {\n    return this.lastHealthCheck;\n  }\n}\n"],"mappings":"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","names":[]}