import Foundation enum UserFacingError { static let generic = "Something went wrong. Please try again." static func message(for error: Error) -> String { if shouldUseGenericMessage(for: error) { return generic } let raw = (error as? LocalizedError)?.errorDescription ?? error.localizedDescription return sanitized(raw) ?? generic } static func networkMessage(for error: URLError) -> String { switch error.code { case .notConnectedToInternet: "You appear to be offline. Check your internet connection and try again." case .timedOut: "The request timed out. Please try again." case .networkConnectionLost: "Couldn't connect. Please try again." default: generic } } static func sanitized(_ message: String) -> String? { let trimmed = message.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return nil } guard !containsSensitiveContent(trimmed.lowercased()) else { return nil } return trimmed } private static func shouldUseGenericMessage(for error: Error) -> Bool { if error is DecodingError || error is EncodingError { return true } switch error { case PostGenerationError.invalidResponse, CommentGenerationError.invalidResponse, TitleOptimizationError.invalidResponse: return true default: return false } } private static func containsSensitiveContent(_ lower: String) -> Bool { lower.contains("api key") || lower.contains("apikey") || lower.contains("openai") || lower.contains("invalid_api_key") || lower.contains("incorrect api key") || lower.contains("bearer ") || lower.contains("sk-") || lower.contains("authentication") || lower.contains("not configured") || lower.contains("response format") || lower.contains("request failed") || lower.contains("ai request failed") || lower.contains("couldn't reach the ai service") || lower.contains("nsurlerrordomain") || lower.contains("cocoaerrordomain") || lower.contains("error domain") || (lower.contains("could not read") && lower.contains("response")) || (lower.contains("couldn't parse") && lower.contains("ai")) || (lower.contains("status") && lower.range(of: #"\b[1-5]\d{2}\b"#, options: .regularExpression) != nil) } }