learning_ai_common_plat/packages/swift-platform-sdk/Sources/BLAuditLogger.swift
saravanakumardb1 23d14f33ea feat(swift-sdk): add 6 new components — BLBlobClient, BLKillSwitchClient, BLLicenseClient, BLBiometricAuth, BLCrashReporter, BLAuditLogger
New SDK components extracted from product apps:
- BLBlobClient — Azure Blob Storage upload via SAS tokens (from LysnrAI BlobService)
- BLKillSwitchClient — Kill switch check from platform-service (from LysnrAI KillSwitchService)
- BLLicenseClient — License key activation + status (from LysnrAI LicenseService)
- BLBiometricAuth — Face ID / Touch ID wrapper (from LysnrAI BiometricAuth)
- BLCrashReporter — MetricKit crash reporting (from ChronoMind CrashReporter)
- BLAuditLogger — Local rotating JSON audit log (from LysnrAI AuditLogger)

SDK now has 13 source files. Updated README with full component table
and migration status (3 apps fully migrated, 18 wrappers total).
2026-02-28 22:38:43 -08:00

84 lines
2.7 KiB
Swift

// Audit Logger
// Generic local audit logger that tracks user actions for debugging.
// Stores events in a rotating JSON file (configurable max entries).
// Product apps configure with a product-specific file name.
import Foundation
/// Audit event stored locally.
public struct BLAuditEvent: Codable, Sendable {
public let id: String
public let action: String
public let details: String?
public let timestamp: Date
public init(action: String, details: String? = nil) {
self.id = UUID().uuidString
self.action = action
self.details = details
self.timestamp = Date()
}
}
/// Generic local audit logger for all ByteLyst iOS apps.
/// Stores events in a rotating JSON file in the Documents directory.
public enum BLAuditLogger {
private static var maxEvents = 1000
private static var fileName = "audit_log.json"
/// Configure the logger with a product-specific file name and max events.
public static func configure(fileName: String = "audit_log.json", maxEvents: Int = 1000) {
self.fileName = fileName
self.maxEvents = maxEvents
}
private static var fileURL: URL {
let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
return docs.appendingPathComponent(fileName)
}
/// Log a user action.
public static func log(_ action: String, details: String? = nil) {
let event = BLAuditEvent(action: action, details: details)
var events = loadEvents()
events.append(event)
// Rotate: keep only the most recent maxEvents
if events.count > maxEvents {
events = Array(events.suffix(maxEvents))
}
saveEvents(events)
}
/// Get all logged events (newest first).
public static func getEvents(limit: Int = 100) -> [BLAuditEvent] {
let events = loadEvents()
return Array(events.suffix(limit).reversed())
}
/// Clear all audit logs.
public static func clear() {
try? FileManager.default.removeItem(at: fileURL)
}
// MARK: - Persistence
private static func loadEvents() -> [BLAuditEvent] {
guard let data = try? Data(contentsOf: fileURL),
let events = try? JSONDecoder().decode([BLAuditEvent].self, from: data) else {
return []
}
return events
}
private static func saveEvents(_ events: [BLAuditEvent]) {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
guard let data = try? encoder.encode(events) else { return }
try? data.write(to: fileURL, options: .atomic)
}
}