155 lines · 5.4 KB · Swift
RawDownload
import Foundation public struct OpenCodeGoUsageSnapshot: Sendable {    public let isBalanceOnly: Bool    public let hasWeeklyUsage: Bool    public let hasMonthlyUsage: Bool    public let rollingUsagePercent: Double    public let weeklyUsagePercent: Double    public let monthlyUsagePercent: Double    public let rollingResetInSec: Int    public let weeklyResetInSec: Int    public let monthlyResetInSec: Int    public private(set) var zenBalanceUSD: Double?    public let renewsAt: Date?    public private(set) var daily: [CostUsageDailyReport.Entry]    public let updatedAt: Date     public init(        isBalanceOnly: Bool = false,        hasWeeklyUsage: Bool = true,        hasMonthlyUsage: Bool,        rollingUsagePercent: Double,        weeklyUsagePercent: Double,        monthlyUsagePercent: Double,        rollingResetInSec: Int,        weeklyResetInSec: Int,        monthlyResetInSec: Int,        zenBalanceUSD: Double? = nil,        renewsAt: Date? = nil,        daily: [CostUsageDailyReport.Entry] = [],        updatedAt: Date)    {        self.isBalanceOnly = isBalanceOnly        self.hasWeeklyUsage = hasWeeklyUsage        self.hasMonthlyUsage = hasMonthlyUsage        self.rollingUsagePercent = rollingUsagePercent        self.weeklyUsagePercent = weeklyUsagePercent        self.monthlyUsagePercent = monthlyUsagePercent        self.rollingResetInSec = rollingResetInSec        self.weeklyResetInSec = weeklyResetInSec        self.monthlyResetInSec = monthlyResetInSec        self.zenBalanceUSD = zenBalanceUSD        self.renewsAt = renewsAt        self.daily = daily        self.updatedAt = updatedAt    }     public static func zenBalanceOnly(balanceUSD: Double, updatedAt: Date) -> OpenCodeGoUsageSnapshot {        OpenCodeGoUsageSnapshot(            isBalanceOnly: true,            hasWeeklyUsage: false,            hasMonthlyUsage: false,            rollingUsagePercent: 0,            weeklyUsagePercent: 0,            monthlyUsagePercent: 0,            rollingResetInSec: 0,            weeklyResetInSec: 0,            monthlyResetInSec: 0,            zenBalanceUSD: balanceUSD,            updatedAt: updatedAt)    }     public func toUsageSnapshot() -> UsageSnapshot {        if self.isBalanceOnly {            return UsageSnapshot(                primary: nil,                secondary: nil,                providerCost: self.providerCostSnapshot,                opencodegoUsage: self,                updatedAt: self.updatedAt,                identity: nil)        }         let rollingReset = self.updatedAt.addingTimeInterval(TimeInterval(self.rollingResetInSec))        let primary = RateWindow(            usedPercent: self.rollingUsagePercent,            windowMinutes: 5 * 60,            resetsAt: rollingReset,            resetDescription: nil)        let secondary: RateWindow?        if self.hasWeeklyUsage {            let weeklyReset = self.updatedAt.addingTimeInterval(TimeInterval(self.weeklyResetInSec))            secondary = RateWindow(                usedPercent: self.weeklyUsagePercent,                windowMinutes: 7 * 24 * 60,                resetsAt: weeklyReset,                resetDescription: nil)        } else {            secondary = nil        }        let tertiary: RateWindow?        if self.hasMonthlyUsage {            let monthlyReset = self.updatedAt.addingTimeInterval(TimeInterval(self.monthlyResetInSec))            tertiary = RateWindow(                usedPercent: self.monthlyUsagePercent,                windowMinutes: 30 * 24 * 60,                resetsAt: monthlyReset,                resetDescription: nil)        } else {            tertiary = nil        }         var extraWindows: [NamedRateWindow]?        if let renewsAt = self.renewsAt {            let renewalWindow = RateWindow(                usedPercent: 0,                windowMinutes: nil,                resetsAt: renewsAt,                resetDescription: nil)            extraWindows = [NamedRateWindow(id: "renewal", title: "Renews", window: renewalWindow)]        }         return UsageSnapshot(            primary: primary,            secondary: secondary,            tertiary: tertiary,            extraRateWindows: extraWindows,            providerCost: self.providerCostSnapshot,            opencodegoUsage: self,            updatedAt: self.updatedAt,            identity: nil)    }     private var providerCostSnapshot: ProviderCostSnapshot? {        self.zenBalanceUSD.map {            ProviderCostSnapshot(                used: $0,                limit: 0,                currencyCode: "USD",                period: "Zen balance",                updatedAt: self.updatedAt)        }    }     public func withZenBalanceUSD(_ balance: Double?) -> OpenCodeGoUsageSnapshot {        var copy = self        copy.zenBalanceUSD = balance        return copy    }     public func withDaily(_ daily: [CostUsageDailyReport.Entry]) -> OpenCodeGoUsageSnapshot {        var copy = self        copy.daily = daily        return copy    }     /// Projects the local per-day cost buckets into the shared cost-history model so OpenCode Go    /// can reuse the same daily usage chart as Codex/Claude instead of a bespoke view.    public func toCostUsageTokenSnapshot(historyDays: Int = 30) -> CostUsageTokenSnapshot {        CostUsageFetcher.tokenSnapshot(            from: CostUsageDailyReport(data: self.daily, summary: nil),            now: self.updatedAt,            historyDays: historyDays)    }}