import Foundation struct UsageCacheEntry: Codable, Sendable { let fetchedAt: Date let payload: Data } actor UsageCache { static let shared = UsageCache() private let directory: URL private let fileManager = FileManager.default init() { let base = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first! directory = base.appendingPathComponent("ai-usage", isDirectory: true) try? fileManager.createDirectory(at: directory, withIntermediateDirectories: true) } func load(provider: ProviderID, maxAge: TimeInterval) -> UsageCacheEntry? { let url = cacheURL(for: provider) guard fileManager.fileExists(atPath: url.path), let data = try? Data(contentsOf: url), let entry = try? JSONDecoder().decode(UsageCacheEntry.self, from: data) else { return nil } if Date().timeIntervalSince(entry.fetchedAt) > maxAge { return nil } return entry } func loadStale(provider: ProviderID) -> UsageCacheEntry? { let url = cacheURL(for: provider) guard fileManager.fileExists(atPath: url.path), let data = try? Data(contentsOf: url), let entry = try? JSONDecoder().decode(UsageCacheEntry.self, from: data) else { return nil } return entry } func save(provider: ProviderID, payload: Data) { let entry = UsageCacheEntry(fetchedAt: Date(), payload: payload) guard let data = try? JSONEncoder().encode(entry) else { return } let url = cacheURL(for: provider) try? data.write(to: url, options: .atomic) try? fileManager.setAttributes([.posixPermissions: 0o600], ofItemAtPath: url.path) } private func cacheURL(for provider: ProviderID) -> URL { directory.appendingPathComponent("\(provider.rawValue)-usage.json") } }