112 lines · 4.2 KB · Swift
RawDownload
import CodexBarCoreimport Foundation struct ProviderSpec {    let style: IconStyle    let isEnabled: @MainActor () -> Bool    let descriptor: ProviderDescriptor    let makeFetchContext: @MainActor () -> ProviderFetchContext} struct ProviderRegistry {    let metadata: [UsageProvider: ProviderMetadata]     static let shared: ProviderRegistry = .init()     init(metadata: [UsageProvider: ProviderMetadata] = ProviderDescriptorRegistry.metadata) {        self.metadata = metadata    }     @MainActor    func specs(        settings: SettingsStore,        metadata: [UsageProvider: ProviderMetadata],        codexFetcher: UsageFetcher,        claudeFetcher: any ClaudeUsageFetching,        browserDetection: BrowserDetection) -> [UsageProvider: ProviderSpec]    {        var specs: [UsageProvider: ProviderSpec] = [:]        specs.reserveCapacity(UsageProvider.allCases.count)         for provider in UsageProvider.allCases {            let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)            let meta = metadata[provider]!            let spec = ProviderSpec(                style: descriptor.branding.iconStyle,                isEnabled: { settings.isProviderEnabled(provider: provider, metadata: meta) },                descriptor: descriptor,                makeFetchContext: {                    let sourceMode = ProviderCatalog.implementation(for: provider)?                        .sourceMode(context: ProviderSourceModeContext(provider: provider, settings: settings))                        ?? .auto                    let snapshot = Self.makeSettingsSnapshot(settings: settings, tokenOverride: nil)                    let env = Self.makeEnvironment(                        base: ProcessInfo.processInfo.environment,                        provider: provider,                        settings: settings,                        tokenOverride: nil)                    let verbose = settings.isVerboseLoggingEnabled                    return ProviderFetchContext(                        runtime: .app,                        sourceMode: sourceMode,                        includeCredits: false,                        webTimeout: 60,                        webDebugDumpHTML: false,                        verbose: verbose,                        env: env,                        settings: snapshot,                        fetcher: codexFetcher,                        claudeFetcher: claudeFetcher,                        browserDetection: browserDetection)                })            specs[provider] = spec        }         return specs    }     @MainActor    static func makeSettingsSnapshot(        settings: SettingsStore,        tokenOverride: TokenAccountOverride?) -> ProviderSettingsSnapshot    {        settings.ensureTokenAccountsLoaded()        var builder = ProviderSettingsSnapshotBuilder(            debugMenuEnabled: settings.debugMenuEnabled,            debugKeepCLISessionsAlive: settings.debugKeepCLISessionsAlive)        let context = ProviderSettingsSnapshotContext(settings: settings, tokenOverride: tokenOverride)        for implementation in ProviderCatalog.all {            if let contribution = implementation.settingsSnapshot(context: context) {                builder.apply(contribution)            }        }        return builder.build()    }     @MainActor    static func makeEnvironment(        base: [String: String],        provider: UsageProvider,        settings: SettingsStore,        tokenOverride: TokenAccountOverride?) -> [String: String]    {        let account = ProviderTokenAccountSelection.selectedAccount(            provider: provider,            settings: settings,            override: tokenOverride)        var env = ProviderConfigEnvironment.applyAPIKeyOverride(            base: base,            provider: provider,            config: settings.providerConfig(for: provider))        // If token account is selected, use its token instead of config's apiKey        if let account, let override = TokenAccountSupportCatalog.envOverride(            for: provider,            token: account.token)        {            for (key, value) in override {                env[key] = value            }        }        return env    }}