From d2ff1d2f2f509eb8dab31d8af0ca15d72384e414 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Fri, 22 May 2026 14:20:40 -0500 Subject: [PATCH] =?UTF-8?q?Fix=20Swift=206=20actor=20isolation=20in=20Mark?= =?UTF-8?q?sAuth=20=E2=80=94=20use=20UserDefaults=20UUID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UIDevice.current is MainActor-isolated; replaced with a stable UUID persisted in UserDefaults to avoid the async access. Co-Authored-By: Claude Sonnet 4.6 --- Marks/Services/MarksAuth.swift | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Marks/Services/MarksAuth.swift b/Marks/Services/MarksAuth.swift index 6ece686..6ea67d3 100644 --- a/Marks/Services/MarksAuth.swift +++ b/Marks/Services/MarksAuth.swift @@ -1,10 +1,9 @@ import Foundation -import UIKit -private let backendBaseURL = "https://chatai-realtime-proxy-production.up.railway.app" - -private let tokenKey = "marksJWT" -private let tokenExpiryKey = "marksJWTExpiry" +private let backendBaseURL = "https://chatai-realtime-proxy-production.up.railway.app" +private let deviceIdKey = "marksDeviceId" +private let tokenKey = "marksJWT" +private let tokenExpiryKey = "marksJWTExpiry" enum MarksAuth { static var baseURL: String { backendBaseURL } @@ -15,6 +14,13 @@ enum MarksAuth { return try await register() } + private static func deviceId() -> String { + if let existing = UserDefaults.standard.string(forKey: deviceIdKey) { return existing } + let new = UUID().uuidString + UserDefaults.standard.set(new, forKey: deviceIdKey) + return new + } + private static func cached() -> String? { guard let token = UserDefaults.standard.string(forKey: tokenKey), @@ -28,22 +34,19 @@ enum MarksAuth { guard let url = URL(string: "\(backendBaseURL)/api/auth/register") else { throw URLError(.badURL) } - let deviceId = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString + let id = deviceId() var req = URLRequest(url: url) req.httpMethod = "POST" req.setValue("application/json", forHTTPHeaderField: "Content-Type") - req.httpBody = try JSONSerialization.data(withJSONObject: ["device_id": deviceId]) + req.httpBody = try JSONSerialization.data(withJSONObject: ["device_id": id]) let (data, response) = try await URLSession.shared.data(for: req) let status = (response as? HTTPURLResponse)?.statusCode ?? 0 - guard (200...299).contains(status) else { - throw APIError.badStatus(status) - } + guard (200...299).contains(status) else { throw APIError.badStatus(status) } struct Resp: Decodable { let access_token: String; let expires_in: Int } let resp = try JSONDecoder().decode(Resp.self, from: data) UserDefaults.standard.set(resp.access_token, forKey: tokenKey) - let expiry = Date().addingTimeInterval(TimeInterval(resp.expires_in)) - UserDefaults.standard.set(expiry, forKey: tokenExpiryKey) - print("[Auth] Registered device \(deviceId.prefix(8))…") + UserDefaults.standard.set(Date().addingTimeInterval(TimeInterval(resp.expires_in)), forKey: tokenExpiryKey) + print("[Auth] Registered \(id.prefix(8))…") return resp.access_token } }