#if os(macOS) import Foundation extension OpenAIDashboardBrowserCookieImporter { private struct PendingCookieStoreMutation { let token: UUID let task: Task } @MainActor private static var pendingCookieStoreMutations: [ObjectIdentifier: PendingCookieStoreMutation] = [:] private nonisolated static let cookieCacheQueue = DispatchQueue( label: "com.steipete.codexbar.openai-cookie-cache") private nonisolated static let deadlineQueue = DispatchQueue( label: "com.steipete.codexbar.openai-cookie-deadline", qos: .userInitiated) private final class CookieLoadCompletion: @unchecked Sendable { private let lock = NSLock() private var didFinish = false func finish(_ action: () -> Void) { let shouldFinish = self.lock.withLock { guard !self.didFinish else { return false } self.didFinish = true return true } if shouldFinish { action() } } } nonisolated static func remainingTimeout( until deadline: Date?, cappedAt localLimit: TimeInterval? = nil, now: Date = Date()) throws -> TimeInterval { guard let deadline else { return localLimit.map(OpenAIDashboardFetcher.sanitizedTimeout) ?? .greatestFiniteMagnitude } let remaining = deadline.timeIntervalSince(now) guard remaining > 0 else { throw URLError(.timedOut) } guard let localLimit else { return remaining } return min(OpenAIDashboardFetcher.sanitizedTimeout(localLimit), remaining) } nonisolated static func runBoundedCookieLoad( deadline: Date?, timeoutObserver: (@Sendable () -> Void)? = nil, operation: @escaping @Sendable () throws -> T) async throws -> T { // The detached/GCD loader does not inherit TaskLocal prompt policy or retry selection. let contextualOperation = BrowserCookieAccessGate.operationPreservingAccessContext(operation) guard let deadline else { return try await Task.detached(priority: .userInitiated, operation: contextualOperation).value } let timeout = try self.remainingTimeout(until: deadline) let completion = CookieLoadCompletion() return try await withCheckedThrowingContinuation { continuation in DispatchQueue.global(qos: .userInitiated).async { let result = Result(catching: contextualOperation) completion.finish { continuation.resume(with: result) } } self.deadlineQueue.asyncAfter(deadline: .now() + timeout) { completion.finish { timeoutObserver?() continuation.resume(throwing: URLError(.timedOut)) } } } } nonisolated static func runBoundedCookieCacheOperation( deadline: Date?, operation: @escaping @Sendable () throws -> T) async throws -> T { guard let deadline else { return try await withCheckedThrowingContinuation { continuation in self.cookieCacheQueue.async { continuation.resume(with: Result(catching: operation)) } } } let timeout = try self.remainingTimeout(until: deadline) let completion = CookieLoadCompletion() return try await withCheckedThrowingContinuation { continuation in self.cookieCacheQueue.async { let result = Result(catching: operation) completion.finish { continuation.resume(with: result) } } self.deadlineQueue.asyncAfter(deadline: .now() + timeout) { completion.finish { continuation.resume(throwing: URLError(.timedOut)) } } } } static func runBoundedCallback( deadline: Date?, timeoutObserver: (@Sendable () -> Void)? = nil, start: (@escaping @Sendable () -> Void) -> Void) async throws { let completion = CookieLoadCompletion() guard let deadline else { await withCheckedContinuation { continuation in start { completion.finish { continuation.resume() } } } return } let timeout = try self.remainingTimeout(until: deadline) try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in start { completion.finish { continuation.resume() } } self.deadlineQueue.asyncAfter(deadline: .now() + timeout) { completion.finish { timeoutObserver?() continuation.resume(throwing: URLError(.timedOut)) } } } } static func runBoundedValueCallback( deadline: Date?, timeoutObserver: (@Sendable () -> Void)? = nil, start: (@escaping @Sendable (T) -> Void) -> Void) async throws -> T { let completion = CookieLoadCompletion() guard let deadline else { return await withCheckedContinuation { continuation in start { value in completion.finish { continuation.resume(returning: value) } } } } let timeout = try self.remainingTimeout(until: deadline) return try await withCheckedThrowingContinuation { continuation in start { value in completion.finish { continuation.resume(returning: value) } } self.deadlineQueue.asyncAfter(deadline: .now() + timeout) { completion.finish { timeoutObserver?() continuation.resume(throwing: URLError(.timedOut)) } } } } static func runSerializedCallback( key: ObjectIdentifier, deadline: Date?, start: @escaping (@escaping @Sendable () -> Void) -> Void) async throws { while let pending = self.pendingCookieStoreMutations[key] { try await self.waitForMutation(pending.task, deadline: deadline) if self.pendingCookieStoreMutations[key]?.token == pending.token { self.pendingCookieStoreMutations[key] = nil } } let token = UUID() let task = Task { @MainActor in await withCheckedContinuation { continuation in start { continuation.resume() } } } self.pendingCookieStoreMutations[key] = PendingCookieStoreMutation(token: token, task: task) Task { @MainActor in await task.value if self.pendingCookieStoreMutations[key]?.token == token { self.pendingCookieStoreMutations[key] = nil } } try await self.waitForMutation(task, deadline: deadline) } private static func waitForMutation(_ task: Task, deadline: Date?) async throws { try await self.runBoundedCallback(deadline: deadline) { completion in Task { @MainActor in await task.value completion() } } } } #endif