// ── Kill Switch Client ────────────────────────────────────── // Checks platform-service kill switch at app launch. // If the app is disabled server-side, surfaces a maintenance message. // Fails open — network errors allow the app to run. import Foundation /// Generic kill switch client for all ByteLyst iOS apps. /// Checks GET /api/settings/kill-switch?productId=X at launch. public final class BLKillSwitchClient { private let config: BLPlatformConfig /// Whether the app is disabled by the server. public private(set) var isDisabled = false /// Maintenance message from the server (empty if not disabled). public private(set) var maintenanceMessage = "" public init(config: BLPlatformConfig) { self.config = config } /// Check kill switch status. Non-blocking — defaults to enabled on failure (fail open). public func check() async { guard let url = URL(string: "\(config.baseURL)/api/settings/kill-switch?productId=\(config.productId)") else { return } var request = URLRequest(url: url) request.timeoutInterval = 5 request.setValue(config.productId, forHTTPHeaderField: "X-Product-Id") request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Request-Id") do { let (data, response) = try await URLSession.shared.data(for: request) guard let http = response as? HTTPURLResponse, http.statusCode == 200 else { return } struct KillSwitchResponse: Codable { let enabled: Bool? let disabled: Bool? let message: String? } let result = try JSONDecoder().decode(KillSwitchResponse.self, from: data) // Support both `enabled: false` and `disabled: true` patterns if result.disabled == true || result.enabled == false { isDisabled = true maintenanceMessage = result.message ?? "\(config.productId) is temporarily unavailable for maintenance." } } catch { // Network error — allow the app to run (fail open) } } /// Reset the kill switch state (e.g. for retry). public func reset() { isDisabled = false maintenanceMessage = "" } }