190 lines · 7.3 KB · Swift
RawDownload
import Foundation public enum CodexBarConfigIssueSeverity: String, Codable, Sendable {    case warning    case error} public struct CodexBarConfigIssue: Codable, Sendable, Equatable {    public let severity: CodexBarConfigIssueSeverity    public let provider: UsageProvider?    public let field: String?    public let code: String    public let message: String     public init(        severity: CodexBarConfigIssueSeverity,        provider: UsageProvider?,        field: String?,        code: String,        message: String)    {        self.severity = severity        self.provider = provider        self.field = field        self.code = code        self.message = message    }} public enum CodexBarConfigValidator {    public static func validate(_ config: CodexBarConfig) -> [CodexBarConfigIssue] {        var issues: [CodexBarConfigIssue] = []         if config.version != CodexBarConfig.currentVersion {            issues.append(CodexBarConfigIssue(                severity: .error,                provider: nil,                field: "version",                code: "version_mismatch",                message: "Unsupported config version \(config.version)."))        }         for entry in config.providers {            self.validateProvider(entry, issues: &issues)        }         return issues    }     private static func validateProvider(_ entry: ProviderConfig, issues: inout [CodexBarConfigIssue]) {        let provider = entry.id        let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)        let supportedSources = descriptor.fetchPlan.sourceModes        let supportsWeb = supportedSources.contains(.auto) || supportedSources.contains(.web)        let supportsAPI = supportedSources.contains(.api)         if let source = entry.source, !supportedSources.contains(source) {            issues.append(CodexBarConfigIssue(                severity: .error,                provider: provider,                field: "source",                code: "unsupported_source",                message: "Source \(source.rawValue) is not supported for \(provider.rawValue)."))        }         if let apiKey = entry.apiKey, !apiKey.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, !supportsAPI {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "apiKey",                code: "api_key_unused",                message: "apiKey is set but \(provider.rawValue) does not support api source."))        }         if let source = entry.source, source == .api, !supportsAPI {            issues.append(CodexBarConfigIssue(                severity: .error,                provider: provider,                field: "source",                code: "api_source_unsupported",                message: "Source api is not supported for \(provider.rawValue)."))        }         if let source = entry.source, source == .api,           entry.apiKey?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true        {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "apiKey",                code: "api_key_missing",                message: "Source api is selected but apiKey is missing for \(provider.rawValue)."))        }         if entry.cookieSource != nil, !supportsWeb {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "cookieSource",                code: "cookie_source_unused",                message: "cookieSource is set but \(provider.rawValue) does not use web cookies."))        }         if let cookieHeader = entry.cookieHeader,           !cookieHeader.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,           !supportsWeb        {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "cookieHeader",                code: "cookie_header_unused",                message: "cookieHeader is set but \(provider.rawValue) does not use web cookies."))        }         if let cookieSource = entry.cookieSource,           cookieSource == .manual,           entry.cookieHeader?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true        {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "cookieHeader",                code: "cookie_header_missing",                message: "cookieSource manual is set but cookieHeader is missing for \(provider.rawValue)."))        }         if let region = entry.region, !region.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {            switch provider {            case .minimax:                if MiniMaxAPIRegion(rawValue: region) == nil {                    issues.append(CodexBarConfigIssue(                        severity: .error,                        provider: provider,                        field: "region",                        code: "invalid_region",                        message: "Region \(region) is not a valid MiniMax region."))                }            case .zai:                if ZaiAPIRegion(rawValue: region) == nil {                    issues.append(CodexBarConfigIssue(                        severity: .error,                        provider: provider,                        field: "region",                        code: "invalid_region",                        message: "Region \(region) is not a valid z.ai region."))                }            case .alibaba:                if AlibabaCodingPlanAPIRegion(rawValue: region) == nil {                    issues.append(CodexBarConfigIssue(                        severity: .error,                        provider: provider,                        field: "region",                        code: "invalid_region",                        message: "Region \(region) is not a valid Alibaba Coding Plan region."))                }            default:                issues.append(CodexBarConfigIssue(                    severity: .warning,                    provider: provider,                    field: "region",                    code: "region_unused",                    message: "region is set but \(provider.rawValue) does not use regions."))            }        }         if let workspaceID = entry.workspaceID,           !workspaceID.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,           provider != .opencode        {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "workspaceID",                code: "workspace_unused",                message: "workspaceID is set but only opencode supports workspaceID."))        }         if let tokenAccounts = entry.tokenAccounts, !tokenAccounts.accounts.isEmpty,           TokenAccountSupportCatalog.support(for: provider) == nil        {            issues.append(CodexBarConfigIssue(                severity: .warning,                provider: provider,                field: "tokenAccounts",                code: "token_accounts_unused",                message: "tokenAccounts are set but \(provider.rawValue) does not support token accounts."))        }    }}