@@ -17,35 +17,23 @@ public class ClerkViewFactory: ClerkViewFactoryProtocol {
1717 // Register this factory with the ClerkExpo module
1818 public static func register( ) {
1919 clerkViewFactory = shared
20- print ( " ✅ [ClerkViewFactory] Registered with ClerkExpo module " )
2120 }
2221
2322 @MainActor
2423 public func configure( publishableKey: String ) async throws {
25- print ( " 🔧 [ClerkViewFactory] Configuring Clerk with key: \( publishableKey. prefix ( 20 ) ) ... " )
2624 Clerk . shared. configure ( publishableKey: publishableKey)
27- print ( " ✅ [ClerkViewFactory] Clerk configured, now loading... " )
2825
2926 // CRITICAL: Must call load() after configure() to restore session from keychain
30- do {
31- try await Clerk . shared. load ( )
32- print ( " ✅ [ClerkViewFactory] Clerk load() completed " )
33- } catch {
34- print ( " ❌ [ClerkViewFactory] Clerk load() failed: \( error) " )
35- }
27+ try await Clerk . shared. load ( )
3628
37- // IMPORTANT: load() is async but session may be populated AFTER it returns
38- // The SDK uses Combine/ObservableObject pattern - session is published asynchronously
39- // We need to wait for the session to actually be populated
40- print ( " ⏳ [ClerkViewFactory] Waiting for session to be populated... " )
41- for i in 0 ..< 30 { // Wait up to 3 seconds
29+ // load() is async but session may be populated AFTER it returns.
30+ // The SDK uses Combine/ObservableObject pattern — session is published asynchronously.
31+ for _ in 0 ..< 30 { // Wait up to 3 seconds
4232 if Clerk . shared. session != nil {
43- print ( " ✅ [ClerkViewFactory] Session found after \( i * 100 ) ms: \( Clerk . shared. session? . id ?? " unknown " ) " )
4433 return
4534 }
4635 try ? await Task . sleep ( nanoseconds: 100_000_000 ) // 100ms
4736 }
48- print ( " ⚠️ [ClerkViewFactory] No session found after 3s, session: \( Clerk . shared. session? . id ?? " none " ) " )
4937 }
5038
5139 public func createAuthViewController(
@@ -88,7 +76,7 @@ public class ClerkViewFactory: ClerkViewFactoryProtocol {
8876 mode: String ,
8977 dismissable: Bool ,
9078 onEvent: @escaping ( String , [ String : Any ] ) -> Void
91- ) -> UIView ? {
79+ ) -> UIViewController ? {
9280 let authMode : AuthView . Mode
9381 switch mode {
9482 case " signIn " :
@@ -107,41 +95,36 @@ public class ClerkViewFactory: ClerkViewFactoryProtocol {
10795 )
10896 )
10997 hostingController. view. backgroundColor = . clear
110- return hostingController. view
98+ return hostingController
11199 }
112100
113101 public func createUserProfileView(
114102 dismissable: Bool ,
115103 onEvent: @escaping ( String , [ String : Any ] ) -> Void
116- ) -> UIView ? {
104+ ) -> UIViewController ? {
117105 let hostingController = UIHostingController (
118106 rootView: ClerkInlineProfileWrapperView (
119107 dismissable: dismissable,
120108 onEvent: onEvent
121109 )
122110 )
123111 hostingController. view. backgroundColor = . clear
124- return hostingController. view
112+ return hostingController
125113 }
126114
127115 @MainActor
128116 public func getSession( ) async -> [ String : Any ] ? {
129117 guard let session = Clerk . shared. session else {
130- print ( " 📭 [ClerkViewFactory] No active session " )
131118 return nil
132119 }
133- print ( " ✅ [ClerkViewFactory] Found active session: \( session. id) " )
134120
135121 var result : [ String : Any ] = [
136122 " sessionId " : session. id,
137123 " status " : String ( describing: session. status)
138124 ]
139125
140126 // Include user details if available
141- // Try to get user from session first, then fallback to Clerk.shared.user
142127 let user = session. user ?? Clerk . shared. user
143- NSLog ( " 🔍 [ClerkViewFactory] Clerk.shared.user: \( Clerk . shared. user? . id ?? " nil " ) " )
144- NSLog ( " 🔍 [ClerkViewFactory] session.user: \( session. user? . id ?? " nil " ) " )
145128
146129 if let user = user {
147130 var userDict : [ String : Any ] = [
@@ -160,18 +143,13 @@ public class ClerkViewFactory: ClerkViewFactoryProtocol {
160143 userDict [ " primaryEmailAddress " ] = firstEmail. emailAddress
161144 }
162145 result [ " user " ] = userDict
163- NSLog ( " ✅ [ClerkViewFactory] User found: \( user. firstName ?? " N/A " ) \( user. lastName ?? " " ) " )
164- } else {
165- NSLog ( " ⚠️ [ClerkViewFactory] No user available - all sources returned nil " )
166146 }
167147
168148 return result
169149 }
170150
171151 public func signOut( ) async throws {
172- print ( " 🔓 [ClerkViewFactory] Signing out... " )
173152 try await Clerk . shared. signOut ( )
174- print ( " ✅ [ClerkViewFactory] Signed out successfully " )
175153 }
176154}
177155
@@ -180,6 +158,7 @@ public class ClerkViewFactory: ClerkViewFactoryProtocol {
180158class ClerkAuthWrapperViewController : UIHostingController < ClerkAuthWrapperView > {
181159 private let completion : ( Result < [ String : Any ] , Error > ) -> Void
182160 private var authEventTask : Task < Void , Never > ?
161+ private var completionCalled = false
183162
184163 init ( mode: AuthView . Mode , dismissable: Bool , completion: @escaping ( Result < [ String : Any ] , Error > ) -> Void ) {
185164 self . completion = completion
@@ -197,25 +176,31 @@ class ClerkAuthWrapperViewController: UIHostingController<ClerkAuthWrapperView>
197176 authEventTask? . cancel ( )
198177 }
199178
179+ private func completeOnce( _ result: Result < [ String : Any ] , Error > ) {
180+ guard !completionCalled else { return }
181+ completionCalled = true
182+ completion ( result)
183+ }
184+
200185 private func subscribeToAuthEvents( ) {
201186 authEventTask = Task { @MainActor [ weak self] in
202187 for await event in Clerk . shared. authEventEmitter. events {
203- guard let self = self else { return }
188+ guard let self = self , ! self . completionCalled else { return }
204189 switch event {
205190 case . signInCompleted( let signIn) :
206191 if let sessionId = signIn. createdSessionId {
207- self . completion ( . success( [ " sessionId " : sessionId, " type " : " signIn " ] ) )
192+ self . completeOnce ( . success( [ " sessionId " : sessionId, " type " : " signIn " ] ) )
208193 self . dismiss ( animated: true )
209194 } else {
210- self . completion ( . failure( NSError ( domain: " ClerkExpo " , code: 4 , userInfo: [ NSLocalizedDescriptionKey: " Sign-in completed but no session was created " ] ) ) )
195+ self . completeOnce ( . failure( NSError ( domain: " ClerkExpo " , code: 4 , userInfo: [ NSLocalizedDescriptionKey: " Sign-in completed but no session was created " ] ) ) )
211196 self . dismiss ( animated: true )
212197 }
213198 case . signUpCompleted( let signUp) :
214199 if let sessionId = signUp. createdSessionId {
215- self . completion ( . success( [ " sessionId " : sessionId, " type " : " signUp " ] ) )
200+ self . completeOnce ( . success( [ " sessionId " : sessionId, " type " : " signUp " ] ) )
216201 self . dismiss ( animated: true )
217202 } else {
218- self . completion ( . failure( NSError ( domain: " ClerkExpo " , code: 4 , userInfo: [ NSLocalizedDescriptionKey: " Sign-up completed but no session was created " ] ) ) )
203+ self . completeOnce ( . failure( NSError ( domain: " ClerkExpo " , code: 4 , userInfo: [ NSLocalizedDescriptionKey: " Sign-up completed but no session was created " ] ) ) )
219204 self . dismiss ( animated: true )
220205 }
221206 default :
@@ -224,7 +209,7 @@ class ClerkAuthWrapperViewController: UIHostingController<ClerkAuthWrapperView>
224209 }
225210 // Stream ended without a completion event
226211 guard let self = self else { return }
227- self . completion ( . failure( NSError ( domain: " ClerkExpo " , code: 5 , userInfo: [ NSLocalizedDescriptionKey: " Auth event stream ended unexpectedly " ] ) ) )
212+ self . completeOnce ( . failure( NSError ( domain: " ClerkExpo " , code: 5 , userInfo: [ NSLocalizedDescriptionKey: " Auth event stream ended unexpectedly " ] ) ) )
228213 }
229214 }
230215}
@@ -243,6 +228,7 @@ struct ClerkAuthWrapperView: View {
243228class ClerkProfileWrapperViewController : UIHostingController < ClerkProfileWrapperView > {
244229 private let completion : ( Result < [ String : Any ] , Error > ) -> Void
245230 private var authEventTask : Task < Void , Never > ?
231+ private var completionCalled = false
246232
247233 init ( dismissable: Bool , completion: @escaping ( Result < [ String : Any ] , Error > ) -> Void ) {
248234 self . completion = completion
@@ -260,21 +246,27 @@ class ClerkProfileWrapperViewController: UIHostingController<ClerkProfileWrapper
260246 authEventTask? . cancel ( )
261247 }
262248
249+ private func completeOnce( _ result: Result < [ String : Any ] , Error > ) {
250+ guard !completionCalled else { return }
251+ completionCalled = true
252+ completion ( result)
253+ }
254+
263255 private func subscribeToAuthEvents( ) {
264256 authEventTask = Task { @MainActor [ weak self] in
265257 for await event in Clerk . shared. authEventEmitter. events {
266- guard let self = self else { return }
258+ guard let self = self , ! self . completionCalled else { return }
267259 switch event {
268260 case . signedOut( let session) :
269- self . completion ( . success( [ " sessionId " : session. id] ) )
261+ self . completeOnce ( . success( [ " sessionId " : session. id] ) )
270262 self . dismiss ( animated: true )
271263 default :
272264 break
273265 }
274266 }
275267 // Stream ended without a sign-out event
276268 guard let self = self else { return }
277- self . completion ( . failure( NSError ( domain: " ClerkExpo " , code: 5 , userInfo: [ NSLocalizedDescriptionKey: " Profile event stream ended unexpectedly " ] ) ) )
269+ self . completeOnce ( . failure( NSError ( domain: " ClerkExpo " , code: 5 , userInfo: [ NSLocalizedDescriptionKey: " Profile event stream ended unexpectedly " ] ) ) )
278270 }
279271 }
280272}
0 commit comments