// Utils/Constants.swift // --------------------- // Central place for app-wide constants. import Foundation // MARK: - Server selection /// The two known JQC servers the inspector can connect to. nonisolated enum ServerOption: String, CaseIterable, Sendable { case primary = "https://jqc.ltservicesinc.com" case secondary = "https://jqc1.ltservicesinc.com" var displayName: String { switch self { case .primary: return "jqc (Primary)" case .secondary: return "jqc1 (Secondary)" } } } /// Runtime-mutable server selection backed by UserDefaults. /// Read `ServerConfig.current` anywhere you would have used `Constants.baseURL`. nonisolated enum ServerConfig { private static let defaultsKey = "com.jqc.selectedServer" /// The currently selected base URL. Reads UserDefaults on every call so /// actor-isolated callers (e.g. APIClient) always get the latest value /// without needing @MainActor access. nonisolated static var current: String { get { let raw = UserDefaults.standard.string(forKey: defaultsKey) ?? "" return ServerOption(rawValue: raw)?.rawValue ?? ServerOption.primary.rawValue } } /// Persist the chosen server. Call from @MainActor UI code only. @MainActor static func select(_ option: ServerOption) { UserDefaults.standard.set(option.rawValue, forKey: defaultsKey) } /// The current selection as a `ServerOption` (for UI binding). @MainActor static var selectedOption: ServerOption { let raw = UserDefaults.standard.string(forKey: defaultsKey) ?? "" return ServerOption(rawValue: raw) ?? .primary } } // MARK: - App-wide constants // Explicitly not @MainActor — these constants must be readable from // any actor context including APIClient and KeychainHelper. nonisolated enum Constants { nonisolated enum Keychain { static let accessToken = "com.jqc.accessToken" static let refreshToken = "com.jqc.refreshToken" static let userId = "com.jqc.userId" static let userRole = "com.jqc.userRole" static let username = "com.jqc.username" static let displayName = "com.jqc.displayName" } static let tokenRefreshBufferMinutes: Double = 5 }