@@ -28,6 +28,8 @@ final class ZaiUsageProvider: UsageProviderProtocol, @unchecked Sendable {
2828
2929 private let apiClient : APIClient
3030 private let credentialProvider : @Sendable ( ) -> String ?
31+ private let credentialLock = NSLock ( )
32+ nonisolated ( unsafe) private var cachedCredential : String ? ?
3133
3234 /// Minimum cache TTL to avoid excessive API requests (Z.ai is API-based).
3335 static let minCacheTTL : TimeInterval = 60
@@ -43,10 +45,11 @@ final class ZaiUsageProvider: UsageProviderProtocol, @unchecked Sendable {
4345 self . credentialProvider = credentialProvider ?? {
4446 KeychainManager . load ( account: ServiceType . zai. keychainAccount)
4547 }
48+ self . cachedCredential = nil
4649 }
4750
4851 func isConfigured( ) async -> Bool {
49- credentialProvider ( ) != nil
52+ resolveCredential ( ) != nil
5053 }
5154
5255 /// Returns cached response if within minimum TTL, nil otherwise.
@@ -74,7 +77,7 @@ final class ZaiUsageProvider: UsageProviderProtocol, @unchecked Sendable {
7477 return cached
7578 }
7679
77- guard let apiKey = credentialProvider ( ) else {
80+ guard let apiKey = resolveCredential ( ) else {
7881 throw APIError . unauthorized
7982 }
8083
@@ -163,4 +166,17 @@ final class ZaiUsageProvider: UsageProviderProtocol, @unchecked Sendable {
163166 }
164167 }
165168
169+ private func resolveCredential( ) -> String ? {
170+ credentialLock. lock ( )
171+ if let cachedCredential {
172+ credentialLock. unlock ( )
173+ return cachedCredential
174+ }
175+
176+ let loadedCredential = credentialProvider ( )
177+ cachedCredential = loadedCredential
178+ credentialLock. unlock ( )
179+ return loadedCredential
180+ }
181+
166182}
0 commit comments