{"version":3,"sources":["../../src/audit/index.ts","../../src/audit/services/audit.service.ts","../../src/audit/services/privacyAuditLogger.ts","../../src/audit/services/clickhouse.ts","../../src/audit/services/hashMapping.ts","../../src/audit/utils/crypto.ts","../../src/audit/hooks/useAuditLog.ts","../../src/audit/hooks/useAuditStream.ts","../../src/audit/hooks/useUserActivity.ts","../../src/audit/hooks/useAuditSearch.ts","../../src/audit/hooks/usePrivacyAuditLog.ts","../../src/auth/hooks/useAuth.ts","../../src/auth/providers/AuthProvider.tsx","../../src/auth/services/auth.service.ts","../../src/audit/components/AuditLogViewer/AuditLogViewer.tsx","../../src/audit/components/ActivityTimeline/ActivityTimeline.tsx","../../src/audit/components/AuditEventDetails/AuditEventDetails.tsx","../../src/audit/components/AuditSearchBar/AuditSearchBar.tsx","../../src/audit/utils/formatter.ts","../../src/audit/utils/exporter.ts"],"sourcesContent":["// Core exports\nexport { audit } from './services/audit.service';\nexport type { AuditConfig, AuditEvent } from './types';\n\n// Privacy-preserving audit exports\nexport { privacyAuditLogger } from './services/privacyAuditLogger';\nexport type { PHIFields } from './services/privacyAuditLogger';\n\n// Utility exports\nexport { \n  hashUserId, \n  generateSalt, \n  createPHIReference, \n  parsePHIReference \n} from './utils/crypto';\n\n// Service exports for advanced usage\nexport { hashMappingService } from './services/hashMapping';\nexport { clickhouseService } from './services/clickhouse';\n\n// Hooks\nexport { useAuditLog } from './hooks/useAuditLog';\nexport { useAuditStream } from './hooks/useAuditStream';\nexport { useUserActivity } from './hooks/useUserActivity';\nexport { useAuditSearch } from './hooks/useAuditSearch';\nexport { usePrivacyAuditLog, usePHIFieldTracking } from './hooks/usePrivacyAuditLog';\n\n// Components\nexport { AuditLogViewer } from './components/AuditLogViewer';\nexport { ActivityTimeline } from './components/ActivityTimeline';\nexport { AuditEventDetails } from './components/AuditEventDetails';\nexport { AuditSearchBar } from './components/AuditSearchBar';\n\n// Utilities\nexport { AuditFormatter } from './utils/formatter';\nexport { AuditExporter } from './utils/exporter';\n\n// Types\nexport type {\n  Actor,\n  Resource,\n  Changes,\n  Context,\n  AuditEventOptions,\n  AuditEventQuery,\n  AuditEventResult,\n  AuditEventStats,\n  StreamConfig,\n  StreamSubscription,\n} from './types';\n\n// Privacy-aware convenience functions\nimport { privacyAuditLogger } from './services/privacyAuditLogger';\nimport { clickhouseService } from './services/clickhouse';\n\n/**\n * Initialize the audit system with privacy features\n */\nexport async function initializePrivacyAudit(): Promise<void> {\n  await clickhouseService.initialize();\n}\n\n/**\n * Log an audit event with automatic PHI obfuscation\n */\nexport async function logPrivacyAuditEvent(\n  action: string,\n  options?: {\n    userId?: string;\n    resourceType?: string;\n    resourceId?: string;\n    phi?: Record<string, any>;\n    metadata?: Record<string, any>;\n  }\n): Promise<string> {\n  return privacyAuditLogger.logEvent({\n    actor: {\n      id: options?.userId || 'system',\n    },\n    action,\n    resource: options?.resourceType ? {\n      type: options.resourceType,\n      id: options.resourceId || '',\n    } : undefined,\n    phi: options?.phi,\n    metadata: options?.metadata,\n  });\n}\n\n/**\n * Log PHI access for HIPAA compliance\n */\nexport async function logPHIAccess(\n  userId: string,\n  patientId: string,\n  accessType: 'view' | 'update' | 'delete',\n  phiData?: Record<string, any>\n): Promise<string> {\n  return privacyAuditLogger.logEvent({\n    actor: {\n      id: userId,\n    },\n    action: `phi_${accessType}`,\n    resource: {\n      type: 'patient',\n      id: patientId,\n    },\n    phi: phiData,\n    severity: accessType === 'delete' ? 'high' : 'medium',\n  });\n}\n\n/**\n * Generate HIPAA compliance audit report\n */\nexport async function generateHIPAAComplianceReport(\n  startDate: Date,\n  endDate: Date,\n  options?: {\n    includePHI?: boolean;\n    actorId?: string;\n    resourceType?: string;\n  }\n): Promise<any> {\n  return privacyAuditLogger.generateAuditReport(startDate, endDate, options);\n}","import {\n  AuditConfig,\n  AuditEvent,\n  AuditEventOptions,\n  AuditError,\n  AuditEventQuery,\n  AuditEventResult,\n  StreamConfig,\n  StreamSubscription,\n} from '../types';\n\nclass AuditService {\n  private config: AuditConfig = {\n    storage: 'firebase',\n    stream: false,\n    retention: '90d',\n  };\n  \n  private events: Map<string, AuditEvent> = new Map();\n  private streamSubscriptions: Map<string, StreamSubscription> = new Map();\n  private decoratedMethods: Map<string, Function> = new Map();\n\n  // Configure the audit service\n  configure(config: AuditConfig): AuditService {\n    this.config = { ...this.config, ...config };\n    return this;\n  }\n\n  // Log an audit event\n  async log(options: AuditEventOptions): Promise<AuditEvent> {\n    try {\n      const event: AuditEvent = {\n        id: this.generateEventId(),\n        timestamp: new Date(),\n        actor: await this.getCurrentActor(),\n        action: options.action,\n        resource: options.resource,\n        result: options.result || 'success',\n        changes: options.changes,\n        metadata: options.metadata,\n        context: await this.captureContext(),\n        tags: options.tags,\n      };\n\n      // Apply filters\n      if (this.config.filters) {\n        for (const filter of this.config.filters) {\n          if (!filter.filter(event)) {\n            return event; // Skip logging if filtered out\n          }\n        }\n      }\n\n      // Apply formatters\n      let formattedEvent = event;\n      if (this.config.formatters) {\n        for (const formatter of this.config.formatters) {\n          formattedEvent = formatter.format(formattedEvent);\n        }\n      }\n\n      // Store event\n      await this.storeEvent(formattedEvent);\n\n      // Stream if enabled\n      if (this.config.stream) {\n        this.streamEvent(formattedEvent);\n      }\n\n      return formattedEvent;\n    } catch (error: any) {\n      const auditError: AuditError = {\n        code: 'audit/log-failed',\n        message: error.message || 'Failed to log audit event',\n        event: options as any,\n        originalError: error,\n      };\n\n      if (this.config.onError) {\n        this.config.onError(auditError);\n      }\n\n      throw auditError;\n    }\n  }\n\n  // Decorator for automatic method tracking\n  track(action: string) {\n    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {\n      const originalMethod = descriptor.value;\n\n      descriptor.value = async function (...args: any[]) {\n        const startTime = Date.now();\n        let result: any;\n        let error: any;\n\n        try {\n          result = await originalMethod.apply(this, args);\n        } catch (e) {\n          error = e;\n        }\n\n        // Log the audit event\n        const audit = new AuditService();\n        await audit.log({\n          action,\n          resource: {\n            type: target.constructor.name,\n            id: propertyKey,\n            name: `${target.constructor.name}.${propertyKey}`,\n          },\n          result: error ? 'failure' : 'success',\n          metadata: {\n            duration: Date.now() - startTime,\n            arguments: args,\n            error: error?.message,\n          },\n        });\n\n        if (error) {\n          throw error;\n        }\n\n        return result;\n      };\n\n      return descriptor;\n    };\n  }\n\n  // Stream real-time audit events\n  stream(config: StreamConfig): StreamSubscription {\n    const subscriptionId = this.generateSubscriptionId();\n    \n    const subscription: StreamSubscription = {\n      id: subscriptionId,\n      unsubscribe: () => {\n        this.streamSubscriptions.delete(subscriptionId);\n      },\n      pause: () => {\n        // Pause implementation\n      },\n      resume: () => {\n        // Resume implementation\n      },\n      updateFilter: (filter) => {\n        // Update filter implementation\n      },\n    };\n\n    this.streamSubscriptions.set(subscriptionId, subscription);\n\n    // Start streaming\n    if (config.onConnect) {\n      config.onConnect();\n    }\n\n    return subscription;\n  }\n\n  // Query audit events\n  async query(query: AuditEventQuery): Promise<AuditEventResult> {\n    let events = Array.from(this.events.values());\n\n    // Apply filters\n    if (query.filters) {\n      const { filters } = query;\n\n      if (filters.startDate) {\n        events = events.filter(e => e.timestamp >= filters.startDate!);\n      }\n\n      if (filters.endDate) {\n        events = events.filter(e => e.timestamp <= filters.endDate!);\n      }\n\n      if (filters.actors?.length) {\n        events = events.filter(e => filters.actors!.includes(e.actor.id));\n      }\n\n      if (filters.actions?.length) {\n        events = events.filter(e => filters.actions!.includes(e.action));\n      }\n\n      if (filters.resourceTypes?.length) {\n        events = events.filter(e => filters.resourceTypes!.includes(e.resource.type));\n      }\n\n      if (filters.results?.length) {\n        events = events.filter(e => filters.results!.includes(e.result));\n      }\n\n      if (filters.search) {\n        const search = filters.search.toLowerCase();\n        events = events.filter(e => \n          e.action.toLowerCase().includes(search) ||\n          e.resource.name?.toLowerCase().includes(search) ||\n          e.actor.name?.toLowerCase().includes(search)\n        );\n      }\n    }\n\n    // Apply sorting\n    if (query.sort) {\n      events.sort((a, b) => {\n        const aValue = (a as any)[query.sort!.field];\n        const bValue = (b as any)[query.sort!.field];\n        const direction = query.sort!.order === 'asc' ? 1 : -1;\n        \n        if (aValue < bValue) return -direction;\n        if (aValue > bValue) return direction;\n        return 0;\n      });\n    } else {\n      // Default sort by timestamp descending\n      events.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n    }\n\n    // Apply pagination\n    const total = events.length;\n    if (query.pagination) {\n      const { page = 1, limit = 50 } = query.pagination;\n      const start = (page - 1) * limit;\n      events = events.slice(start, start + limit);\n    }\n\n    return {\n      events,\n      total,\n      page: query.pagination?.page || 1,\n      pageSize: query.pagination?.limit || events.length,\n      hasMore: total > (query.pagination?.page || 1) * (query.pagination?.limit || total),\n    };\n  }\n\n  // Get user activity\n  async getUserActivity(userId: string, startDate?: Date, endDate?: Date): Promise<AuditEvent[]> {\n    const query: AuditEventQuery = {\n      filters: {\n        actors: [userId],\n        startDate,\n        endDate,\n      },\n    };\n\n    const result = await this.query(query);\n    return result.events;\n  }\n\n  // Private methods\n  private async getCurrentActor() {\n    // This would typically get the current user from auth service\n    return {\n      id: 'system',\n      type: 'system' as const,\n      name: 'System',\n    };\n  }\n\n  private async captureContext() {\n    // Capture request context\n    return {\n      ip: '127.0.0.1',\n      userAgent: typeof window !== 'undefined' ? window.navigator.userAgent : 'Server',\n      sessionId: this.generateSessionId(),\n    };\n  }\n\n  private async storeEvent(event: AuditEvent) {\n    // Store in memory for now (would use actual storage in production)\n    this.events.set(event.id, event);\n\n    // Clean up old events based on retention\n    if (this.config.retention) {\n      this.cleanupOldEvents();\n    }\n  }\n\n  private streamEvent(event: AuditEvent) {\n    // Send event to all active stream subscriptions\n    this.streamSubscriptions.forEach((subscription, id) => {\n      // Stream implementation would go here\n    });\n  }\n\n  private cleanupOldEvents() {\n    const retentionMs = this.parseRetention(this.config.retention!);\n    const cutoffDate = new Date(Date.now() - retentionMs);\n\n    this.events.forEach((event, id) => {\n      if (event.timestamp < cutoffDate) {\n        this.events.delete(id);\n      }\n    });\n  }\n\n  private parseRetention(retention: string): number {\n    const match = retention.match(/^(\\d+)([hdwmy])$/);\n    if (!match) return 90 * 24 * 60 * 60 * 1000; // Default 90 days\n\n    const [, value, unit] = match;\n    const num = parseInt(value, 10);\n\n    switch (unit) {\n      case 'h': return num * 60 * 60 * 1000;\n      case 'd': return num * 24 * 60 * 60 * 1000;\n      case 'w': return num * 7 * 24 * 60 * 60 * 1000;\n      case 'm': return num * 30 * 24 * 60 * 60 * 1000;\n      case 'y': return num * 365 * 24 * 60 * 60 * 1000;\n      default: return 90 * 24 * 60 * 60 * 1000;\n    }\n  }\n\n  private generateEventId(): string {\n    return `evt_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n  }\n\n  private generateSubscriptionId(): string {\n    return `sub_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n  }\n\n  private generateSessionId(): string {\n    return `ses_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n  }\n}\n\n// Singleton instance\nexport const audit = new AuditService();","import { randomUUID } from 'crypto';\nimport { clickhouseService } from './clickhouse';\nimport { hashMappingService } from './hashMapping';\nimport { createPHIReference, parsePHIReference } from '../utils/crypto';\nimport { doc, getDoc, getFirestore } from 'firebase/firestore';\nimport { getApp } from 'firebase/app';\n\nexport interface PHIFields {\n  patientName?: string;\n  patientEmail?: string;\n  patientPhone?: string;\n  patientDob?: string;\n  patientSsn?: string;\n  patientMrn?: string;\n  diagnosis?: string;\n  treatmentDetails?: string;\n  medications?: string;\n  [key: string]: string | undefined;\n}\n\nexport interface AuditEvent {\n  id?: string;\n  timestamp?: Date;\n  actor: {\n    id: string;\n    email?: string;\n    name?: string;\n    role?: string;\n  };\n  action: string;\n  resource?: {\n    type: string;\n    id: string;\n    name?: string;\n  };\n  severity?: 'low' | 'medium' | 'high' | 'critical';\n  success?: boolean;\n  error?: string;\n  phi?: PHIFields;\n  metadata?: Record<string, any>;\n  ipAddress?: string;\n  userAgent?: string;\n  department?: string;\n  location?: string;\n  sessionId?: string;\n  requestId?: string;\n}\n\nexport interface PHIMapping {\n  collection: string;\n  field: string;\n  value: any;\n}\n\n/**\n * Privacy-aware audit logger that separates PHI from audit events\n */\nexport class PrivacyAuditLogger {\n  private static instance: PrivacyAuditLogger;\n  private db = getFirestore(getApp());\n  \n  private constructor() {}\n  \n  static getInstance(): PrivacyAuditLogger {\n    if (!PrivacyAuditLogger.instance) {\n      PrivacyAuditLogger.instance = new PrivacyAuditLogger();\n    }\n    return PrivacyAuditLogger.instance;\n  }\n  \n  /**\n   * Log an audit event with automatic PHI obfuscation\n   */\n  async logEvent(event: AuditEvent): Promise<string> {\n    const eventId = event.id || randomUUID();\n    const timestamp = event.timestamp || new Date();\n    \n    // Process PHI fields if present\n    const phiReferences: Record<string, string> = {};\n    if (event.phi) {\n      // Get hash for the patient/user\n      const patientUserId = event.resource?.id || event.actor.id;\n      const hashedUserId = await hashMappingService.getOrCreateHashMapping(patientUserId);\n      \n      // Convert PHI fields to references\n      for (const [key, value] of Object.entries(event.phi)) {\n        if (value !== undefined && value !== null) {\n          // Determine collection and field based on PHI field name\n          const { collection, field } = this.getFirestoreLocation(key);\n          phiReferences[this.mapPHIFieldToColumn(key)] = createPHIReference(\n            hashedUserId,\n            collection,\n            field\n          );\n        }\n      }\n    }\n    \n    // Prepare event for ClickHouse\n    const clickhouseEvent = {\n      id: eventId,\n      timestamp: timestamp.toISOString(),\n      actor_id: await hashMappingService.getOrCreateHashMapping(event.actor.id),\n      actor_email: event.actor.email || null,\n      actor_name: event.actor.name || null,\n      actor_role: event.actor.role || null,\n      action: event.action,\n      resource_type: event.resource?.type || null,\n      resource_id: event.resource?.id || null,\n      resource_name: event.resource?.name || null,\n      severity: event.severity || 'low',\n      success: event.success !== false,\n      error_message: event.error || null,\n      ...phiReferences,\n      ip_address: event.ipAddress || null,\n      user_agent: event.userAgent || null,\n      department: event.department || null,\n      location: event.location || null,\n      session_id: event.sessionId || null,\n      request_id: event.requestId || null,\n      metadata: JSON.stringify(event.metadata || {})\n    };\n    \n    // Insert into ClickHouse\n    await clickhouseService.insertEvents([clickhouseEvent]);\n    \n    return eventId;\n  }\n  \n  /**\n   * Log multiple events in batch\n   */\n  async logEvents(events: AuditEvent[]): Promise<string[]> {\n    const processedEvents = await Promise.all(\n      events.map(async (event) => {\n        const eventId = event.id || randomUUID();\n        const timestamp = event.timestamp || new Date();\n        \n        // Process PHI fields\n        const phiReferences: Record<string, string> = {};\n        if (event.phi) {\n          const patientUserId = event.resource?.id || event.actor.id;\n          const hashedUserId = await hashMappingService.getOrCreateHashMapping(patientUserId);\n          \n          for (const [key, value] of Object.entries(event.phi)) {\n            if (value !== undefined && value !== null) {\n              const { collection, field } = this.getFirestoreLocation(key);\n              phiReferences[this.mapPHIFieldToColumn(key)] = createPHIReference(\n                hashedUserId,\n                collection,\n                field\n              );\n            }\n          }\n        }\n        \n        return {\n          id: eventId,\n          timestamp: timestamp.toISOString(),\n          actor_id: await hashMappingService.getOrCreateHashMapping(event.actor.id),\n          actor_email: event.actor.email || null,\n          actor_name: event.actor.name || null,\n          actor_role: event.actor.role || null,\n          action: event.action,\n          resource_type: event.resource?.type || null,\n          resource_id: event.resource?.id || null,\n          resource_name: event.resource?.name || null,\n          severity: event.severity || 'low',\n          success: event.success !== false,\n          error_message: event.error || null,\n          ...phiReferences,\n          ip_address: event.ipAddress || null,\n          user_agent: event.userAgent || null,\n          department: event.department || null,\n          location: event.location || null,\n          session_id: event.sessionId || null,\n          request_id: event.requestId || null,\n          metadata: JSON.stringify(event.metadata || {})\n        };\n      })\n    );\n    \n    await clickhouseService.insertEvents(processedEvents);\n    return processedEvents.map(e => e.id);\n  }\n  \n  /**\n   * Reconstruct an audit event with PHI data\n   */\n  async reconstructWithPHI(eventId: string): Promise<AuditEvent | null> {\n    // Query ClickHouse for the event\n    const query = `\n      SELECT * FROM audit_logs.audit_events \n      WHERE id = {eventId:String}\n      LIMIT 1\n    `;\n    \n    const results = await clickhouseService.queryEvents(query, { eventId });\n    if (results.length === 0) {\n      return null;\n    }\n    \n    const event = results[0];\n    \n    // Resolve actor ID\n    const actorId = await hashMappingService.resolveHash(event.actor_id);\n    if (!actorId) {\n      throw new Error(`Unable to resolve actor hash: ${event.actor_id}`);\n    }\n    \n    // Reconstruct basic event\n    const reconstructed: AuditEvent = {\n      id: event.id,\n      timestamp: new Date(event.timestamp),\n      actor: {\n        id: actorId,\n        email: event.actor_email,\n        name: event.actor_name,\n        role: event.actor_role\n      },\n      action: event.action,\n      resource: event.resource_type ? {\n        type: event.resource_type,\n        id: event.resource_id,\n        name: event.resource_name\n      } : undefined,\n      severity: event.severity,\n      success: event.success,\n      error: event.error_message,\n      metadata: JSON.parse(event.metadata || '{}'),\n      ipAddress: event.ip_address,\n      userAgent: event.user_agent,\n      department: event.department,\n      location: event.location,\n      sessionId: event.session_id,\n      requestId: event.request_id\n    };\n    \n    // Resolve PHI fields\n    const phiFields: PHIFields = {};\n    const phiColumns = [\n      'patient_name', 'patient_email', 'patient_phone', \n      'patient_dob', 'patient_ssn', 'patient_mrn',\n      'diagnosis', 'treatment_details', 'medications'\n    ];\n    \n    for (const column of phiColumns) {\n      if (event[column]) {\n        const parsed = parsePHIReference(event[column]);\n        if (parsed) {\n          const userId = await hashMappingService.resolveHash(parsed.hashedUserId);\n          if (userId) {\n            const value = await this.fetchPHIValue(userId, parsed.collection, parsed.field);\n            if (value !== null) {\n              phiFields[this.mapColumnToPHIField(column)] = value;\n            }\n          }\n        }\n      }\n    }\n    \n    if (Object.keys(phiFields).length > 0) {\n      reconstructed.phi = phiFields;\n    }\n    \n    return reconstructed;\n  }\n  \n  /**\n   * Query audit events with optional PHI reconstruction\n   */\n  async queryEvents(\n    query: string, \n    params?: Record<string, any>,\n    includePHI: boolean = false\n  ): Promise<AuditEvent[]> {\n    const results = await clickhouseService.queryEvents(query, params);\n    \n    if (!includePHI) {\n      // Return events without PHI reconstruction\n      return results.map(event => ({\n        id: event.id,\n        timestamp: new Date(event.timestamp),\n        actor: {\n          id: event.actor_id, // Keep hashed for privacy\n          email: event.actor_email,\n          name: event.actor_name,\n          role: event.actor_role\n        },\n        action: event.action,\n        resource: event.resource_type ? {\n          type: event.resource_type,\n          id: event.resource_id,\n          name: event.resource_name\n        } : undefined,\n        severity: event.severity,\n        success: event.success,\n        error: event.error_message,\n        metadata: JSON.parse(event.metadata || '{}')\n      }));\n    }\n    \n    // Reconstruct with PHI\n    const reconstructed = await Promise.all(\n      results.map(r => this.reconstructWithPHI(r.id))\n    );\n    \n    return reconstructed.filter(e => e !== null) as AuditEvent[];\n  }\n  \n  /**\n   * Generate audit report for compliance\n   */\n  async generateAuditReport(\n    startDate: Date,\n    endDate: Date,\n    options?: {\n      actorId?: string;\n      resourceType?: string;\n      resourceId?: string;\n      includePHI?: boolean;\n    }\n  ): Promise<any> {\n    let query = `\n      SELECT * FROM audit_logs.audit_events \n      WHERE timestamp >= {startDate:DateTime64} \n        AND timestamp <= {endDate:DateTime64}\n    `;\n    \n    const params: Record<string, any> = {\n      startDate: startDate.toISOString(),\n      endDate: endDate.toISOString()\n    };\n    \n    if (options?.actorId) {\n      const hashedActorId = await hashMappingService.getOrCreateHashMapping(options.actorId);\n      query += ` AND actor_id = {actorId:String}`;\n      params.actorId = hashedActorId;\n    }\n    \n    if (options?.resourceType) {\n      query += ` AND resource_type = {resourceType:String}`;\n      params.resourceType = options.resourceType;\n    }\n    \n    if (options?.resourceId) {\n      query += ` AND resource_id = {resourceId:String}`;\n      params.resourceId = options.resourceId;\n    }\n    \n    query += ` ORDER BY timestamp DESC`;\n    \n    const events = await this.queryEvents(query, params, options?.includePHI || false);\n    \n    // Generate summary statistics\n    const summaryQuery = `\n      SELECT \n        count() as total_events,\n        countIf(success = 1) as successful_events,\n        countIf(success = 0) as failed_events,\n        uniqExact(actor_id) as unique_actors,\n        groupArray(DISTINCT action) as actions\n      FROM audit_logs.audit_events \n      WHERE timestamp >= {startDate:DateTime64} \n        AND timestamp <= {endDate:DateTime64}\n    `;\n    \n    const summary = await clickhouseService.queryEvents(summaryQuery, params);\n    \n    return {\n      report: {\n        startDate,\n        endDate,\n        summary: summary[0],\n        events\n      }\n    };\n  }\n  \n  /**\n   * Determine Firestore collection and field for a PHI field\n   */\n  private getFirestoreLocation(phiFieldName: string): { collection: string; field: string } {\n    // Default mappings - can be customized per implementation\n    const mappings: Record<string, { collection: string; field: string }> = {\n      patientName: { collection: 'users', field: 'displayName' },\n      patientEmail: { collection: 'users', field: 'email' },\n      patientPhone: { collection: 'users', field: 'phoneNumber' },\n      patientDob: { collection: 'patient_profiles', field: 'dateOfBirth' },\n      patientSsn: { collection: 'patient_profiles', field: 'ssn' },\n      patientMrn: { collection: 'patient_profiles', field: 'medicalRecordNumber' },\n      diagnosis: { collection: 'medical_records', field: 'diagnosis' },\n      treatmentDetails: { collection: 'medical_records', field: 'treatmentPlan' },\n      medications: { collection: 'medical_records', field: 'medications' }\n    };\n    \n    return mappings[phiFieldName] || { collection: 'users', field: phiFieldName };\n  }\n  \n  /**\n   * Map PHI field names to ClickHouse column names\n   */\n  private mapPHIFieldToColumn(fieldName: string): string {\n    const mappings: Record<string, string> = {\n      patientName: 'patient_name',\n      patientEmail: 'patient_email',\n      patientPhone: 'patient_phone',\n      patientDob: 'patient_dob',\n      patientSsn: 'patient_ssn',\n      patientMrn: 'patient_mrn',\n      diagnosis: 'diagnosis',\n      treatmentDetails: 'treatment_details',\n      medications: 'medications'\n    };\n    \n    return mappings[fieldName] || fieldName.replace(/([A-Z])/g, '_$1').toLowerCase();\n  }\n  \n  /**\n   * Map ClickHouse column names back to PHI field names\n   */\n  private mapColumnToPHIField(columnName: string): string {\n    const mappings: Record<string, string> = {\n      patient_name: 'patientName',\n      patient_email: 'patientEmail',\n      patient_phone: 'patientPhone',\n      patient_dob: 'patientDob',\n      patient_ssn: 'patientSsn',\n      patient_mrn: 'patientMrn',\n      diagnosis: 'diagnosis',\n      treatment_details: 'treatmentDetails',\n      medications: 'medications'\n    };\n    \n    return mappings[columnName] || columnName;\n  }\n  \n  /**\n   * Fetch PHI value from Firestore\n   */\n  private async fetchPHIValue(\n    userId: string, \n    collection: string, \n    field: string\n  ): Promise<any> {\n    try {\n      const docRef = doc(this.db, collection, userId);\n      const snapshot = await getDoc(docRef);\n      \n      if (!snapshot.exists()) {\n        return null;\n      }\n      \n      const data = snapshot.data();\n      return data[field] || null;\n    } catch (error) {\n      console.error(`Failed to fetch PHI value from ${collection}/${userId}/${field}:`, error);\n      return null;\n    }\n  }\n}\n\n// Export singleton instance\nexport const privacyAuditLogger = PrivacyAuditLogger.getInstance();","import { createClient, ClickHouseClient } from '@clickhouse/client';\n\n/**\n * ClickHouse client singleton for audit logging\n */\nexport class ClickHouseService {\n  private static instance: ClickHouseService;\n  private client: ClickHouseClient | null = null;\n  private config = {\n    host: process.env.CLICKHOUSE_HOST || '',\n    username: process.env.CLICKHOUSE_USER || 'default',\n    password: process.env.CLICKHOUSE_PASSWORD || '',\n    database: process.env.CLICKHOUSE_DATABASE || 'audit_logs',\n    request_timeout: 60000,\n    max_open_connections: 10,\n    compression: {\n      request: true,\n      response: true\n    }\n  };\n  \n  private constructor() {}\n  \n  static getInstance(): ClickHouseService {\n    if (!ClickHouseService.instance) {\n      ClickHouseService.instance = new ClickHouseService();\n    }\n    return ClickHouseService.instance;\n  }\n  \n  /**\n   * Initialize the ClickHouse client\n   */\n  async initialize(): Promise<void> {\n    if (!this.client) {\n      this.client = createClient(this.config);\n      await this.ensureDatabase();\n      await this.ensureTable();\n    }\n  }\n  \n  /**\n   * Get the ClickHouse client instance\n   */\n  getClient(): ClickHouseClient {\n    if (!this.client) {\n      throw new Error('ClickHouse client not initialized. Call initialize() first.');\n    }\n    return this.client;\n  }\n  \n  /**\n   * Ensure the audit database exists\n   */\n  private async ensureDatabase(): Promise<void> {\n    try {\n      await this.client!.query({\n        query: `CREATE DATABASE IF NOT EXISTS ${this.config.database}`,\n        format: 'JSONEachRow'\n      });\n    } catch (error) {\n      console.error('Failed to create database:', error);\n      throw error;\n    }\n  }\n  \n  /**\n   * Ensure the audit events table exists\n   */\n  private async ensureTable(): Promise<void> {\n    const createTableQuery = `\n      CREATE TABLE IF NOT EXISTS ${this.config.database}.audit_events (\n        id String,\n        timestamp DateTime64(3),\n        actor_id String,\n        actor_email String,\n        actor_name String,\n        actor_role String,\n        action String,\n        resource_type String,\n        resource_id String,\n        resource_name String,\n        severity LowCardinality(String),\n        success Boolean,\n        error_message Nullable(String),\n        \n        -- PHI reference fields (stored as encrypted references)\n        patient_name Nullable(String),\n        patient_email Nullable(String),\n        patient_phone Nullable(String),\n        patient_dob Nullable(String),\n        patient_ssn Nullable(String),\n        patient_mrn Nullable(String),\n        diagnosis Nullable(String),\n        treatment_details Nullable(String),\n        medications Nullable(String),\n        \n        -- Non-PHI metadata\n        ip_address Nullable(String),\n        user_agent Nullable(String),\n        department Nullable(String),\n        location Nullable(String),\n        session_id Nullable(String),\n        request_id Nullable(String),\n        \n        -- Custom metadata as JSON\n        metadata String,\n        \n        -- Indexing and partitioning\n        date Date DEFAULT toDate(timestamp)\n      )\n      ENGINE = MergeTree()\n      PARTITION BY toYYYYMM(date)\n      ORDER BY (timestamp, actor_id, action)\n      TTL date + INTERVAL 7 YEAR\n      SETTINGS index_granularity = 8192\n    `;\n    \n    try {\n      await this.client!.query({\n        query: createTableQuery,\n        format: 'JSONEachRow'\n      });\n      \n      // Create materialized views for common queries\n      await this.createMaterializedViews();\n    } catch (error) {\n      console.error('Failed to create table:', error);\n      throw error;\n    }\n  }\n  \n  /**\n   * Create materialized views for performance optimization\n   */\n  private async createMaterializedViews(): Promise<void> {\n    // Daily activity summary\n    const dailyActivityView = `\n      CREATE MATERIALIZED VIEW IF NOT EXISTS ${this.config.database}.daily_activity_mv\n      ENGINE = SummingMergeTree()\n      ORDER BY (date, actor_id, action)\n      AS SELECT\n        date,\n        actor_id,\n        action,\n        count() as event_count,\n        countIf(success = 1) as success_count,\n        countIf(success = 0) as failure_count\n      FROM ${this.config.database}.audit_events\n      GROUP BY date, actor_id, action\n    `;\n    \n    // Resource access patterns\n    const resourceAccessView = `\n      CREATE MATERIALIZED VIEW IF NOT EXISTS ${this.config.database}.resource_access_mv\n      ENGINE = AggregatingMergeTree()\n      ORDER BY (resource_type, resource_id, date)\n      AS SELECT\n        resource_type,\n        resource_id,\n        date,\n        uniqExact(actor_id) as unique_actors,\n        count() as access_count,\n        groupArray(action) as actions\n      FROM ${this.config.database}.audit_events\n      GROUP BY resource_type, resource_id, date\n    `;\n    \n    try {\n      await this.client!.query({ query: dailyActivityView, format: 'JSONEachRow' });\n      await this.client!.query({ query: resourceAccessView, format: 'JSONEachRow' });\n    } catch (error) {\n      // Views might already exist, log but don't throw\n      console.warn('Failed to create materialized views:', error);\n    }\n  }\n  \n  /**\n   * Insert audit events into ClickHouse\n   */\n  async insertEvents(events: any[]): Promise<void> {\n    if (!this.client) {\n      await this.initialize();\n    }\n    \n    try {\n      await this.client!.insert({\n        table: `${this.config.database}.audit_events`,\n        values: events,\n        format: 'JSONEachRow'\n      });\n    } catch (error) {\n      console.error('Failed to insert events:', error);\n      throw error;\n    }\n  }\n  \n  /**\n   * Query audit events\n   */\n  async queryEvents(query: string, params?: Record<string, any>): Promise<any[]> {\n    if (!this.client) {\n      await this.initialize();\n    }\n    \n    try {\n      const result = await this.client!.query({\n        query,\n        format: 'JSONEachRow',\n        query_params: params\n      });\n      \n      return await result.json();\n    } catch (error) {\n      console.error('Failed to query events:', error);\n      throw error;\n    }\n  }\n  \n  /**\n   * Close the ClickHouse connection\n   */\n  async close(): Promise<void> {\n    if (this.client) {\n      await this.client.close();\n      this.client = null;\n    }\n  }\n}\n\n// Export singleton instance\nexport const clickhouseService = ClickHouseService.getInstance();","import { \n  collection, \n  doc, \n  setDoc, \n  getDoc, \n  getDocs, \n  query, \n  where, \n  Timestamp,\n  writeBatch\n} from 'firebase/firestore';\nimport { getFirestore } from 'firebase/firestore';\nimport { getApp } from 'firebase/app';\nimport { hashUserId, generateSalt } from '../utils/crypto';\n\nconst HASH_MAPPINGS_COLLECTION = 'user_hash_mappings';\n\nexport interface HashMapping {\n  hash: string;\n  userId: string;\n  salt: string;\n  createdAt: Timestamp;\n  lastAccessed?: Timestamp;\n}\n\n/**\n * Service for managing user ID hash mappings in Firestore\n */\nexport class HashMappingService {\n  private static instance: HashMappingService;\n  private memoryCache: Map<string, HashMapping> = new Map();\n  private db = getFirestore(getApp());\n  \n  private constructor() {}\n  \n  static getInstance(): HashMappingService {\n    if (!HashMappingService.instance) {\n      HashMappingService.instance = new HashMappingService();\n    }\n    return HashMappingService.instance;\n  }\n  \n  /**\n   * Get or create a hash mapping for a user ID\n   */\n  async getOrCreateHashMapping(userId: string): Promise<string> {\n    // Check memory cache first\n    const cached = Array.from(this.memoryCache.values()).find(\n      mapping => mapping.userId === userId\n    );\n    if (cached) {\n      return cached.hash;\n    }\n    \n    // Check Firestore\n    const mappingsRef = collection(this.db, HASH_MAPPINGS_COLLECTION);\n    const q = query(mappingsRef, where('userId', '==', userId));\n    const snapshot = await getDocs(q);\n    \n    if (!snapshot.empty) {\n      const mapping = snapshot.docs[0].data() as HashMapping;\n      this.memoryCache.set(mapping.hash, mapping);\n      return mapping.hash;\n    }\n    \n    // Create new mapping\n    const salt = generateSalt();\n    const hash = hashUserId(userId, salt);\n    const mapping: HashMapping = {\n      hash,\n      userId,\n      salt,\n      createdAt: Timestamp.now()\n    };\n    \n    await setDoc(doc(this.db, HASH_MAPPINGS_COLLECTION, hash), mapping);\n    this.memoryCache.set(hash, mapping);\n    \n    return hash;\n  }\n  \n  /**\n   * Resolve a hash back to a user ID\n   */\n  async resolveHash(hash: string): Promise<string | null> {\n    // Check memory cache first\n    const cached = this.memoryCache.get(hash);\n    if (cached) {\n      // Update last accessed time asynchronously\n      this.updateLastAccessed(hash);\n      return cached.userId;\n    }\n    \n    // Check Firestore\n    const docRef = doc(this.db, HASH_MAPPINGS_COLLECTION, hash);\n    const snapshot = await getDoc(docRef);\n    \n    if (!snapshot.exists()) {\n      return null;\n    }\n    \n    const mapping = snapshot.data() as HashMapping;\n    this.memoryCache.set(hash, mapping);\n    \n    // Update last accessed time asynchronously\n    this.updateLastAccessed(hash);\n    \n    return mapping.userId;\n  }\n  \n  /**\n   * Batch create hash mappings for multiple users\n   */\n  async batchCreateHashMappings(userIds: string[]): Promise<Map<string, string>> {\n    const batch = writeBatch(this.db);\n    const userHashMap = new Map<string, string>();\n    \n    for (const userId of userIds) {\n      // Check if mapping already exists\n      const existingHash = await this.getOrCreateHashMapping(userId);\n      if (existingHash) {\n        userHashMap.set(userId, existingHash);\n        continue;\n      }\n      \n      const salt = generateSalt();\n      const hash = hashUserId(userId, salt);\n      const mapping: HashMapping = {\n        hash,\n        userId,\n        salt,\n        createdAt: Timestamp.now()\n      };\n      \n      batch.set(doc(this.db, HASH_MAPPINGS_COLLECTION, hash), mapping);\n      userHashMap.set(userId, hash);\n      this.memoryCache.set(hash, mapping);\n    }\n    \n    await batch.commit();\n    return userHashMap;\n  }\n  \n  /**\n   * Resolve multiple hashes in batch\n   */\n  async batchResolveHashes(hashes: string[]): Promise<Map<string, string>> {\n    const resolvedMap = new Map<string, string>();\n    const uncachedHashes: string[] = [];\n    \n    // Check cache first\n    for (const hash of hashes) {\n      const cached = this.memoryCache.get(hash);\n      if (cached) {\n        resolvedMap.set(hash, cached.userId);\n      } else {\n        uncachedHashes.push(hash);\n      }\n    }\n    \n    // Fetch uncached from Firestore\n    if (uncachedHashes.length > 0) {\n      const mappingsRef = collection(this.db, HASH_MAPPINGS_COLLECTION);\n      const q = query(mappingsRef, where('hash', 'in', uncachedHashes));\n      const snapshot = await getDocs(q);\n      \n      snapshot.docs.forEach(doc => {\n        const mapping = doc.data() as HashMapping;\n        resolvedMap.set(mapping.hash, mapping.userId);\n        this.memoryCache.set(mapping.hash, mapping);\n      });\n    }\n    \n    // Update last accessed times asynchronously\n    hashes.forEach(hash => this.updateLastAccessed(hash));\n    \n    return resolvedMap;\n  }\n  \n  /**\n   * Clear memory cache (useful for testing or memory management)\n   */\n  clearCache(): void {\n    this.memoryCache.clear();\n  }\n  \n  /**\n   * Update last accessed timestamp for a hash mapping\n   */\n  private async updateLastAccessed(hash: string): Promise<void> {\n    try {\n      await setDoc(\n        doc(this.db, HASH_MAPPINGS_COLLECTION, hash),\n        { lastAccessed: Timestamp.now() },\n        { merge: true }\n      );\n    } catch (error) {\n      // Log error but don't throw - this is a non-critical operation\n      console.error('Failed to update last accessed time:', error);\n    }\n  }\n}\n\n// Export singleton instance\nexport const hashMappingService = HashMappingService.getInstance();","import { createHash, randomBytes } from 'crypto';\n\n/**\n * Cryptographic utilities for privacy-preserving audit logging\n */\n\n/**\n * Generate a deterministic hash for a user ID with an optional salt\n * This creates a one-way hash that can be used to obfuscate user IDs\n */\nexport function hashUserId(userId: string, salt?: string): string {\n  const data = salt ? `${userId}:${salt}` : userId;\n  return createHash('sha256').update(data).digest('hex');\n}\n\n/**\n * Generate a cryptographically secure random salt\n */\nexport function generateSalt(): string {\n  return randomBytes(32).toString('hex');\n}\n\n/**\n * Create a PHI reference string in the format: hash.collection.field\n */\nexport function createPHIReference(\n  hashedUserId: string,\n  collection: string,\n  field: string\n): string {\n  return `${hashedUserId}.${collection}.${field}`;\n}\n\n/**\n * Parse a PHI reference string into its components\n */\nexport function parsePHIReference(reference: string): {\n  hashedUserId: string;\n  collection: string;\n  field: string;\n} | null {\n  const parts = reference.split('.');\n  if (parts.length !== 3) {\n    return null;\n  }\n  \n  return {\n    hashedUserId: parts[0],\n    collection: parts[1],\n    field: parts[2]\n  };\n}\n\n/**\n * Batch hash multiple values for efficiency\n */\nexport function batchHashUserIds(\n  userIds: string[],\n  salt?: string\n): Map<string, string> {\n  const hashMap = new Map<string, string>();\n  \n  for (const userId of userIds) {\n    hashMap.set(userId, hashUserId(userId, salt));\n  }\n  \n  return hashMap;\n}","import { useCallback, useState } from 'react';\nimport { audit } from '../services/audit.service';\nimport { AuditEventOptions, AuditEvent, AuditError } from '../types';\n\nexport function useAuditLog() {\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<AuditError | null>(null);\n  const [lastEvent, setLastEvent] = useState<AuditEvent | null>(null);\n\n  const log = useCallback(async (options: AuditEventOptions): Promise<AuditEvent> => {\n    setLoading(true);\n    setError(null);\n\n    try {\n      const event = await audit.log(options);\n      setLastEvent(event);\n      return event;\n    } catch (err: any) {\n      const auditError: AuditError = {\n        code: err.code || 'audit/log-failed',\n        message: err.message || 'Failed to log audit event',\n        originalError: err,\n      };\n      setError(auditError);\n      throw auditError;\n    } finally {\n      setLoading(false);\n    }\n  }, []);\n\n  const logAction = useCallback(async (\n    action: string,\n    resourceType: string,\n    resourceId: string,\n    metadata?: any\n  ): Promise<AuditEvent> => {\n    return log({\n      action,\n      resource: {\n        type: resourceType,\n        id: resourceId,\n      },\n      metadata,\n    });\n  }, [log]);\n\n  const logSuccess = useCallback(async (\n    action: string,\n    resource: any,\n    changes?: any\n  ): Promise<AuditEvent> => {\n    return log({\n      action,\n      resource,\n      result: 'success',\n      changes,\n    });\n  }, [log]);\n\n  const logFailure = useCallback(async (\n    action: string,\n    resource: any,\n    error: any\n  ): Promise<AuditEvent> => {\n    return log({\n      action,\n      resource,\n      result: 'failure',\n      metadata: {\n        error: error.message || error,\n        errorCode: error.code,\n      },\n    });\n  }, [log]);\n\n  return {\n    log,\n    logAction,\n    logSuccess,\n    logFailure,\n    loading,\n    error,\n    lastEvent,\n  };\n}","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { audit } from '../services/audit.service';\nimport { AuditEvent, StreamConfig, StreamFilter } from '../types';\n\ninterface UseAuditStreamOptions {\n  filter?: StreamFilter;\n  limit?: number;\n  autoConnect?: boolean;\n}\n\nexport function useAuditStream(options: UseAuditStreamOptions = {}) {\n  const { filter, limit = 50, autoConnect = true } = options;\n  const [events, setEvents] = useState<AuditEvent[]>([]);\n  const [loading, setLoading] = useState(false);\n  const [connected, setConnected] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n  const subscriptionRef = useRef<any>(null);\n\n  const connect = useCallback(() => {\n    if (subscriptionRef.current) {\n      return; // Already connected\n    }\n\n    setLoading(true);\n    setError(null);\n\n    try {\n      const config: StreamConfig = {\n        filter,\n        onEvent: (event) => {\n          setEvents(prev => {\n            const newEvents = [event, ...prev];\n            return newEvents.slice(0, limit);\n          });\n        },\n        onError: (streamError) => {\n          setError(new Error(streamError.message));\n        },\n        onConnect: () => {\n          setConnected(true);\n          setLoading(false);\n        },\n        onDisconnect: () => {\n          setConnected(false);\n        },\n      };\n\n      subscriptionRef.current = audit.stream(config);\n    } catch (err: any) {\n      setError(err);\n      setLoading(false);\n    }\n  }, [filter, limit]);\n\n  const disconnect = useCallback(() => {\n    if (subscriptionRef.current) {\n      subscriptionRef.current.unsubscribe();\n      subscriptionRef.current = null;\n      setConnected(false);\n    }\n  }, []);\n\n  const pause = useCallback(() => {\n    if (subscriptionRef.current) {\n      subscriptionRef.current.pause();\n    }\n  }, []);\n\n  const resume = useCallback(() => {\n    if (subscriptionRef.current) {\n      subscriptionRef.current.resume();\n    }\n  }, []);\n\n  const updateFilter = useCallback((newFilter: StreamFilter) => {\n    if (subscriptionRef.current) {\n      subscriptionRef.current.updateFilter(newFilter);\n    }\n  }, []);\n\n  const clear = useCallback(() => {\n    setEvents([]);\n  }, []);\n\n  // Auto-connect on mount if enabled\n  useEffect(() => {\n    if (autoConnect) {\n      connect();\n    }\n\n    return () => {\n      disconnect();\n    };\n  }, [autoConnect, connect, disconnect]);\n\n  return {\n    events,\n    loading,\n    connected,\n    error,\n    connect,\n    disconnect,\n    pause,\n    resume,\n    updateFilter,\n    clear,\n  };\n}","import { useState, useEffect, useCallback } from 'react';\nimport { audit } from '../services/audit.service';\nimport { AuditEvent, AuditEventStats } from '../types';\n\ninterface UseUserActivityOptions {\n  range?: 'today' | 'last7days' | 'last30days' | 'custom';\n  startDate?: Date;\n  endDate?: Date;\n  autoLoad?: boolean;\n}\n\nexport function useUserActivity(userId: string, options: UseUserActivityOptions = {}) {\n  const { range = 'last30days', startDate, endDate, autoLoad = true } = options;\n  const [activity, setActivity] = useState<AuditEvent[]>([]);\n  const [stats, setStats] = useState<AuditEventStats | null>(null);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n\n  const getDateRange = useCallback(() => {\n    const now = new Date();\n    let start: Date;\n    let end = endDate || now;\n\n    switch (range) {\n      case 'today':\n        start = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n        break;\n      case 'last7days':\n        start = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);\n        break;\n      case 'last30days':\n        start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n        break;\n      case 'custom':\n        start = startDate || new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n        break;\n      default:\n        start = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);\n    }\n\n    return { start, end };\n  }, [range, startDate, endDate]);\n\n  const loadActivity = useCallback(async () => {\n    if (!userId) return;\n\n    setLoading(true);\n    setError(null);\n\n    try {\n      const { start, end } = getDateRange();\n      const events = await audit.getUserActivity(userId, start, end);\n      \n      setActivity(events);\n\n      // Calculate stats\n      const calculatedStats: AuditEventStats = {\n        total: events.length,\n        byAction: {},\n        byActor: {},\n        byResource: {},\n        byResult: {},\n        byHour: {},\n        byDay: {},\n      };\n\n      events.forEach(event => {\n        // By action\n        calculatedStats.byAction[event.action] = (calculatedStats.byAction[event.action] || 0) + 1;\n        \n        // By actor\n        const actorKey = `${event.actor.type}:${event.actor.id}`;\n        calculatedStats.byActor[actorKey] = (calculatedStats.byActor[actorKey] || 0) + 1;\n        \n        // By resource\n        calculatedStats.byResource[event.resource.type] = (calculatedStats.byResource[event.resource.type] || 0) + 1;\n        \n        // By result\n        calculatedStats.byResult[event.result] = (calculatedStats.byResult[event.result] || 0) + 1;\n        \n        // By hour\n        const hour = event.timestamp.getHours();\n        calculatedStats.byHour![hour] = (calculatedStats.byHour![hour] || 0) + 1;\n        \n        // By day\n        const day = event.timestamp.toDateString();\n        calculatedStats.byDay![day] = (calculatedStats.byDay![day] || 0) + 1;\n      });\n\n      setStats(calculatedStats);\n    } catch (err: any) {\n      setError(err);\n    } finally {\n      setLoading(false);\n    }\n  }, [userId, getDateRange]);\n\n  const refresh = useCallback(() => {\n    loadActivity();\n  }, [loadActivity]);\n\n  // Auto-load on mount and when dependencies change\n  useEffect(() => {\n    if (autoLoad) {\n      loadActivity();\n    }\n  }, [autoLoad, loadActivity]);\n\n  return {\n    activity,\n    stats,\n    loading,\n    error,\n    refresh,\n  };\n}","import { useState, useCallback } from 'react';\nimport { audit } from '../services/audit.service';\nimport { AuditEventQuery, AuditEventResult, EventFilters } from '../types';\n\nexport function useAuditSearch() {\n  const [result, setResult] = useState<AuditEventResult | null>(null);\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<Error | null>(null);\n  const [filters, setFilters] = useState<EventFilters>({});\n  const [page, setPage] = useState(1);\n  const [pageSize, setPageSize] = useState(50);\n\n  const search = useCallback(async (query?: AuditEventQuery) => {\n    setLoading(true);\n    setError(null);\n\n    try {\n      const searchQuery: AuditEventQuery = query || {\n        filters,\n        pagination: {\n          page,\n          limit: pageSize,\n        },\n      };\n\n      const searchResult = await audit.query(searchQuery);\n      setResult(searchResult);\n    } catch (err: any) {\n      setError(err);\n    } finally {\n      setLoading(false);\n    }\n  }, [filters, page, pageSize]);\n\n  const updateFilters = useCallback((newFilters: Partial<EventFilters>) => {\n    setFilters(prev => ({ ...prev, ...newFilters }));\n    setPage(1); // Reset to first page when filters change\n  }, []);\n\n  const clearFilters = useCallback(() => {\n    setFilters({});\n    setPage(1);\n  }, []);\n\n  const nextPage = useCallback(() => {\n    if (result && result.hasMore) {\n      setPage(prev => prev + 1);\n    }\n  }, [result]);\n\n  const previousPage = useCallback(() => {\n    if (page > 1) {\n      setPage(prev => prev - 1);\n    }\n  }, [page]);\n\n  const goToPage = useCallback((pageNumber: number) => {\n    if (pageNumber >= 1) {\n      setPage(pageNumber);\n    }\n  }, []);\n\n  const changePageSize = useCallback((size: number) => {\n    setPageSize(size);\n    setPage(1); // Reset to first page when page size changes\n  }, []);\n\n  return {\n    result,\n    loading,\n    error,\n    filters,\n    page,\n    pageSize,\n    search,\n    updateFilters,\n    clearFilters,\n    nextPage,\n    previousPage,\n    goToPage,\n    changePageSize,\n  };\n}","import { useCallback } from 'react';\nimport { useAuth } from '../../auth/hooks/useAuth';\nimport { privacyAuditLogger } from '../services/privacyAuditLogger';\nimport type { PHIFields } from '../services/privacyAuditLogger';\n\nexport interface UsePrivacyAuditLogOptions {\n  defaultMetadata?: Record<string, any>;\n  autoIncludeUser?: boolean;\n}\n\nexport interface PrivacyAuditLogFunction {\n  (\n    action: string,\n    options?: {\n      resourceType?: string;\n      resourceId?: string;\n      resourceName?: string;\n      phi?: PHIFields;\n      metadata?: Record<string, any>;\n      severity?: 'low' | 'medium' | 'high' | 'critical';\n      success?: boolean;\n      error?: string;\n    }\n  ): Promise<string>;\n}\n\nexport interface UsePrivacyAuditLogReturn {\n  logEvent: PrivacyAuditLogFunction;\n  logPHIAccess: (\n    patientId: string,\n    accessType: 'view' | 'update' | 'delete',\n    phiData?: PHIFields\n  ) => Promise<string>;\n  logError: (\n    action: string,\n    error: Error | string,\n    options?: {\n      resourceType?: string;\n      resourceId?: string;\n      metadata?: Record<string, any>;\n    }\n  ) => Promise<string>;\n}\n\n/**\n * Hook for privacy-aware audit logging with automatic user context\n */\nexport function usePrivacyAuditLog(\n  options: UsePrivacyAuditLogOptions = {}\n): UsePrivacyAuditLogReturn {\n  const { user } = useAuth();\n  const { defaultMetadata = {}, autoIncludeUser = true } = options;\n  \n  const logEvent: PrivacyAuditLogFunction = useCallback(\n    async (action, eventOptions = {}) => {\n      const actor = autoIncludeUser && user\n        ? {\n            id: user.uid,\n            email: user.email || undefined,\n            name: user.displayName || undefined,\n            role: user.customClaims?.role || undefined,\n          }\n        : { id: 'anonymous' };\n      \n      const metadata = {\n        ...defaultMetadata,\n        ...eventOptions.metadata,\n        userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n        timestamp: new Date().toISOString(),\n      };\n      \n      return privacyAuditLogger.logEvent({\n        actor,\n        action,\n        resource: eventOptions.resourceType\n          ? {\n              type: eventOptions.resourceType,\n              id: eventOptions.resourceId || '',\n              name: eventOptions.resourceName,\n            }\n          : undefined,\n        phi: eventOptions.phi,\n        metadata,\n        severity: eventOptions.severity,\n        success: eventOptions.success,\n        error: eventOptions.error,\n      });\n    },\n    [user, autoIncludeUser, defaultMetadata]\n  );\n  \n  const logPHIAccess = useCallback(\n    async (\n      patientId: string,\n      accessType: 'view' | 'update' | 'delete',\n      phiData?: PHIFields\n    ) => {\n      return logEvent(`phi_${accessType}`, {\n        resourceType: 'patient',\n        resourceId: patientId,\n        phi: phiData,\n        severity: accessType === 'delete' ? 'high' : 'medium',\n      });\n    },\n    [logEvent]\n  );\n  \n  const logError = useCallback(\n    async (\n      action: string,\n      error: Error | string,\n      errorOptions?: {\n        resourceType?: string;\n        resourceId?: string;\n        metadata?: Record<string, any>;\n      }\n    ) => {\n      const errorMessage = error instanceof Error ? error.message : error;\n      const errorStack = error instanceof Error ? error.stack : undefined;\n      \n      return logEvent(action, {\n        ...errorOptions,\n        success: false,\n        error: errorMessage,\n        severity: 'high',\n        metadata: {\n          ...errorOptions?.metadata,\n          errorStack,\n          errorType: error instanceof Error ? error.name : 'Error',\n        },\n      });\n    },\n    [logEvent]\n  );\n  \n  return {\n    logEvent,\n    logPHIAccess,\n    logError,\n  };\n}\n\n/**\n * Hook for tracking PHI field access with automatic logging\n */\nexport function usePHIFieldTracking(patientId: string) {\n  const { logPHIAccess } = usePrivacyAuditLog();\n  \n  const trackFieldAccess = useCallback(\n    (fieldName: string, value: any, accessType: 'view' | 'update' = 'view') => {\n      // Log the access without exposing the actual value\n      logPHIAccess(patientId, accessType, {\n        [fieldName]: '***REDACTED***', // Log that field was accessed without the value\n      });\n      \n      return value;\n    },\n    [patientId, logPHIAccess]\n  );\n  \n  const createTrackedField = useCallback(\n    <T>(fieldName: string) => ({\n      get: (value: T): T => trackFieldAccess(fieldName, value, 'view'),\n      set: (value: T): T => trackFieldAccess(fieldName, value, 'update'),\n    }),\n    [trackFieldAccess]\n  );\n  \n  return {\n    trackFieldAccess,\n    createTrackedField,\n  };\n}","import { useCallback } from 'react';\nimport { useAuthContext } from '../providers/AuthProvider';\n\nexport function useAuth() {\n  const {\n    user,\n    loading,\n    error,\n    isAuthenticated,\n    signIn,\n    signUp,\n    signOut,\n    signInWithProvider,\n    sendPasswordResetEmail,\n  } = useAuthContext();\n\n  const signInWithGoogle = useCallback(() => signInWithProvider('google'), [signInWithProvider]);\n  const signInWithGithub = useCallback(() => signInWithProvider('github'), [signInWithProvider]);\n\n  return {\n    user,\n    loading,\n    error,\n    isAuthenticated,\n    signIn,\n    signUp,\n    signOut,\n    signInWithGoogle,\n    signInWithGithub,\n    sendPasswordResetEmail,\n  };\n}","'use client';\n\nimport React, { createContext, useContext, useEffect, useState, useCallback } from 'react';\nimport { AuthUser, AuthState, AuthConfig } from '../types';\nimport { getAuthInstance, initAuth } from '../services/auth.service';\n\ninterface AuthContextValue extends AuthState {\n  signIn: (email: string, password: string, rememberMe?: boolean) => Promise<AuthUser>;\n  signUp: (email: string, password: string, displayName?: string) => Promise<AuthUser>;\n  signOut: () => Promise<void>;\n  signInWithProvider: (provider: 'google' | 'github') => Promise<AuthUser>;\n  sendPasswordResetEmail: (email: string) => Promise<void>;\n  refreshUser: () => Promise<void>;\n}\n\nconst AuthContext = createContext<AuthContextValue | undefined>(undefined);\n\ninterface AuthProviderProps {\n  children: React.ReactNode;\n  config?: AuthConfig;\n}\n\nexport function AuthProvider({ children, config }: AuthProviderProps) {\n  const [state, setState] = useState<AuthState>({\n    user: null,\n    loading: true,\n    error: null,\n    isAuthenticated: false,\n  });\n\n  // Initialize auth service if config provided\n  useEffect(() => {\n    if (config) {\n      initAuth(config);\n    }\n  }, [config]);\n\n  // Subscribe to auth state changes\n  useEffect(() => {\n    try {\n      const auth = getAuthInstance();\n      \n      const unsubscribe = auth.onAuthStateChange((user) => {\n        setState({\n          user,\n          loading: false,\n          error: null,\n          isAuthenticated: !!user,\n        });\n      });\n\n      return unsubscribe;\n    } catch (error) {\n      setState({\n        user: null,\n        loading: false,\n        error: {\n          code: 'auth/not-initialized',\n          message: 'Auth not initialized. Provide config to AuthProvider.',\n        },\n        isAuthenticated: false,\n      });\n      return () => {}; // Return empty cleanup function\n    }\n  }, []);\n\n  const signIn = useCallback(async (email: string, password: string, rememberMe = false) => {\n    setState(prev => ({ ...prev, loading: true, error: null }));\n    \n    try {\n      const auth = getAuthInstance();\n      const { user } = await auth.signIn({ email, password, rememberMe });\n      \n      setState({\n        user,\n        loading: false,\n        error: null,\n        isAuthenticated: true,\n      });\n      \n      return user;\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        loading: false,\n        error,\n      }));\n      throw error;\n    }\n  }, []);\n\n  const signUp = useCallback(async (email: string, password: string, displayName?: string) => {\n    setState(prev => ({ ...prev, loading: true, error: null }));\n    \n    try {\n      const auth = getAuthInstance();\n      const { user } = await auth.signUp({ email, password, displayName });\n      \n      setState({\n        user,\n        loading: false,\n        error: null,\n        isAuthenticated: true,\n      });\n      \n      return user;\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        loading: false,\n        error,\n      }));\n      throw error;\n    }\n  }, []);\n\n  const signOut = useCallback(async () => {\n    setState(prev => ({ ...prev, loading: true, error: null }));\n    \n    try {\n      const auth = getAuthInstance();\n      await auth.signOut();\n      \n      setState({\n        user: null,\n        loading: false,\n        error: null,\n        isAuthenticated: false,\n      });\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        loading: false,\n        error,\n      }));\n      throw error;\n    }\n  }, []);\n\n  const signInWithProvider = useCallback(async (provider: 'google' | 'github') => {\n    setState(prev => ({ ...prev, loading: true, error: null }));\n    \n    try {\n      const auth = getAuthInstance();\n      const { user } = await auth.signInWith(provider);\n      \n      setState({\n        user,\n        loading: false,\n        error: null,\n        isAuthenticated: true,\n      });\n      \n      return user;\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        loading: false,\n        error,\n      }));\n      throw error;\n    }\n  }, []);\n\n  const sendPasswordResetEmail = useCallback(async (email: string) => {\n    try {\n      const auth = getAuthInstance();\n      await auth.sendPasswordResetEmail(email);\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        error,\n      }));\n      throw error;\n    }\n  }, []);\n\n  const refreshUser = useCallback(async () => {\n    if (!state.user) return;\n    \n    setState(prev => ({ ...prev, loading: true }));\n    \n    try {\n      // Force token refresh to get latest custom claims\n      await state.user.getIdToken(true);\n      const auth = getAuthInstance();\n      const currentUser = auth.getCurrentUser();\n      \n      setState(prev => ({\n        ...prev,\n        user: currentUser,\n        loading: false,\n      }));\n    } catch (error: any) {\n      setState(prev => ({\n        ...prev,\n        loading: false,\n        error,\n      }));\n    }\n  }, [state.user]);\n\n  const value: AuthContextValue = {\n    ...state,\n    signIn,\n    signUp,\n    signOut,\n    signInWithProvider,\n    sendPasswordResetEmail,\n    refreshUser,\n  };\n\n  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\n}\n\nexport function useAuthContext() {\n  const context = useContext(AuthContext);\n  if (context === undefined) {\n    throw new Error('useAuthContext must be used within an AuthProvider');\n  }\n  return context;\n}","import { \n  initializeApp, \n  getApps, \n  getApp,\n  FirebaseApp \n} from 'firebase/app';\nimport {\n  getAuth,\n  Auth as FirebaseAuth,\n  createUserWithEmailAndPassword,\n  signInWithEmailAndPassword,\n  signOut as firebaseSignOut,\n  onAuthStateChanged,\n  User as FirebaseUser,\n  GoogleAuthProvider,\n  GithubAuthProvider,\n  signInWithPopup,\n  sendPasswordResetEmail,\n  updateProfile,\n  setPersistence,\n  browserLocalPersistence,\n  browserSessionPersistence,\n} from 'firebase/auth';\nimport { \n  AuthConfig, \n  AuthUser, \n  SignInOptions, \n  SignUpOptions,\n  AuthProvider,\n  AuthError \n} from '../types';\n\nclass AuthService {\n  private app: FirebaseApp;\n  private auth: FirebaseAuth;\n  private config: AuthConfig;\n  private customClaimsCache: Map<string, any> = new Map();\n\n  constructor(config: AuthConfig) {\n    this.config = config;\n    \n    // Initialize Firebase app\n    this.app = getApps().length > 0 \n      ? getApp() \n      : initializeApp(config.firebaseConfig);\n    \n    this.auth = getAuth(this.app);\n  }\n\n  // Initialize auth with configuration\n  async initialize(): Promise<void> {\n    // Set up auth state observer\n    onAuthStateChanged(this.auth, async (user) => {\n      if (user) {\n        await this.enhanceUser(user);\n        if (this.config.onUserCreated && this.isNewUser(user)) {\n          await this.config.onUserCreated(user as AuthUser);\n        }\n      }\n    });\n  }\n\n  // Sign up with email and password\n  async signUp(options: SignUpOptions): Promise<{ user: AuthUser }> {\n    try {\n      const { email, password, displayName, photoURL, metadata } = options;\n      \n      const userCredential = await createUserWithEmailAndPassword(\n        this.auth, \n        email, \n        password\n      );\n\n      // Update profile if display name or photo provided\n      if (displayName || photoURL) {\n        await updateProfile(userCredential.user, {\n          displayName,\n          photoURL,\n        });\n      }\n\n      // Store metadata in custom claims (server-side required)\n      if (metadata) {\n        await this.setUserMetadata(userCredential.user.uid, metadata);\n      }\n\n      const user = await this.enhanceUser(userCredential.user);\n      return { user };\n    } catch (error: any) {\n      throw this.normalizeError(error);\n    }\n  }\n\n  // Sign in with email and password\n  async signIn(options: SignInOptions): Promise<{ user: AuthUser }> {\n    try {\n      const { email, password, rememberMe = false } = options;\n      \n      // Set persistence based on remember me option\n      await setPersistence(\n        this.auth,\n        rememberMe ? browserLocalPersistence : browserSessionPersistence\n      );\n\n      const userCredential = await signInWithEmailAndPassword(\n        this.auth,\n        email,\n        password\n      );\n\n      const user = await this.enhanceUser(userCredential.user);\n      return { user };\n    } catch (error: any) {\n      throw this.normalizeError(error);\n    }\n  }\n\n  // Sign in with social provider\n  async signInWith(provider: AuthProvider): Promise<{ user: AuthUser }> {\n    try {\n      let authProvider;\n      \n      switch (provider) {\n        case 'google':\n          authProvider = new GoogleAuthProvider();\n          break;\n        case 'github':\n          authProvider = new GithubAuthProvider();\n          break;\n        default:\n          throw new Error(`Provider ${provider} not supported yet`);\n      }\n\n      const userCredential = await signInWithPopup(this.auth, authProvider);\n      const user = await this.enhanceUser(userCredential.user);\n      return { user };\n    } catch (error: any) {\n      throw this.normalizeError(error);\n    }\n  }\n\n  // Sign out\n  async signOut(): Promise<void> {\n    try {\n      await firebaseSignOut(this.auth);\n      this.customClaimsCache.clear();\n    } catch (error: any) {\n      throw this.normalizeError(error);\n    }\n  }\n\n  // Send password reset email\n  async sendPasswordResetEmail(email: string): Promise<void> {\n    try {\n      await sendPasswordResetEmail(this.auth, email);\n    } catch (error: any) {\n      throw this.normalizeError(error);\n    }\n  }\n\n  // Get current user\n  getCurrentUser(): AuthUser | null {\n    const user = this.auth.currentUser;\n    if (!user) return null;\n    \n    // Return cached enhanced user\n    return this.getCachedEnhancedUser(user);\n  }\n\n  // Subscribe to auth state changes\n  onAuthStateChange(callback: (user: AuthUser | null) => void): () => void {\n    return onAuthStateChanged(this.auth, async (user) => {\n      if (user) {\n        const enhancedUser = await this.enhanceUser(user);\n        callback(enhancedUser);\n      } else {\n        callback(null);\n      }\n    });\n  }\n\n  // Enhance Firebase user with custom claims and additional data\n  private async enhanceUser(user: FirebaseUser): Promise<AuthUser> {\n    const tokenResult = await user.getIdTokenResult();\n    const customClaims = tokenResult.claims;\n    \n    // Cache custom claims\n    this.customClaimsCache.set(user.uid, customClaims);\n\n    const enhancedUser: AuthUser = {\n      ...user,\n      customClaims,\n      role: customClaims.role as string | undefined,\n      roles: customClaims.roles as string[] | undefined,\n      department: customClaims.department as string | undefined,\n      departments: customClaims.departments as string[] | undefined,\n      isAdmin: customClaims.isAdmin as boolean | undefined,\n      isSuperAdmin: customClaims.isSuperAdmin as boolean | undefined,\n      permissions: customClaims.permissions as string[] | undefined,\n    };\n\n    return enhancedUser;\n  }\n\n  // Get cached enhanced user\n  private getCachedEnhancedUser(user: FirebaseUser): AuthUser {\n    const customClaims = this.customClaimsCache.get(user.uid) || {};\n    \n    return {\n      ...user,\n      customClaims,\n      role: customClaims.role as string | undefined,\n      permissions: customClaims.permissions as string[] | undefined,\n      department: customClaims.department as string | undefined,\n    };\n  }\n\n  // Check if user is new (created within last minute)\n  private isNewUser(user: FirebaseUser): boolean {\n    if (!user.metadata.creationTime) return false;\n    \n    const creationTime = new Date(user.metadata.creationTime).getTime();\n    const now = Date.now();\n    const oneMinute = 60 * 1000;\n    \n    return now - creationTime < oneMinute;\n  }\n\n  // Set user metadata (requires server-side implementation)\n  private async setUserMetadata(_uid: string, _metadata: any): Promise<void> {\n    // This would typically call your backend API to set custom claims\n    console.warn('setUserMetadata requires server-side implementation');\n  }\n\n  // Normalize Firebase errors to consistent format\n  private normalizeError(error: any): AuthError {\n    const errorCode = error.code || 'unknown';\n    let message = error.message || 'An unknown error occurred';\n\n    // Provide user-friendly error messages\n    switch (errorCode) {\n      case 'auth/invalid-email':\n        message = 'The email address is not valid.';\n        break;\n      case 'auth/user-disabled':\n        message = 'This user account has been disabled.';\n        break;\n      case 'auth/user-not-found':\n        message = 'No user found with this email address.';\n        break;\n      case 'auth/wrong-password':\n        message = 'The password is incorrect.';\n        break;\n      case 'auth/email-already-in-use':\n        message = 'An account already exists with this email address.';\n        break;\n      case 'auth/weak-password':\n        message = 'The password must be at least 6 characters long.';\n        break;\n      case 'auth/popup-closed-by-user':\n        message = 'The sign-in popup was closed before completing sign in.';\n        break;\n    }\n\n    return {\n      code: errorCode,\n      message,\n      originalError: error,\n    };\n  }\n\n  // Get Firebase Auth instance (for advanced usage)\n  getAuth(): FirebaseAuth {\n    return this.auth;\n  }\n\n  // Get Firebase App instance\n  getApp(): FirebaseApp {\n    return this.app;\n  }\n}\n\n// Singleton instance\nlet authInstance: AuthService | null = null;\n\n// Initialize auth service\nexport function initAuth(config: AuthConfig): AuthService {\n  if (!authInstance) {\n    authInstance = new AuthService(config);\n    authInstance.initialize();\n  }\n  return authInstance;\n}\n\n// Get auth instance\nexport function getAuthInstance(): AuthService {\n  if (!authInstance) {\n    throw new Error('Auth not initialized. Call initAuth first.');\n  }\n  return authInstance;\n}","'use client';\n\nimport React from 'react';\nimport { Paper, Title, Text } from '@mantine/core';\n\ninterface AuditLogViewerProps {\n  filters?: any;\n  columns?: string[];\n  exportFormats?: string[];\n}\n\nexport function AuditLogViewer({ filters, columns, exportFormats }: AuditLogViewerProps) {\n  return (\n    <Paper shadow=\"sm\" radius=\"md\" p=\"lg\">\n      <Title order={4}>Audit Log Viewer</Title>\n      <Text c=\"dimmed\" size=\"sm\">Audit log viewer coming soon</Text>\n    </Paper>\n  );\n}","'use client';\n\nimport React from 'react';\nimport { Paper, Title, Text } from '@mantine/core';\n\ninterface ActivityTimelineProps {\n  userId: string;\n  groupBy?: 'hour' | 'day' | 'week';\n  showDetails?: boolean;\n}\n\nexport function ActivityTimeline({ userId, groupBy, showDetails }: ActivityTimelineProps) {\n  return (\n    <Paper shadow=\"sm\" radius=\"md\" p=\"lg\">\n      <Title order={4}>Activity Timeline</Title>\n      <Text c=\"dimmed\" size=\"sm\">Activity timeline coming soon</Text>\n    </Paper>\n  );\n}","'use client';\n\nimport React from 'react';\nimport { Paper, Title, Text } from '@mantine/core';\nimport { AuditEvent } from '../../types';\n\ninterface AuditEventDetailsProps {\n  event: AuditEvent;\n}\n\nexport function AuditEventDetails({ event }: AuditEventDetailsProps) {\n  return (\n    <Paper shadow=\"sm\" radius=\"md\" p=\"lg\">\n      <Title order={4}>Audit Event Details</Title>\n      <Text c=\"dimmed\" size=\"sm\">Event details viewer coming soon</Text>\n    </Paper>\n  );\n}","'use client';\n\nimport React from 'react';\nimport { Paper, Title, Text } from '@mantine/core';\n\ninterface AuditSearchBarProps {\n  onSearch?: (query: string) => void;\n}\n\nexport function AuditSearchBar({ onSearch }: AuditSearchBarProps) {\n  return (\n    <Paper shadow=\"sm\" radius=\"md\" p=\"lg\">\n      <Title order={4}>Audit Search</Title>\n      <Text c=\"dimmed\" size=\"sm\">Search functionality coming soon</Text>\n    </Paper>\n  );\n}","import { AuditEvent, AuditFormatter as IAuditFormatter } from '../types';\n\nexport class AuditFormatter {\n  static defaultFormatter: IAuditFormatter = {\n    name: 'default',\n    format: (event: AuditEvent) => event,\n  };\n\n  static jsonFormatter: IAuditFormatter = {\n    name: 'json',\n    format: (event: AuditEvent) => {\n      return {\n        ...event,\n        timestamp: event.timestamp.toISOString(),\n        formatted: true,\n      } as any;\n    },\n  };\n\n  static humanReadableFormatter: IAuditFormatter = {\n    name: 'human-readable',\n    format: (event: AuditEvent) => {\n      const formatted = { ...event };\n      \n      // Format the action as human readable\n      formatted.action = event.action\n        .split('.')\n        .map(part => part.charAt(0).toUpperCase() + part.slice(1))\n        .join(' ');\n      \n      return formatted;\n    },\n  };\n\n  static privacyFormatter: IAuditFormatter = {\n    name: 'privacy',\n    format: (event: AuditEvent) => {\n      const formatted = { ...event };\n      \n      // Redact sensitive information\n      if (formatted.actor.email) {\n        const [localPart, domain] = formatted.actor.email.split('@');\n        formatted.actor.email = `${localPart.slice(0, 2)}***@${domain}`;\n      }\n      \n      if (formatted.context?.ip) {\n        const parts = formatted.context.ip.split('.');\n        formatted.context.ip = `${parts[0]}.${parts[1]}.xxx.xxx`;\n      }\n      \n      return formatted;\n    },\n  };\n\n  static compactFormatter: AuditFormatter = {\n    name: 'compact',\n    format: (event: AuditEvent) => {\n      return {\n        id: event.id,\n        timestamp: event.timestamp,\n        action: event.action,\n        actor: event.actor.id,\n        resource: `${event.resource.type}:${event.resource.id}`,\n        result: event.result,\n      } as any;\n    },\n  };\n}","import { AuditEvent, AuditEventExport } from '../types';\n\nexport class AuditExporter {\n  static async exportToCSV(events: AuditEvent[], options?: Partial<AuditEventExport>): Promise<string> {\n    const fields = options?.fields || [\n      'id',\n      'timestamp',\n      'actor.id',\n      'actor.type',\n      'action',\n      'resource.type',\n      'resource.id',\n      'result',\n    ];\n\n    // Create header row\n    const header = fields.join(',');\n    \n    // Create data rows\n    const rows = events.map(event => {\n      return fields.map(field => {\n        const value = this.getNestedValue(event, field);\n        // Escape values containing commas or quotes\n        if (typeof value === 'string' && (value.includes(',') || value.includes('\"'))) {\n          return `\"${value.replace(/\"/g, '\"\"')}\"`;\n        }\n        return value?.toString() || '';\n      }).join(',');\n    });\n\n    return [header, ...rows].join('\\n');\n  }\n\n  static async exportToJSON(events: AuditEvent[], options?: Partial<AuditEventExport>): Promise<string> {\n    const fields = options?.fields;\n    \n    if (fields) {\n      // Export only specified fields\n      const filtered = events.map(event => {\n        const result: any = {};\n        fields.forEach(field => {\n          result[field] = this.getNestedValue(event, field);\n        });\n        return result;\n      });\n      return JSON.stringify(filtered, null, 2);\n    }\n\n    return JSON.stringify(events, null, 2);\n  }\n\n  static async export(events: AuditEvent[], options: AuditEventExport): Promise<Blob> {\n    let content: string;\n    let mimeType: string;\n\n    switch (options.format) {\n      case 'csv':\n        content = await this.exportToCSV(events, options);\n        mimeType = 'text/csv';\n        break;\n      case 'json':\n        content = await this.exportToJSON(events, options);\n        mimeType = 'application/json';\n        break;\n      default:\n        throw new Error(`Unsupported export format: ${options.format}`);\n    }\n\n    return new Blob([content], { type: mimeType });\n  }\n\n  static download(blob: Blob, filename: string): void {\n    const url = URL.createObjectURL(blob);\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = filename;\n    document.body.appendChild(a);\n    a.click();\n    document.body.removeChild(a);\n    URL.revokeObjectURL(url);\n  }\n\n  private static getNestedValue(obj: any, path: string): any {\n    return path.split('.').reduce((current, key) => current?.[key], obj);\n  }\n}"],"mappings":"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","names":["audit","query","import_crypto","query","import_firestore","collection","mapping","doc","import_firestore","import_app","collection","query","error","import_react","import_react","import_react","query","import_react","import_react","import_react","import_app","sendPasswordResetEmail","logPHIAccess","import_jsx_runtime","import_core","import_jsx_runtime","import_core","import_jsx_runtime","import_core","import_jsx_runtime"]}