| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- 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)
- }
- }
|