import Combine import Foundation @MainActor protocol AnalyticsTracking { func track(_ event: String, attributes: [String: String]) } struct HermesTrackedEvent: Identifiable, Equatable { let id = UUID() let event: String let attributes: [String: String] let timestamp: Date } @MainActor final class HermesAnalyticsClient: ObservableObject, AnalyticsTracking { @Published private(set) var trackedEvents: [HermesTrackedEvent] = [] func track(_ event: String, attributes: [String: String]) { trackedEvents.append( HermesTrackedEvent( event: event, attributes: attributes, timestamp: Date() ) ) } func flush(using repository: HermesRepository) async { guard repository.currentSession != nil else { return } let pendingEvents = trackedEvents guard !pendingEvents.isEmpty else { return } do { try await repository.submitAnalyticsBatch( HermesAnalyticsBatchRequest( events: pendingEvents.map { event in HermesAnalyticsEventInput( eventName: event.event, occurredAt: event.timestamp, attributes: event.attributes.map { HermesAnalyticsAttributeInput(key: $0.key, value: $0.value) } ) } ) ) let deliveredIds = Set(pendingEvents.map(\.id)) trackedEvents.removeAll { deliveredIds.contains($0.id) } } catch { return } } }