@clerk/expo 3.4.7-snapshot.v20260618154136 → 3.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/expo/modules/clerk/ClerkExpoModule.kt +65 -33
- package/dist/google-one-tap/ClerkGoogleOneTapSignIn.d.ts +2 -1
- package/dist/google-one-tap/ClerkGoogleOneTapSignIn.d.ts.map +1 -1
- package/dist/google-one-tap/ClerkGoogleOneTapSignIn.js +2 -1
- package/dist/google-one-tap/ClerkGoogleOneTapSignIn.js.map +1 -1
- package/dist/google-one-tap/types.d.ts +18 -2
- package/dist/google-one-tap/types.d.ts.map +1 -1
- package/dist/hooks/useNativeClientEvents.d.ts.map +1 -1
- package/dist/hooks/useNativeClientEvents.js +8 -1
- package/dist/hooks/useNativeClientEvents.js.map +1 -1
- package/dist/provider/ClerkProvider.js +1 -1
- package/dist/provider/nativeClientSync.d.ts.map +1 -1
- package/dist/provider/nativeClientSync.js +11 -7
- package/dist/provider/nativeClientSync.js.map +1 -1
- package/dist/specs/NativeClerkModule.android.d.ts +1 -1
- package/dist/specs/NativeClerkModule.android.d.ts.map +1 -1
- package/dist/specs/NativeClerkModule.android.js.map +1 -1
- package/dist/specs/NativeClerkModule.d.ts +1 -1
- package/dist/specs/NativeClerkModule.d.ts.map +1 -1
- package/dist/specs/NativeClerkModule.js.map +1 -1
- package/dist/utils/native-module.d.ts +3 -3
- package/dist/utils/native-module.d.ts.map +1 -1
- package/dist/utils/native-module.js +1 -1
- package/dist/utils/native-module.js.map +1 -1
- package/ios/ClerkExpoModule.m +1 -0
- package/ios/ClerkExpoModule.swift +9 -2
- package/ios/ClerkGoogleSignInModule.swift +1 -4
- package/ios/ClerkNativeBridge.swift +26 -32
- package/package.json +6 -6
- package/src/specs/NativeClerkModule.android.ts +5 -1
- package/src/specs/NativeClerkModule.ts +5 -1
|
@@ -73,8 +73,13 @@ class ClerkExpoModule : Module() {
|
|
|
73
73
|
getClientToken(promise)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
AsyncFunction("syncFromJsClientToken") { clientToken: String?, sourceId: String?, promise: Promise ->
|
|
77
|
-
syncFromJsClientToken(
|
|
76
|
+
AsyncFunction("syncFromJsClientToken") { clientToken: String?, sourceId: String?, shouldRefreshClient: Boolean?, promise: Promise ->
|
|
77
|
+
syncFromJsClientToken(
|
|
78
|
+
clientToken,
|
|
79
|
+
sourceId,
|
|
80
|
+
shouldRefreshClient ?: clientToken.isNullOrBlank(),
|
|
81
|
+
promise
|
|
82
|
+
)
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
|
|
@@ -169,7 +174,7 @@ class ClerkExpoModule : Module() {
|
|
|
169
174
|
// before resolving the configure call.
|
|
170
175
|
if (!bearerToken.isNullOrEmpty()) {
|
|
171
176
|
withTimeout(5_000L) {
|
|
172
|
-
Clerk.
|
|
177
|
+
Clerk.clientFlow.first { it != null }
|
|
173
178
|
}
|
|
174
179
|
}
|
|
175
180
|
} catch (e: TimeoutCancellationException) {
|
|
@@ -230,10 +235,10 @@ class ClerkExpoModule : Module() {
|
|
|
230
235
|
|
|
231
236
|
try {
|
|
232
237
|
withTimeout(5_000L) {
|
|
233
|
-
Clerk.
|
|
238
|
+
Clerk.clientFlow.first { it != null }
|
|
234
239
|
}
|
|
235
240
|
} catch (_: TimeoutCancellationException) {
|
|
236
|
-
debugLog(TAG, "configure -
|
|
241
|
+
debugLog(TAG, "configure - client did not appear after reconfigure token update")
|
|
237
242
|
}
|
|
238
243
|
}
|
|
239
244
|
|
|
@@ -251,13 +256,13 @@ class ClerkExpoModule : Module() {
|
|
|
251
256
|
debugLog(TAG, "configure - updateDeviceToken failed: ${result.error}")
|
|
252
257
|
}
|
|
253
258
|
|
|
254
|
-
// Wait for
|
|
259
|
+
// Wait for client state to hydrate with the new token (up to 5s).
|
|
255
260
|
try {
|
|
256
261
|
withTimeout(5_000L) {
|
|
257
|
-
Clerk.
|
|
262
|
+
Clerk.clientFlow.first { it != null }
|
|
258
263
|
}
|
|
259
264
|
} catch (_: TimeoutCancellationException) {
|
|
260
|
-
debugLog(TAG, "configure -
|
|
265
|
+
debugLog(TAG, "configure - client did not appear after token update")
|
|
261
266
|
}
|
|
262
267
|
}
|
|
263
268
|
|
|
@@ -285,7 +290,12 @@ class ClerkExpoModule : Module() {
|
|
|
285
290
|
|
|
286
291
|
// MARK: - syncFromJsClientToken
|
|
287
292
|
|
|
288
|
-
private fun syncFromJsClientToken(
|
|
293
|
+
private fun syncFromJsClientToken(
|
|
294
|
+
clientToken: String?,
|
|
295
|
+
sourceId: String?,
|
|
296
|
+
shouldRefreshClient: Boolean,
|
|
297
|
+
promise: Promise
|
|
298
|
+
) {
|
|
289
299
|
if (!Clerk.isInitialized.value) {
|
|
290
300
|
promise.resolve(null)
|
|
291
301
|
return
|
|
@@ -295,43 +305,65 @@ class ClerkExpoModule : Module() {
|
|
|
295
305
|
try {
|
|
296
306
|
jsOriginatedClientSyncDepth += 1
|
|
297
307
|
if (!clientToken.isNullOrBlank()) {
|
|
298
|
-
|
|
308
|
+
val currentDeviceToken = try {
|
|
309
|
+
Clerk.getDeviceToken()
|
|
310
|
+
} catch (_: Exception) {
|
|
311
|
+
null
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (currentDeviceToken == clientToken) {
|
|
315
|
+
if (!shouldRefreshClient) {
|
|
316
|
+
emitSyncedClientChanged(sourceId)
|
|
317
|
+
promise.resolve(null)
|
|
318
|
+
return@launch
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
when (val result = Clerk.updateDeviceToken(clientToken)) {
|
|
322
|
+
is ClerkResult.Failure -> {
|
|
323
|
+
promise.reject(
|
|
324
|
+
"E_SYNC_FROM_JS_FAILED",
|
|
325
|
+
result.error?.firstMessage() ?: result.throwable?.message ?: "Client token sync failed",
|
|
326
|
+
null
|
|
327
|
+
)
|
|
328
|
+
return@launch
|
|
329
|
+
}
|
|
330
|
+
is ClerkResult.Success -> {
|
|
331
|
+
try {
|
|
332
|
+
withTimeout(5_000L) {
|
|
333
|
+
Clerk.clientFlow.first { it != null }
|
|
334
|
+
}
|
|
335
|
+
} catch (_: TimeoutCancellationException) {
|
|
336
|
+
debugLog(TAG, "syncFromJsClientToken - client did not appear after token update")
|
|
337
|
+
}
|
|
338
|
+
if (!shouldRefreshClient) {
|
|
339
|
+
emitSyncedClientChanged(sourceId)
|
|
340
|
+
promise.resolve(null)
|
|
341
|
+
return@launch
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (shouldRefreshClient) {
|
|
349
|
+
when (val result = Clerk.refreshClient()) {
|
|
299
350
|
is ClerkResult.Failure -> {
|
|
300
351
|
promise.reject(
|
|
301
352
|
"E_SYNC_FROM_JS_FAILED",
|
|
302
|
-
result.error?.firstMessage() ?: result.throwable?.message ?: "Client
|
|
353
|
+
result.error?.firstMessage() ?: result.throwable?.message ?: "Client refresh failed",
|
|
303
354
|
null
|
|
304
355
|
)
|
|
305
|
-
return@launch
|
|
306
356
|
}
|
|
307
357
|
is ClerkResult.Success -> {
|
|
308
|
-
try {
|
|
309
|
-
withTimeout(5_000L) {
|
|
310
|
-
Clerk.sessionFlow.first { it != null }
|
|
311
|
-
}
|
|
312
|
-
} catch (_: TimeoutCancellationException) {
|
|
313
|
-
debugLog(TAG, "syncFromJsClientToken - session did not appear after token update")
|
|
314
|
-
}
|
|
315
358
|
emitSyncedClientChanged(sourceId)
|
|
316
359
|
promise.resolve(null)
|
|
317
|
-
return@launch
|
|
318
360
|
}
|
|
319
361
|
}
|
|
362
|
+
return@launch
|
|
320
363
|
}
|
|
321
364
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
promise.reject(
|
|
325
|
-
"E_SYNC_FROM_JS_FAILED",
|
|
326
|
-
result.error?.firstMessage() ?: result.throwable?.message ?: "Client refresh failed",
|
|
327
|
-
null
|
|
328
|
-
)
|
|
329
|
-
}
|
|
330
|
-
is ClerkResult.Success -> {
|
|
331
|
-
emitSyncedClientChanged(sourceId)
|
|
332
|
-
promise.resolve(null)
|
|
333
|
-
}
|
|
334
|
-
}
|
|
365
|
+
emitSyncedClientChanged(sourceId)
|
|
366
|
+
promise.resolve(null)
|
|
335
367
|
} catch (e: Exception) {
|
|
336
368
|
promise.reject("E_SYNC_FROM_JS_FAILED", e.message ?: "Client token sync failed", e)
|
|
337
369
|
} finally {
|
|
@@ -45,7 +45,8 @@ export declare const ClerkGoogleOneTapSignIn: {
|
|
|
45
45
|
*
|
|
46
46
|
* @param params - Sign-in parameters
|
|
47
47
|
* @param params.nonce - Cryptographic nonce for replay protection
|
|
48
|
-
* @param params.filterByAuthorizedAccounts -
|
|
48
|
+
* @param params.filterByAuthorizedAccounts - Android only. Filter to previously authorized accounts.
|
|
49
|
+
* @param params.hint - iOS only. Hint for Google Sign-In.
|
|
49
50
|
*
|
|
50
51
|
* @returns Promise resolving to OneTapResponse
|
|
51
52
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClerkGoogleOneTapSignIn.d.ts","sourceRoot":"","sources":["../../src/google-one-tap/ClerkGoogleOneTapSignIn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,YAAY,EACb,MAAM,SAAS,CAAC;AAYjB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,iBAAiB,CAE3F;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,sBAAsB,CAE7G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,qBAAqB,CAE7F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAS1F;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;IAClC;;;;;;;OAOG;sBACe,eAAe,GAAG,IAAI;IAIxC
|
|
1
|
+
{"version":3,"file":"ClerkGoogleOneTapSignIn.d.ts","sourceRoot":"","sources":["../../src/google-one-tap/ClerkGoogleOneTapSignIn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,YAAY,EACb,MAAM,SAAS,CAAC;AAYjB;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,iBAAiB,CAE3F;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,sBAAsB,CAE7G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,IAAI,qBAAqB,CAE7F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAS1F;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB;IAClC;;;;;;;OAOG;sBACe,eAAe,GAAG,IAAI;IAIxC;;;;;;;;;;;;OAYG;oBACmB,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAgB5D;;;;;;;;;;OAUG;2BAC0B,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC;IAgB1E;;;;;;;;;;OAUG;mCACkC,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAanF;;;;OAIG;eACc,OAAO,CAAC,IAAI,CAAC;CAG/B,CAAC;AAEF,YAAY,EACV,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,GACX,MAAM,SAAS,CAAC"}
|
|
@@ -61,7 +61,8 @@ const ClerkGoogleOneTapSignIn = {
|
|
|
61
61
|
*
|
|
62
62
|
* @param params - Sign-in parameters
|
|
63
63
|
* @param params.nonce - Cryptographic nonce for replay protection
|
|
64
|
-
* @param params.filterByAuthorizedAccounts -
|
|
64
|
+
* @param params.filterByAuthorizedAccounts - Android only. Filter to previously authorized accounts.
|
|
65
|
+
* @param params.hint - iOS only. Hint for Google Sign-In.
|
|
65
66
|
*
|
|
66
67
|
* @returns Promise resolving to OneTapResponse
|
|
67
68
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClerkGoogleOneTapSignIn.js","names":["NativeClerkGoogleSignIn"],"sources":["../../src/google-one-tap/ClerkGoogleOneTapSignIn.ts"],"sourcesContent":["import NativeClerkGoogleSignIn from '../specs/NativeClerkGoogleSignIn';\nimport type {\n CancelledResponse,\n ConfigureParams,\n CreateAccountParams,\n ExplicitSignInParams,\n NoSavedCredentialFound,\n OneTapResponse,\n OneTapSuccessResponse,\n SignInParams,\n} from './types';\n\nfunction getNativeModule(): NonNullable<typeof NativeClerkGoogleSignIn> {\n if (!NativeClerkGoogleSignIn) {\n throw new Error(\n 'ClerkGoogleSignIn native module is not available. ' +\n 'Ensure the @clerk/expo plugin is added to your app.json and you have run a development build.',\n );\n }\n return NativeClerkGoogleSignIn;\n}\n\n/**\n * Check if a response indicates the user cancelled the sign-in flow.\n */\nexport function isCancelledResponse(response: OneTapResponse): response is CancelledResponse {\n return response.type === 'cancelled';\n}\n\n/**\n * Check if a response indicates no saved credential was found.\n */\nexport function isNoSavedCredentialFoundResponse(response: OneTapResponse): response is NoSavedCredentialFound {\n return response.type === 'noSavedCredentialFound';\n}\n\n/**\n * Check if a response is a successful sign-in.\n */\nexport function isSuccessResponse(response: OneTapResponse): response is OneTapSuccessResponse {\n return response.type === 'success';\n}\n\n/**\n * Check if an error has code and message properties (Google Sign-In error).\n */\nexport function isErrorWithCode(error: unknown): error is { code: string; message: string } {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n typeof (error as { code: unknown }).code === 'string' &&\n 'message' in error &&\n typeof (error as { message: unknown }).message === 'string'\n );\n}\n\n/**\n * Internal Google One Tap Sign-In module.\n *\n * This module provides native Google Sign-In functionality using Google's\n * Credential Manager API with full nonce support for replay attack protection.\n *\n * @internal This is an internal module. Use the `useSignInWithGoogle` hook instead.\n * @platform Android, iOS\n */\nexport const ClerkGoogleOneTapSignIn = {\n /**\n * Configure Google Sign-In. Must be called before any sign-in methods.\n *\n * @param params - Configuration parameters\n * @param params.webClientId - The web client ID from Google Cloud Console (required)\n * @param params.hostedDomain - Optional domain restriction\n * @param params.autoSelectEnabled - Auto-select for single credential (default: false)\n */\n configure(params: ConfigureParams): void {\n getNativeModule().configure(params as any);\n },\n\n /**\n * Attempt to sign in with saved credentials (One Tap).\n *\n * This method will show the One Tap UI if there are saved credentials,\n * or return a \"noSavedCredentialFound\" response if there are none.\n *\n * @param params - Sign-in parameters\n * @param params.nonce - Cryptographic nonce for replay protection\n * @param params.filterByAuthorizedAccounts -
|
|
1
|
+
{"version":3,"file":"ClerkGoogleOneTapSignIn.js","names":["NativeClerkGoogleSignIn"],"sources":["../../src/google-one-tap/ClerkGoogleOneTapSignIn.ts"],"sourcesContent":["import NativeClerkGoogleSignIn from '../specs/NativeClerkGoogleSignIn';\nimport type {\n CancelledResponse,\n ConfigureParams,\n CreateAccountParams,\n ExplicitSignInParams,\n NoSavedCredentialFound,\n OneTapResponse,\n OneTapSuccessResponse,\n SignInParams,\n} from './types';\n\nfunction getNativeModule(): NonNullable<typeof NativeClerkGoogleSignIn> {\n if (!NativeClerkGoogleSignIn) {\n throw new Error(\n 'ClerkGoogleSignIn native module is not available. ' +\n 'Ensure the @clerk/expo plugin is added to your app.json and you have run a development build.',\n );\n }\n return NativeClerkGoogleSignIn;\n}\n\n/**\n * Check if a response indicates the user cancelled the sign-in flow.\n */\nexport function isCancelledResponse(response: OneTapResponse): response is CancelledResponse {\n return response.type === 'cancelled';\n}\n\n/**\n * Check if a response indicates no saved credential was found.\n */\nexport function isNoSavedCredentialFoundResponse(response: OneTapResponse): response is NoSavedCredentialFound {\n return response.type === 'noSavedCredentialFound';\n}\n\n/**\n * Check if a response is a successful sign-in.\n */\nexport function isSuccessResponse(response: OneTapResponse): response is OneTapSuccessResponse {\n return response.type === 'success';\n}\n\n/**\n * Check if an error has code and message properties (Google Sign-In error).\n */\nexport function isErrorWithCode(error: unknown): error is { code: string; message: string } {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n typeof (error as { code: unknown }).code === 'string' &&\n 'message' in error &&\n typeof (error as { message: unknown }).message === 'string'\n );\n}\n\n/**\n * Internal Google One Tap Sign-In module.\n *\n * This module provides native Google Sign-In functionality using Google's\n * Credential Manager API with full nonce support for replay attack protection.\n *\n * @internal This is an internal module. Use the `useSignInWithGoogle` hook instead.\n * @platform Android, iOS\n */\nexport const ClerkGoogleOneTapSignIn = {\n /**\n * Configure Google Sign-In. Must be called before any sign-in methods.\n *\n * @param params - Configuration parameters\n * @param params.webClientId - The web client ID from Google Cloud Console (required)\n * @param params.hostedDomain - Optional domain restriction\n * @param params.autoSelectEnabled - Auto-select for single credential (default: false)\n */\n configure(params: ConfigureParams): void {\n getNativeModule().configure(params as any);\n },\n\n /**\n * Attempt to sign in with saved credentials (One Tap).\n *\n * This method will show the One Tap UI if there are saved credentials,\n * or return a \"noSavedCredentialFound\" response if there are none.\n *\n * @param params - Sign-in parameters\n * @param params.nonce - Cryptographic nonce for replay protection\n * @param params.filterByAuthorizedAccounts - Android only. Filter to previously authorized accounts.\n * @param params.hint - iOS only. Hint for Google Sign-In.\n *\n * @returns Promise resolving to OneTapResponse\n */\n async signIn(params?: SignInParams): Promise<OneTapResponse> {\n try {\n return (await getNativeModule().signIn((params as any) ?? null)) as unknown as OneTapResponse;\n } catch (error) {\n if (isErrorWithCode(error)) {\n if (error.code === 'SIGN_IN_CANCELLED') {\n return { type: 'cancelled', data: null };\n }\n if (error.code === 'NO_SAVED_CREDENTIAL_FOUND') {\n return { type: 'noSavedCredentialFound', data: null };\n }\n }\n throw error;\n }\n },\n\n /**\n * Create a new account (shows all Google accounts).\n *\n * This method shows the account picker with all available Google accounts,\n * not just previously authorized ones.\n *\n * @param params - Create account parameters\n * @param params.nonce - Cryptographic nonce for replay protection\n *\n * @returns Promise resolving to OneTapResponse\n */\n async createAccount(params?: CreateAccountParams): Promise<OneTapResponse> {\n try {\n return (await getNativeModule().createAccount((params as any) ?? null)) as unknown as OneTapResponse;\n } catch (error) {\n if (isErrorWithCode(error)) {\n if (error.code === 'SIGN_IN_CANCELLED') {\n return { type: 'cancelled', data: null };\n }\n if (error.code === 'NO_SAVED_CREDENTIAL_FOUND') {\n return { type: 'noSavedCredentialFound', data: null };\n }\n }\n throw error;\n }\n },\n\n /**\n * Present explicit sign-in UI (Google Sign-In button flow).\n *\n * This shows the full Google Sign-In UI, similar to clicking a\n * \"Sign in with Google\" button.\n *\n * @param params - Explicit sign-in parameters\n * @param params.nonce - Cryptographic nonce for replay protection\n *\n * @returns Promise resolving to OneTapResponse\n */\n async presentExplicitSignIn(params?: ExplicitSignInParams): Promise<OneTapResponse> {\n try {\n return (await getNativeModule().presentExplicitSignIn((params as any) ?? null)) as unknown as OneTapResponse;\n } catch (error) {\n if (isErrorWithCode(error)) {\n if (error.code === 'SIGN_IN_CANCELLED') {\n return { type: 'cancelled', data: null };\n }\n }\n throw error;\n }\n },\n\n /**\n * Sign out and clear credential state.\n *\n * This disables automatic sign-in until the user signs in again.\n */\n async signOut(): Promise<void> {\n await getNativeModule().signOut();\n },\n};\n\nexport type {\n ConfigureParams,\n SignInParams,\n CreateAccountParams,\n ExplicitSignInParams,\n OneTapResponse,\n OneTapSuccessResponse,\n CancelledResponse,\n NoSavedCredentialFound,\n GoogleUser,\n} from './types';\n"],"mappings":";;;;;;AAYA,SAAS,kBAA+D;CACtE,IAAI,CAACA,2CACH,MAAM,IAAI,MACR,iJAEF;CAEF,OAAOA;AACT;;;;AAKA,SAAgB,oBAAoB,UAAyD;CAC3F,OAAO,SAAS,SAAS;AAC3B;;;;AAKA,SAAgB,iCAAiC,UAA8D;CAC7G,OAAO,SAAS,SAAS;AAC3B;;;;AAKA,SAAgB,kBAAkB,UAA6D;CAC7F,OAAO,SAAS,SAAS;AAC3B;;;;AAKA,SAAgB,gBAAgB,OAA4D;CAC1F,OACE,UAAU,QACV,OAAO,UAAU,YACjB,UAAU,SACV,OAAQ,MAA4B,SAAS,YAC7C,aAAa,SACb,OAAQ,MAA+B,YAAY;AAEvD;;;;;;;;;;AAWA,MAAa,0BAA0B;;;;;;;;;CASrC,UAAU,QAA+B;EACvC,gBAAgB,CAAC,CAAC,UAAU,MAAa;CAC3C;;;;;;;;;;;;;;CAeA,MAAM,OAAO,QAAgD;EAC3D,IAAI;GACF,OAAQ,MAAM,gBAAgB,CAAC,CAAC,OAAQ,UAAkB,IAAI;EAChE,SAAS,OAAO;GACd,IAAI,gBAAgB,KAAK,GAAG;IAC1B,IAAI,MAAM,SAAS,qBACjB,OAAO;KAAE,MAAM;KAAa,MAAM;IAAK;IAEzC,IAAI,MAAM,SAAS,6BACjB,OAAO;KAAE,MAAM;KAA0B,MAAM;IAAK;GAExD;GACA,MAAM;EACR;CACF;;;;;;;;;;;;CAaA,MAAM,cAAc,QAAuD;EACzE,IAAI;GACF,OAAQ,MAAM,gBAAgB,CAAC,CAAC,cAAe,UAAkB,IAAI;EACvE,SAAS,OAAO;GACd,IAAI,gBAAgB,KAAK,GAAG;IAC1B,IAAI,MAAM,SAAS,qBACjB,OAAO;KAAE,MAAM;KAAa,MAAM;IAAK;IAEzC,IAAI,MAAM,SAAS,6BACjB,OAAO;KAAE,MAAM;KAA0B,MAAM;IAAK;GAExD;GACA,MAAM;EACR;CACF;;;;;;;;;;;;CAaA,MAAM,sBAAsB,QAAwD;EAClF,IAAI;GACF,OAAQ,MAAM,gBAAgB,CAAC,CAAC,sBAAuB,UAAkB,IAAI;EAC/E,SAAS,OAAO;GACd,IAAI,gBAAgB,KAAK,GACvB;QAAI,MAAM,SAAS,qBACjB,OAAO;KAAE,MAAM;KAAa,MAAM;IAAK;GACzC;GAEF,MAAM;EACR;CACF;;;;;;CAOA,MAAM,UAAyB;EAC7B,MAAM,gBAAgB,CAAC,CAAC,QAAQ;CAClC;AACF"}
|
|
@@ -36,11 +36,27 @@ export type SignInParams = {
|
|
|
36
36
|
*/
|
|
37
37
|
nonce?: string;
|
|
38
38
|
/**
|
|
39
|
-
* Whether to filter credentials to only show accounts that have
|
|
40
|
-
* previously authorized
|
|
39
|
+
* Android only. Whether to filter credentials to only show accounts that have
|
|
40
|
+
* previously authorized this app.
|
|
41
|
+
*
|
|
42
|
+
* No-op on iOS.
|
|
43
|
+
*
|
|
44
|
+
* @platform Android
|
|
41
45
|
* @default true
|
|
42
46
|
*/
|
|
43
47
|
filterByAuthorizedAccounts?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* iOS only. Hint passed to Google Sign-In, such as a user ID or email
|
|
50
|
+
* address.
|
|
51
|
+
*
|
|
52
|
+
* This may prefill or prioritize an account when possible, but does not
|
|
53
|
+
* restrict the account picker.
|
|
54
|
+
*
|
|
55
|
+
* No-op on Android.
|
|
56
|
+
*
|
|
57
|
+
* @platform iOS
|
|
58
|
+
*/
|
|
59
|
+
hint?: string;
|
|
44
60
|
};
|
|
45
61
|
/**
|
|
46
62
|
* Parameters for the createAccount method.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/google-one-tap/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/google-one-tap/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;OAQG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;IAErC;;;;;;;;;;OAUG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpB;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzB;;OAEG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ;;WAEG;QACH,OAAO,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,IAAI,EAAE,UAAU,CAAC;KAClB,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,IAAI,EAAE,IAAI,CAAC;CACZ,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,sBAAsB,CAAC;AAEhG;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAC7B,mBAAmB,GACnB,2BAA2B,GAC3B,gBAAgB,GAChB,sBAAsB,GACtB,wBAAwB,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,KAAK;IAC9C,IAAI,EAAE,qBAAqB,CAAC;CAC7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNativeClientEvents.d.ts","sourceRoot":"","sources":["../../src/hooks/useNativeClientEvents.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,oBAAoB;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,2BAA2B;IACnC,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC7C;
|
|
1
|
+
{"version":3,"file":"useNativeClientEvents.d.ts","sourceRoot":"","sources":["../../src/hooks/useNativeClientEvents.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,oBAAoB;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,oBAAoB;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,2BAA2B;IACnC,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC7C;AAyBD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,2BAA2B,CAkCnE"}
|
|
@@ -5,6 +5,11 @@ let src_utils_native_module = require("../utils/native-module");
|
|
|
5
5
|
|
|
6
6
|
//#region src/hooks/useNativeClientEvents.ts
|
|
7
7
|
const nativeClientChangedEvent = "clerkNativeClientChanged";
|
|
8
|
+
function getNativeClientEventEmitter() {
|
|
9
|
+
if (react_native.Platform.OS === "ios") return react_native.DeviceEventEmitter;
|
|
10
|
+
if (src_utils_native_module.ClerkExpoModule && typeof src_utils_native_module.ClerkExpoModule.addListener === "function") return src_utils_native_module.ClerkExpoModule;
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
8
13
|
/**
|
|
9
14
|
* Listens for native client events that should sync JS client state.
|
|
10
15
|
*/
|
|
@@ -14,7 +19,9 @@ function useNativeClientEvents() {
|
|
|
14
19
|
if (!src_utils_native_module.isNativeSupported || !src_utils_native_module.ClerkExpoModule) return;
|
|
15
20
|
let subscription = null;
|
|
16
21
|
try {
|
|
17
|
-
|
|
22
|
+
const eventEmitter = getNativeClientEventEmitter();
|
|
23
|
+
if (!eventEmitter) return;
|
|
24
|
+
subscription = eventEmitter.addListener(nativeClientChangedEvent, (snapshot) => {
|
|
18
25
|
setNativeClientEvent({
|
|
19
26
|
issuedAt: Date.now(),
|
|
20
27
|
...snapshot
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNativeClientEvents.js","names":["
|
|
1
|
+
{"version":3,"file":"useNativeClientEvents.js","names":["Platform","DeviceEventEmitter","ClerkExpo","isNativeSupported"],"sources":["../../src/hooks/useNativeClientEvents.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { DeviceEventEmitter, Platform } from 'react-native';\n\nimport { ClerkExpoModule as ClerkExpo, isNativeSupported } from '../utils/native-module';\n\nconst nativeClientChangedEvent = 'clerkNativeClientChanged';\n\nexport interface NativeClientSnapshot {\n clientToken?: string | null;\n sourceId?: string | null;\n}\n\n/**\n * Local marker for a native client event.\n */\nexport interface NativeClientEvent extends NativeClientSnapshot {\n issuedAt: number;\n}\n\ninterface UseNativeClientEventsReturn {\n nativeClientEvent: NativeClientEvent | null;\n}\n\ntype RefreshClientEventSubscription = {\n remove: () => void;\n};\n\ntype RefreshClientEventEmitter = {\n addListener: (\n eventName: typeof nativeClientChangedEvent,\n listener: (snapshot?: NativeClientSnapshot) => void,\n ) => RefreshClientEventSubscription;\n};\n\nfunction getNativeClientEventEmitter(): RefreshClientEventEmitter | null {\n if (Platform.OS === 'ios') {\n return DeviceEventEmitter;\n }\n\n if (ClerkExpo && typeof ClerkExpo.addListener === 'function') {\n return ClerkExpo as RefreshClientEventEmitter;\n }\n\n return null;\n}\n\n/**\n * Listens for native client events that should sync JS client state.\n */\nexport function useNativeClientEvents(): UseNativeClientEventsReturn {\n const [nativeClientEvent, setNativeClientEvent] = useState<NativeClientEvent | null>(null);\n\n useEffect(() => {\n if (!isNativeSupported || !ClerkExpo) {\n return;\n }\n\n let subscription: { remove: () => void } | null = null;\n\n try {\n const eventEmitter = getNativeClientEventEmitter();\n\n if (!eventEmitter) {\n return;\n }\n\n subscription = eventEmitter.addListener(nativeClientChangedEvent, snapshot => {\n setNativeClientEvent({ issuedAt: Date.now(), ...snapshot });\n });\n } catch (error) {\n if (__DEV__) {\n console.error('[useNativeClientEvents] Failed to set up event listener:', error);\n }\n }\n\n return () => {\n subscription?.remove();\n };\n }, []);\n\n return {\n nativeClientEvent,\n };\n}\n"],"mappings":";;;;;;AAKA,MAAM,2BAA2B;AA6BjC,SAAS,8BAAgE;CACvE,IAAIA,sBAAS,OAAO,OAClB,OAAOC;CAGT,IAAIC,2CAAa,OAAOA,wCAAU,gBAAgB,YAChD,OAAOA;CAGT,OAAO;AACT;;;;AAKA,SAAgB,wBAAqD;CACnE,MAAM,CAAC,mBAAmB,4CAA2D,IAAI;CAEzF,2BAAgB;EACd,IAAI,CAACC,6CAAqB,CAACD,yCACzB;EAGF,IAAI,eAA8C;EAElD,IAAI;GACF,MAAM,eAAe,4BAA4B;GAEjD,IAAI,CAAC,cACH;GAGF,eAAe,aAAa,YAAY,2BAA0B,aAAY;IAC5E,qBAAqB;KAAE,UAAU,KAAK,IAAI;KAAG,GAAG;IAAS,CAAC;GAC5D,CAAC;EACH,SAAS,OAAO,CAIhB;EAEA,aAAa;GACX,cAAc,OAAO;EACvB;CACF,GAAG,CAAC,CAAC;CAEL,OAAO,EACL,kBACF;AACF"}
|
|
@@ -11,7 +11,7 @@ let src_provider_nativeClientSync = require("./nativeClientSync");
|
|
|
11
11
|
//#region src/provider/ClerkProvider.tsx
|
|
12
12
|
const SDK_METADATA = {
|
|
13
13
|
name: "@clerk/expo",
|
|
14
|
-
version: "3.4.7
|
|
14
|
+
version: "3.4.7"
|
|
15
15
|
};
|
|
16
16
|
function ClerkProvider(props) {
|
|
17
17
|
const { children, tokenCache, publishableKey, proxyUrl, domain, __experimental_passkeys, experimental, __experimental_resourceCache, ...rest } = props;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeClientSync.d.ts","sourceRoot":"","sources":["../../src/provider/nativeClientSync.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,KAAK,gBAAgB,EAA2C,MAAM,OAAO,CAAC;AAIvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAcjD,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,IAAI,CAAC;IAC5F,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,8BAA8B,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACxG,iCAAiC,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE,CAAC;
|
|
1
|
+
{"version":3,"file":"nativeClientSync.d.ts","sourceRoot":"","sources":["../../src/provider/nativeClientSync.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,KAAK,gBAAgB,EAA2C,MAAM,OAAO,CAAC;AAIvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAcjD,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,IAAI,CAAC;IAC5F,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,8BAA8B,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACxG,iCAAiC,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE,CAAC;AAWF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;AAM5E,wBAAgB,qBAAqB,CAAC,EACpC,kCAAkC,EAClC,UAAU,EACV,sBAAsB,GACvB,EAAE;IACD,kCAAkC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9D,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,sBAAsB,EAAE,gBAAgB,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;CACzE,GAAG,UAAU,GAAG,SAAS,CAkCzB;AAqVD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,aAAa,EACb,gCAAgC,EAChC,0BAA0B,EAC1B,kCAAkC,EAClC,UAAU,EACV,sBAAsB,GACvB,EAAE;IACD,aAAa,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,gCAAgC,EAAE,gBAAgB,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAAC;IACzF,0BAA0B,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACrD,kCAAkC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9D,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,sBAAsB,EAAE,gBAAgB,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;CACzE,GAAG,IAAI,CAwOP;AAED,wBAAgB,wBAAwB,CAAC,EACvC,cAAc,EACd,kCAAkC,EAClC,UAAU,EACV,aAAa,GACd,EAAE;IACD,cAAc,EAAE,MAAM,CAAC;IACvB,kCAAkC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9D,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;IACnC,aAAa,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;CACzD,6BAsGA;AAED,wBAAgB,wBAAwB,CAAC,EACvC,aAAa,EACb,YAAY,EACZ,gCAAgC,EAChC,0BAA0B,EAC1B,kCAAkC,EAClC,UAAU,GACX,EAAE;IACD,aAAa,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,CAAC;IACxD,YAAY,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxC,gCAAgC,EAAE,gBAAgB,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAAC;IACzF,0BAA0B,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACrD,kCAAkC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9D,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC;CACpC,QAwCA"}
|
|
@@ -159,8 +159,10 @@ async function runWithSuppressedJsClientChanges(suppressJsClientChangedRef, task
|
|
|
159
159
|
}
|
|
160
160
|
function mergePendingNativeRefreshOptions(current, next) {
|
|
161
161
|
if (!current) return next;
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
const merged = { shouldRefreshClient: current.shouldRefreshClient || next.shouldRefreshClient };
|
|
163
|
+
if ("clientToken" in current) merged.clientToken = current.clientToken ?? null;
|
|
164
|
+
if ("clientToken" in next) merged.clientToken = next.clientToken ?? null;
|
|
165
|
+
return merged;
|
|
164
166
|
}
|
|
165
167
|
async function getCachedClientToken(tokenCache) {
|
|
166
168
|
if (!tokenCache) return null;
|
|
@@ -243,7 +245,6 @@ function NativeClientSync({ clerkInstance, nativeRefreshFromJsControllerRef, sup
|
|
|
243
245
|
}, [clerkInstance, suppressJsClientChangedRef]);
|
|
244
246
|
const queueNativeRefreshFromJs = (0, react.useCallback)((options) => {
|
|
245
247
|
if (isRefreshingNativeFromJsRef.current) {
|
|
246
|
-
if (!("clientToken" in options)) return;
|
|
247
248
|
pendingNativeRefreshRef.current = mergePendingNativeRefreshOptions(pendingNativeRefreshRef.current, options);
|
|
248
249
|
nativeRefreshGenerationRef.current += 1;
|
|
249
250
|
return;
|
|
@@ -257,7 +258,7 @@ function NativeClientSync({ clerkInstance, nativeRefreshFromJsControllerRef, sup
|
|
|
257
258
|
const bearerToken = "clientToken" in options ? options.clientToken ?? null : null;
|
|
258
259
|
if (generation !== nativeRefreshGenerationRef.current) return;
|
|
259
260
|
const sourceId = `${nativeClientSyncSourceIdPrefix}-${generation}`;
|
|
260
|
-
await ClerkExpo.syncFromJsClientToken(bearerToken, sourceId);
|
|
261
|
+
await ClerkExpo.syncFromJsClientToken(bearerToken, sourceId, options.shouldRefreshClient);
|
|
261
262
|
};
|
|
262
263
|
let latestRunGeneration = initialGeneration;
|
|
263
264
|
(async () => {
|
|
@@ -269,7 +270,7 @@ function NativeClientSync({ clerkInstance, nativeRefreshFromJsControllerRef, sup
|
|
|
269
270
|
try {
|
|
270
271
|
await refreshNativeFromJsClient(pendingOptions, generation);
|
|
271
272
|
} catch (error) {}
|
|
272
|
-
pendingOptions = pendingNativeRefreshRef.current ?? {};
|
|
273
|
+
pendingOptions = pendingNativeRefreshRef.current ?? { shouldRefreshClient: false };
|
|
273
274
|
if (pendingNativeRefreshRef.current !== null) {
|
|
274
275
|
generation = nativeRefreshGenerationRef.current + 1;
|
|
275
276
|
nativeRefreshGenerationRef.current = generation;
|
|
@@ -281,7 +282,10 @@ function NativeClientSync({ clerkInstance, nativeRefreshFromJsControllerRef, sup
|
|
|
281
282
|
}, []);
|
|
282
283
|
(0, react.useEffect)(() => {
|
|
283
284
|
const listener = (clientToken) => {
|
|
284
|
-
queueNativeRefreshFromJs({
|
|
285
|
+
queueNativeRefreshFromJs({
|
|
286
|
+
clientToken,
|
|
287
|
+
shouldRefreshClient: clientToken === null
|
|
288
|
+
});
|
|
285
289
|
};
|
|
286
290
|
const tokenCacheListeners = tokenCacheListenersRef.current;
|
|
287
291
|
tokenCacheListeners.add(listener);
|
|
@@ -334,7 +338,7 @@ function NativeClientSync({ clerkInstance, nativeRefreshFromJsControllerRef, sup
|
|
|
334
338
|
if (!clerkInstance || typeof clerkInstance.addListener !== "function") return;
|
|
335
339
|
const unsubscribe = clerkInstance.addListener(() => {
|
|
336
340
|
if (suppressJsClientChangedRef.current > 0) return;
|
|
337
|
-
queueNativeRefreshFromJs({});
|
|
341
|
+
queueNativeRefreshFromJs({ shouldRefreshClient: true });
|
|
338
342
|
}, { skipInitialEmit: true });
|
|
339
343
|
return () => {
|
|
340
344
|
unsubscribe();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeClientSync.js","names":["Platform","MemoryTokenCache","CLERK_CLIENT_JWT_KEY","NativeClerkModule"],"sources":["../../src/provider/nativeClientSync.tsx"],"sourcesContent":["import type { ClientResource, SignedInSessionResource } from '@clerk/shared/types';\nimport { type MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { Platform } from 'react-native';\n\nimport { MemoryTokenCache } from '../cache';\nimport type { TokenCache } from '../cache/types';\nimport { CLERK_CLIENT_JWT_KEY } from '../constants';\nimport {\n type NativeClientEvent,\n type NativeClientSnapshot,\n useNativeClientEvents,\n} from '../hooks/useNativeClientEvents';\nimport { ClerkExpoModule as NativeClerkModule } from '../utils/native-module';\n\nconst tokenCacheReadTimeoutMs = 1_000;\nconst clientTokenPollIntervalMs = 100;\nconst clientTokenAvailabilityTimeoutMs = 3_000;\nconst nativeClientSyncSourceIdPrefix = 'clerk-expo-js-sync';\n\nexport type SyncableClerkInstance = {\n addListener?: (listener: () => void, options?: { skipInitialEmit?: boolean }) => () => void;\n addOnLoaded?: (listener: () => void) => void;\n client?: ClientResource;\n handleUnauthenticated?: (options?: { broadcast?: boolean }) => Promise<unknown>;\n loaded?: boolean;\n session?: SignedInSessionResource | null;\n setActive?: (params: { session: SignedInSessionResource | string | null }) => Promise<void>;\n updateClient?: (client: ClientResource, options?: { __internal_dangerouslySkipEmit?: boolean }) => void;\n __internal_reloadInitialResources?: () => void | Promise<void>;\n};\n\ntype RefreshableClientResource = ClientResource & {\n fetch?: (options?: { fetchMaxTries?: number }) => Promise<ClientResource>;\n};\n\ntype NativeRefreshFromJsOptions = {\n clientToken?: string | null;\n};\n\nexport type NativeRefreshFromJsController = {\n cancel: () => void;\n};\n\nexport type ClientTokenCacheListener = (clientToken: string | null) => void;\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport function useSyncableTokenCache({\n suppressTokenCacheNotificationsRef,\n tokenCache,\n tokenCacheListenersRef,\n}: {\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n tokenCacheListenersRef: MutableRefObject<Set<ClientTokenCacheListener>>;\n}): TokenCache | undefined {\n return useMemo(() => {\n const effectiveTokenCache =\n tokenCache ?? (Platform.OS === 'ios' || Platform.OS === 'android' ? MemoryTokenCache : undefined);\n if (!effectiveTokenCache) {\n return undefined;\n }\n\n const notifyClientTokenListeners = (clientToken: string | null) => {\n if (suppressTokenCacheNotificationsRef.current) {\n return;\n }\n\n for (const listener of tokenCacheListenersRef.current) {\n listener(clientToken);\n }\n };\n\n return {\n getToken: key => effectiveTokenCache.getToken(key),\n saveToken: async (key, token) => {\n await effectiveTokenCache.saveToken(key, token);\n if (key === CLERK_CLIENT_JWT_KEY) {\n notifyClientTokenListeners(token);\n }\n },\n clearToken: async key => {\n await effectiveTokenCache.clearToken?.(key);\n if (key === CLERK_CLIENT_JWT_KEY) {\n notifyClientTokenListeners(null);\n }\n },\n };\n }, [suppressTokenCacheNotificationsRef, tokenCache, tokenCacheListenersRef]);\n}\n\nfunction getNativeClientTokenFromSnapshot(\n snapshot: NativeClientSnapshot | null | undefined,\n): string | null | undefined {\n if (!snapshot || !('clientToken' in snapshot)) {\n return undefined;\n }\n\n return snapshot.clientToken ?? null;\n}\n\nasync function readNativeClientToken({ waitForToken }: { waitForToken: boolean }): Promise<string | null> {\n const ClerkExpo = NativeClerkModule;\n if (!ClerkExpo?.getClientToken) {\n return null;\n }\n\n const startedAt = Date.now();\n let remainingMs = clientTokenAvailabilityTimeoutMs;\n\n do {\n const nativeClientToken = await ClerkExpo.getClientToken();\n if (nativeClientToken) {\n return nativeClientToken;\n }\n\n if (!waitForToken) {\n return null;\n }\n\n remainingMs = clientTokenAvailabilityTimeoutMs - (Date.now() - startedAt);\n if (remainingMs <= 0) {\n return null;\n }\n\n await delay(Math.min(clientTokenPollIntervalMs, remainingMs));\n } while (remainingMs > 0);\n\n return null;\n}\n\nasync function syncClientTokenToCache(tokenCache: TokenCache | undefined, clientToken: string | null): Promise<void> {\n if (clientToken) {\n await tokenCache?.saveToken(CLERK_CLIENT_JWT_KEY, clientToken);\n return;\n }\n\n await tokenCache?.clearToken?.(CLERK_CLIENT_JWT_KEY);\n}\n\nasync function syncClientTokenToCacheWithoutNotifying({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clientToken: string | null;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n suppressTokenCacheNotificationsRef.current = true;\n try {\n await syncClientTokenToCache(tokenCache, clientToken);\n } finally {\n suppressTokenCacheNotificationsRef.current = false;\n }\n}\n\nasync function syncNativeTokenToCache({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clientToken: string | null;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n if (suppressTokenCacheNotificationsRef) {\n await syncClientTokenToCacheWithoutNotifying({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n return;\n }\n\n await syncClientTokenToCache(tokenCache, clientToken);\n}\n\nfunction getDefaultSignedInSession(client: ClientResource | null | undefined): SignedInSessionResource | null {\n if (!client) {\n return null;\n }\n\n if (client.lastActiveSessionId) {\n const lastActiveSession = client.signedInSessions.find(session => session.id === client.lastActiveSessionId);\n if (lastActiveSession) {\n return lastActiveSession;\n }\n }\n\n return client.signedInSessions[0] ?? null;\n}\n\nasync function refreshJsClientWithoutEmitting(clerkInstance: SyncableClerkInstance): Promise<ClientResource | null> {\n const client = clerkInstance.client as RefreshableClientResource | undefined;\n\n if (typeof client?.fetch !== 'function' || typeof clerkInstance.updateClient !== 'function') {\n return null;\n }\n\n const refreshedClient = await client.fetch({ fetchMaxTries: 1 });\n const nextSession = getDefaultSignedInSession(refreshedClient);\n\n clerkInstance.updateClient(refreshedClient, {\n __internal_dangerouslySkipEmit: Boolean(nextSession),\n });\n\n return refreshedClient;\n}\n\nasync function refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeClientToken: string | null;\n reloadInitialResources: boolean;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n await syncNativeTokenToCache({\n clientToken: nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n\n const refreshedClient = await refreshJsClientWithoutEmitting(clerkInstance);\n if (refreshedClient) {\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return true;\n }\n\n if (reloadInitialResources && typeof clerkInstance.__internal_reloadInitialResources === 'function') {\n await clerkInstance.__internal_reloadInitialResources();\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return Boolean(getDefaultSignedInSession(clerkInstance.client));\n }\n\n return false;\n}\n\nasync function reloadJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeClientToken: string;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n await syncNativeTokenToCache({\n clientToken: nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n\n await clerkInstance.__internal_reloadInitialResources?.();\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return Boolean(getDefaultSignedInSession(clerkInstance.client));\n}\n\nasync function recoverJsClientFromNativeToken({\n clerkInstance,\n error,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n error: unknown;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n const nativeClientToken = await readNativeClientToken({ waitForToken: false });\n if (!nativeClientToken) {\n return false;\n }\n\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to refresh JS client with native client token:', error);\n }\n\n try {\n return await reloadJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n } catch (recoveryError) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to recover JS client after unauthenticated state:', recoveryError);\n }\n return false;\n }\n}\n\nasync function reconcileJsActiveSessionFromClient({\n clerkInstance,\n}: {\n clerkInstance: SyncableClerkInstance;\n}): Promise<void> {\n const fallbackSession = getDefaultSignedInSession(clerkInstance.client);\n if (!fallbackSession || typeof clerkInstance.setActive !== 'function') {\n return;\n }\n\n const currentSession = clerkInstance.session;\n const currentSessionStillExists = currentSession\n ? clerkInstance.client?.signedInSessions.some(session => session.id === currentSession.id)\n : false;\n\n if (currentSessionStillExists && currentSession?.id === fallbackSession.id) {\n return;\n }\n\n await clerkInstance.setActive({ session: fallbackSession });\n}\n\nasync function runWithSuppressedJsClientChanges<T>(\n suppressJsClientChangedRef: MutableRefObject<number> | undefined,\n task: () => Promise<T>,\n): Promise<T> {\n if (!suppressJsClientChangedRef) {\n return task();\n }\n\n suppressJsClientChangedRef.current += 1;\n try {\n return await task();\n } finally {\n suppressJsClientChangedRef.current = Math.max(0, suppressJsClientChangedRef.current - 1);\n }\n}\n\nfunction mergePendingNativeRefreshOptions(\n current: NativeRefreshFromJsOptions | null,\n next: NativeRefreshFromJsOptions,\n): NativeRefreshFromJsOptions {\n if (!current) {\n return next;\n }\n\n if ('clientToken' in next) {\n return {\n clientToken: next.clientToken ?? null,\n };\n }\n\n return current;\n}\n\nasync function getCachedClientToken(tokenCache: TokenCache | undefined): Promise<string | null> {\n if (!tokenCache) {\n return null;\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n try {\n return (\n (await Promise.race([\n tokenCache.getToken(CLERK_CLIENT_JWT_KEY),\n new Promise<null>(resolve => {\n timeoutId = setTimeout(() => resolve(null), tokenCacheReadTimeoutMs);\n }),\n ])) ?? null\n );\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n}\n\nasync function syncNativeClientToJs({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n nativeClientEvent,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeRefreshFromJsControllerRef?: MutableRefObject<NativeRefreshFromJsController | null>;\n nativeClientEvent?: NativeClientEvent | null;\n suppressJsClientChangedRef?: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n const nativeClientTokenFromEvent = getNativeClientTokenFromSnapshot(nativeClientEvent);\n const nativeClientToken =\n nativeClientTokenFromEvent !== undefined\n ? nativeClientTokenFromEvent\n : await readNativeClientToken({\n waitForToken: !nativeClientEvent,\n });\n\n if (!nativeClientToken && !nativeClientEvent) {\n return;\n }\n\n await runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n nativeRefreshFromJsControllerRef?.current?.cancel();\n\n await refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources: true,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n });\n}\n\n/**\n * Syncs JS SDK client changes to the native Clerk SDK so native components\n * (UserButton, UserProfileView) stay in sync after JS-owned resource changes.\n *\n * Must be rendered inside `ClerkReactProvider` so the Clerk instance has loaded\n * resources to emit.\n */\nexport function NativeClientSync({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n tokenCacheListenersRef,\n}: {\n clerkInstance: SyncableClerkInstance | null | undefined;\n nativeRefreshFromJsControllerRef: MutableRefObject<NativeRefreshFromJsController | null>;\n suppressJsClientChangedRef: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n tokenCacheListenersRef: MutableRefObject<Set<ClientTokenCacheListener>>;\n}): null {\n const isRefreshingNativeFromJsRef = useRef(false);\n const pendingNativeRefreshRef = useRef<NativeRefreshFromJsOptions | null>(null);\n const nativeRefreshGenerationRef = useRef(0);\n\n const cancelNativeRefreshFromJs = useCallback(() => {\n pendingNativeRefreshRef.current = null;\n nativeRefreshGenerationRef.current += 1;\n isRefreshingNativeFromJsRef.current = false;\n }, []);\n\n useEffect(() => {\n nativeRefreshFromJsControllerRef.current = {\n cancel: cancelNativeRefreshFromJs,\n };\n\n return () => {\n if (nativeRefreshFromJsControllerRef.current?.cancel === cancelNativeRefreshFromJs) {\n nativeRefreshFromJsControllerRef.current = null;\n }\n };\n }, [cancelNativeRefreshFromJs, nativeRefreshFromJsControllerRef]);\n\n useEffect(() => {\n if (\n !clerkInstance ||\n typeof clerkInstance.updateClient !== 'function' ||\n typeof clerkInstance.setActive !== 'function'\n ) {\n return;\n }\n\n const originalUpdateClient = clerkInstance.updateClient.bind(clerkInstance);\n let isReconcilingRemovedActiveSession = false;\n\n const updateClient: SyncableClerkInstance['updateClient'] = (newClient, options) => {\n const currentSessionId = clerkInstance.session?.id;\n const fallbackSession = getDefaultSignedInSession(newClient);\n const currentSessionWasRemoved = currentSessionId\n ? !newClient.signedInSessions.some(session => session.id === currentSessionId)\n : false;\n const alreadyReconcilingRemovedActiveSession = isReconcilingRemovedActiveSession;\n\n if ((currentSessionWasRemoved || alreadyReconcilingRemovedActiveSession) && fallbackSession) {\n // Clerk JS briefly emits signed-out when the active session disappears,\n // even if the refreshed client still has another signed-in session.\n // Keep that transient state internal so native session switching does\n // not dismiss mounted native UI before setActive settles on JS.\n isReconcilingRemovedActiveSession = true;\n originalUpdateClient(newClient, { __internal_dangerouslySkipEmit: true });\n\n if (alreadyReconcilingRemovedActiveSession) {\n return;\n }\n\n void runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n try {\n await clerkInstance.setActive?.({ session: fallbackSession });\n } catch (error) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to set remaining active JS session:', error);\n }\n originalUpdateClient(newClient, options);\n } finally {\n isReconcilingRemovedActiveSession = false;\n }\n });\n return;\n }\n\n originalUpdateClient(newClient, options);\n };\n\n clerkInstance.updateClient = updateClient;\n\n return () => {\n if (clerkInstance.updateClient === updateClient) {\n clerkInstance.updateClient = originalUpdateClient;\n }\n };\n }, [clerkInstance, suppressJsClientChangedRef]);\n\n const queueNativeRefreshFromJs = useCallback((options: NativeRefreshFromJsOptions): void => {\n if (isRefreshingNativeFromJsRef.current) {\n if (!('clientToken' in options)) {\n return;\n }\n\n pendingNativeRefreshRef.current = mergePendingNativeRefreshOptions(pendingNativeRefreshRef.current, options);\n nativeRefreshGenerationRef.current += 1;\n return;\n }\n\n const initialGeneration = nativeRefreshGenerationRef.current + 1;\n nativeRefreshGenerationRef.current = initialGeneration;\n isRefreshingNativeFromJsRef.current = true;\n\n const refreshNativeFromJsClient = async (\n options: NativeRefreshFromJsOptions,\n generation: number,\n ): Promise<void> => {\n const ClerkExpo = NativeClerkModule;\n if (!ClerkExpo || generation !== nativeRefreshGenerationRef.current) {\n return;\n }\n\n const bearerToken = 'clientToken' in options ? (options.clientToken ?? null) : null;\n if (generation !== nativeRefreshGenerationRef.current) {\n return;\n }\n\n const sourceId = `${nativeClientSyncSourceIdPrefix}-${generation}`;\n await ClerkExpo.syncFromJsClientToken(bearerToken, sourceId);\n };\n\n let latestRunGeneration = initialGeneration;\n\n void (async () => {\n let pendingOptions = options;\n let generation = initialGeneration;\n do {\n latestRunGeneration = generation;\n pendingNativeRefreshRef.current = null;\n try {\n await refreshNativeFromJsClient(pendingOptions, generation);\n } catch (error: unknown) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to refresh native client from JS client change:', error);\n }\n }\n pendingOptions = pendingNativeRefreshRef.current ?? {};\n if (pendingNativeRefreshRef.current !== null) {\n generation = nativeRefreshGenerationRef.current + 1;\n nativeRefreshGenerationRef.current = generation;\n }\n } while (pendingNativeRefreshRef.current !== null);\n })().finally(() => {\n if (latestRunGeneration === nativeRefreshGenerationRef.current || pendingNativeRefreshRef.current === null) {\n isRefreshingNativeFromJsRef.current = false;\n }\n });\n }, []);\n\n useEffect(() => {\n const listener: ClientTokenCacheListener = clientToken => {\n queueNativeRefreshFromJs({ clientToken });\n };\n const tokenCacheListeners = tokenCacheListenersRef.current;\n\n tokenCacheListeners.add(listener);\n return () => {\n tokenCacheListeners.delete(listener);\n };\n }, [queueNativeRefreshFromJs, tokenCacheListenersRef]);\n\n useEffect(() => {\n if (!clerkInstance || typeof clerkInstance.handleUnauthenticated !== 'function') {\n return;\n }\n\n const originalHandleUnauthenticated = clerkInstance.handleUnauthenticated.bind(clerkInstance);\n let isHandlingUnauthenticated = false;\n\n const handleUnauthenticated: SyncableClerkInstance['handleUnauthenticated'] = async options => {\n if (isHandlingUnauthenticated) {\n return;\n }\n\n isHandlingUnauthenticated = true;\n try {\n return await runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n try {\n const nativeClientToken = await readNativeClientToken({ waitForToken: false });\n // Native may have already moved the server-side client to a new\n // active session. Refresh JS before allowing Clerk JS' stale-session\n // 401 path to collapse the whole client to signed out.\n const didRecover = await refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources: false,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n if (didRecover) {\n return;\n }\n } catch (error) {\n const didRecover = await recoverJsClientFromNativeToken({\n clerkInstance,\n error,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n if (didRecover) {\n return;\n }\n }\n\n return originalHandleUnauthenticated(options);\n });\n } finally {\n isHandlingUnauthenticated = false;\n }\n };\n\n clerkInstance.handleUnauthenticated = handleUnauthenticated;\n\n return () => {\n if (clerkInstance.handleUnauthenticated === handleUnauthenticated) {\n clerkInstance.handleUnauthenticated = originalHandleUnauthenticated;\n }\n };\n }, [clerkInstance, suppressJsClientChangedRef, suppressTokenCacheNotificationsRef, tokenCache]);\n\n useEffect(() => {\n if (!clerkInstance || typeof clerkInstance.addListener !== 'function') {\n return;\n }\n\n const unsubscribe = clerkInstance.addListener(\n () => {\n if (suppressJsClientChangedRef.current > 0) {\n return;\n }\n\n queueNativeRefreshFromJs({});\n },\n { skipInitialEmit: true },\n );\n\n return () => {\n unsubscribe();\n };\n }, [clerkInstance, queueNativeRefreshFromJs, suppressJsClientChangedRef]);\n\n return null;\n}\n\nexport function useNativeClientBootstrap({\n publishableKey,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n clerkInstance,\n}: {\n publishableKey: string;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n clerkInstance: SyncableClerkInstance | null | undefined;\n}) {\n const initStartedRef = useRef(false);\n const nativeClientSyncedRef = useRef(false);\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n initStartedRef.current = false;\n nativeClientSyncedRef.current = false;\n }, [publishableKey]);\n\n useEffect(() => {\n isMountedRef.current = true;\n\n if ((Platform.OS === 'ios' || Platform.OS === 'android') && publishableKey && !initStartedRef.current) {\n initStartedRef.current = true;\n\n const configureNativeClerk = async () => {\n try {\n const ClerkExpo = NativeClerkModule;\n\n if (ClerkExpo?.configure) {\n await ClerkExpo.configure(publishableKey, null);\n\n if (!isMountedRef.current) {\n return;\n }\n\n let bearerToken: string | null = null;\n try {\n bearerToken = await getCachedClientToken(tokenCache);\n } catch (e) {\n if (__DEV__) {\n console.warn('[ClerkProvider] Token cache read failed:', e);\n }\n }\n\n if (bearerToken) {\n await ClerkExpo.configure(publishableKey, bearerToken);\n\n if (!isMountedRef.current) {\n return;\n }\n }\n\n if (clerkInstance) {\n const waitForLoad = (): Promise<void> => {\n return new Promise(resolve => {\n if (clerkInstance.loaded) {\n resolve();\n } else if (typeof clerkInstance.addOnLoaded === 'function') {\n clerkInstance.addOnLoaded(() => resolve());\n } else {\n if (__DEV__) {\n console.warn('[ClerkProvider] Clerk instance has no loaded property or addOnLoaded method');\n }\n resolve();\n }\n });\n };\n\n await waitForLoad();\n\n if (!isMountedRef.current) {\n return;\n }\n\n if (!nativeClientSyncedRef.current) {\n nativeClientSyncedRef.current = true;\n await syncNativeClientToJs({\n clerkInstance,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n }\n }\n }\n } catch (error) {\n const isNativeModuleNotFound =\n error instanceof Error &&\n (error.message.includes('Cannot find native module') ||\n error.message.includes(\"TurboModuleRegistry.getEnforcing(...): 'ClerkExpo'\"));\n if (isNativeModuleNotFound) {\n if (__DEV__) {\n console.debug(\n `[ClerkProvider] Native Clerk module not available. ` +\n `To enable native features, add \"@clerk/expo\" to your app.json plugins array.`,\n );\n }\n } else if (__DEV__) {\n console.error(`[ClerkProvider] Failed to configure Clerk ${Platform.OS}:`, error);\n }\n }\n };\n void configureNativeClerk();\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [publishableKey, suppressTokenCacheNotificationsRef, tokenCache, clerkInstance]);\n\n return isMountedRef;\n}\n\nexport function useNativeClientEventSync({\n clerkInstance,\n isMountedRef,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance | null | undefined;\n isMountedRef: MutableRefObject<boolean>;\n nativeRefreshFromJsControllerRef: MutableRefObject<NativeRefreshFromJsController | null>;\n suppressJsClientChangedRef: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}) {\n const { nativeClientEvent } = useNativeClientEvents();\n\n useEffect(() => {\n if (!nativeClientEvent || !clerkInstance) {\n return;\n }\n\n if (nativeClientEvent.sourceId?.startsWith(nativeClientSyncSourceIdPrefix)) {\n return;\n }\n\n const syncNativeClientStateToJs = async () => {\n try {\n if (!isMountedRef.current) {\n return;\n }\n await syncNativeClientToJs({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n nativeClientEvent,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n } catch (error) {\n console.error(`[ClerkProvider] Failed to sync native client state:`, error);\n }\n };\n\n void syncNativeClientStateToJs();\n }, [\n nativeClientEvent,\n clerkInstance,\n isMountedRef,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n ]);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nativeClientSync.js","names":["Platform","MemoryTokenCache","CLERK_CLIENT_JWT_KEY","NativeClerkModule"],"sources":["../../src/provider/nativeClientSync.tsx"],"sourcesContent":["import type { ClientResource, SignedInSessionResource } from '@clerk/shared/types';\nimport { type MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { Platform } from 'react-native';\n\nimport { MemoryTokenCache } from '../cache';\nimport type { TokenCache } from '../cache/types';\nimport { CLERK_CLIENT_JWT_KEY } from '../constants';\nimport {\n type NativeClientEvent,\n type NativeClientSnapshot,\n useNativeClientEvents,\n} from '../hooks/useNativeClientEvents';\nimport { ClerkExpoModule as NativeClerkModule } from '../utils/native-module';\n\nconst tokenCacheReadTimeoutMs = 1_000;\nconst clientTokenPollIntervalMs = 100;\nconst clientTokenAvailabilityTimeoutMs = 3_000;\nconst nativeClientSyncSourceIdPrefix = 'clerk-expo-js-sync';\n\nexport type SyncableClerkInstance = {\n addListener?: (listener: () => void, options?: { skipInitialEmit?: boolean }) => () => void;\n addOnLoaded?: (listener: () => void) => void;\n client?: ClientResource;\n handleUnauthenticated?: (options?: { broadcast?: boolean }) => Promise<unknown>;\n loaded?: boolean;\n session?: SignedInSessionResource | null;\n setActive?: (params: { session: SignedInSessionResource | string | null }) => Promise<void>;\n updateClient?: (client: ClientResource, options?: { __internal_dangerouslySkipEmit?: boolean }) => void;\n __internal_reloadInitialResources?: () => void | Promise<void>;\n};\n\ntype RefreshableClientResource = ClientResource & {\n fetch?: (options?: { fetchMaxTries?: number }) => Promise<ClientResource>;\n};\n\ntype NativeRefreshFromJsOptions = {\n clientToken?: string | null;\n shouldRefreshClient: boolean;\n};\n\nexport type NativeRefreshFromJsController = {\n cancel: () => void;\n};\n\nexport type ClientTokenCacheListener = (clientToken: string | null) => void;\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport function useSyncableTokenCache({\n suppressTokenCacheNotificationsRef,\n tokenCache,\n tokenCacheListenersRef,\n}: {\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n tokenCacheListenersRef: MutableRefObject<Set<ClientTokenCacheListener>>;\n}): TokenCache | undefined {\n return useMemo(() => {\n const effectiveTokenCache =\n tokenCache ?? (Platform.OS === 'ios' || Platform.OS === 'android' ? MemoryTokenCache : undefined);\n if (!effectiveTokenCache) {\n return undefined;\n }\n\n const notifyClientTokenListeners = (clientToken: string | null) => {\n if (suppressTokenCacheNotificationsRef.current) {\n return;\n }\n\n for (const listener of tokenCacheListenersRef.current) {\n listener(clientToken);\n }\n };\n\n return {\n getToken: key => effectiveTokenCache.getToken(key),\n saveToken: async (key, token) => {\n await effectiveTokenCache.saveToken(key, token);\n if (key === CLERK_CLIENT_JWT_KEY) {\n notifyClientTokenListeners(token);\n }\n },\n clearToken: async key => {\n await effectiveTokenCache.clearToken?.(key);\n if (key === CLERK_CLIENT_JWT_KEY) {\n notifyClientTokenListeners(null);\n }\n },\n };\n }, [suppressTokenCacheNotificationsRef, tokenCache, tokenCacheListenersRef]);\n}\n\nfunction getNativeClientTokenFromSnapshot(\n snapshot: NativeClientSnapshot | null | undefined,\n): string | null | undefined {\n if (!snapshot || !('clientToken' in snapshot)) {\n return undefined;\n }\n\n return snapshot.clientToken ?? null;\n}\n\nasync function readNativeClientToken({ waitForToken }: { waitForToken: boolean }): Promise<string | null> {\n const ClerkExpo = NativeClerkModule;\n if (!ClerkExpo?.getClientToken) {\n return null;\n }\n\n const startedAt = Date.now();\n let remainingMs = clientTokenAvailabilityTimeoutMs;\n\n do {\n const nativeClientToken = await ClerkExpo.getClientToken();\n if (nativeClientToken) {\n return nativeClientToken;\n }\n\n if (!waitForToken) {\n return null;\n }\n\n remainingMs = clientTokenAvailabilityTimeoutMs - (Date.now() - startedAt);\n if (remainingMs <= 0) {\n return null;\n }\n\n await delay(Math.min(clientTokenPollIntervalMs, remainingMs));\n } while (remainingMs > 0);\n\n return null;\n}\n\nasync function syncClientTokenToCache(tokenCache: TokenCache | undefined, clientToken: string | null): Promise<void> {\n if (clientToken) {\n await tokenCache?.saveToken(CLERK_CLIENT_JWT_KEY, clientToken);\n return;\n }\n\n await tokenCache?.clearToken?.(CLERK_CLIENT_JWT_KEY);\n}\n\nasync function syncClientTokenToCacheWithoutNotifying({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clientToken: string | null;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n suppressTokenCacheNotificationsRef.current = true;\n try {\n await syncClientTokenToCache(tokenCache, clientToken);\n } finally {\n suppressTokenCacheNotificationsRef.current = false;\n }\n}\n\nasync function syncNativeTokenToCache({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clientToken: string | null;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n if (suppressTokenCacheNotificationsRef) {\n await syncClientTokenToCacheWithoutNotifying({\n clientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n return;\n }\n\n await syncClientTokenToCache(tokenCache, clientToken);\n}\n\nfunction getDefaultSignedInSession(client: ClientResource | null | undefined): SignedInSessionResource | null {\n if (!client) {\n return null;\n }\n\n if (client.lastActiveSessionId) {\n const lastActiveSession = client.signedInSessions.find(session => session.id === client.lastActiveSessionId);\n if (lastActiveSession) {\n return lastActiveSession;\n }\n }\n\n return client.signedInSessions[0] ?? null;\n}\n\nasync function refreshJsClientWithoutEmitting(clerkInstance: SyncableClerkInstance): Promise<ClientResource | null> {\n const client = clerkInstance.client as RefreshableClientResource | undefined;\n\n if (typeof client?.fetch !== 'function' || typeof clerkInstance.updateClient !== 'function') {\n return null;\n }\n\n const refreshedClient = await client.fetch({ fetchMaxTries: 1 });\n const nextSession = getDefaultSignedInSession(refreshedClient);\n\n clerkInstance.updateClient(refreshedClient, {\n __internal_dangerouslySkipEmit: Boolean(nextSession),\n });\n\n return refreshedClient;\n}\n\nasync function refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeClientToken: string | null;\n reloadInitialResources: boolean;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n await syncNativeTokenToCache({\n clientToken: nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n\n const refreshedClient = await refreshJsClientWithoutEmitting(clerkInstance);\n if (refreshedClient) {\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return true;\n }\n\n if (reloadInitialResources && typeof clerkInstance.__internal_reloadInitialResources === 'function') {\n await clerkInstance.__internal_reloadInitialResources();\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return Boolean(getDefaultSignedInSession(clerkInstance.client));\n }\n\n return false;\n}\n\nasync function reloadJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeClientToken: string;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n await syncNativeTokenToCache({\n clientToken: nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n\n await clerkInstance.__internal_reloadInitialResources?.();\n await reconcileJsActiveSessionFromClient({\n clerkInstance,\n });\n return Boolean(getDefaultSignedInSession(clerkInstance.client));\n}\n\nasync function recoverJsClientFromNativeToken({\n clerkInstance,\n error,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n error: unknown;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<boolean> {\n const nativeClientToken = await readNativeClientToken({ waitForToken: false });\n if (!nativeClientToken) {\n return false;\n }\n\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to refresh JS client with native client token:', error);\n }\n\n try {\n return await reloadJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n } catch (recoveryError) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to recover JS client after unauthenticated state:', recoveryError);\n }\n return false;\n }\n}\n\nasync function reconcileJsActiveSessionFromClient({\n clerkInstance,\n}: {\n clerkInstance: SyncableClerkInstance;\n}): Promise<void> {\n const fallbackSession = getDefaultSignedInSession(clerkInstance.client);\n if (!fallbackSession || typeof clerkInstance.setActive !== 'function') {\n return;\n }\n\n const currentSession = clerkInstance.session;\n const currentSessionStillExists = currentSession\n ? clerkInstance.client?.signedInSessions.some(session => session.id === currentSession.id)\n : false;\n\n if (currentSessionStillExists && currentSession?.id === fallbackSession.id) {\n return;\n }\n\n await clerkInstance.setActive({ session: fallbackSession });\n}\n\nasync function runWithSuppressedJsClientChanges<T>(\n suppressJsClientChangedRef: MutableRefObject<number> | undefined,\n task: () => Promise<T>,\n): Promise<T> {\n if (!suppressJsClientChangedRef) {\n return task();\n }\n\n suppressJsClientChangedRef.current += 1;\n try {\n return await task();\n } finally {\n suppressJsClientChangedRef.current = Math.max(0, suppressJsClientChangedRef.current - 1);\n }\n}\n\nfunction mergePendingNativeRefreshOptions(\n current: NativeRefreshFromJsOptions | null,\n next: NativeRefreshFromJsOptions,\n): NativeRefreshFromJsOptions {\n if (!current) {\n return next;\n }\n\n const merged: NativeRefreshFromJsOptions = {\n shouldRefreshClient: current.shouldRefreshClient || next.shouldRefreshClient,\n };\n\n if ('clientToken' in current) {\n merged.clientToken = current.clientToken ?? null;\n }\n\n if ('clientToken' in next) {\n merged.clientToken = next.clientToken ?? null;\n }\n\n return merged;\n}\n\nasync function getCachedClientToken(tokenCache: TokenCache | undefined): Promise<string | null> {\n if (!tokenCache) {\n return null;\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n try {\n return (\n (await Promise.race([\n tokenCache.getToken(CLERK_CLIENT_JWT_KEY),\n new Promise<null>(resolve => {\n timeoutId = setTimeout(() => resolve(null), tokenCacheReadTimeoutMs);\n }),\n ])) ?? null\n );\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n}\n\nasync function syncNativeClientToJs({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n nativeClientEvent,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance;\n nativeRefreshFromJsControllerRef?: MutableRefObject<NativeRefreshFromJsController | null>;\n nativeClientEvent?: NativeClientEvent | null;\n suppressJsClientChangedRef?: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef?: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}): Promise<void> {\n const nativeClientTokenFromEvent = getNativeClientTokenFromSnapshot(nativeClientEvent);\n const nativeClientToken =\n nativeClientTokenFromEvent !== undefined\n ? nativeClientTokenFromEvent\n : await readNativeClientToken({\n waitForToken: !nativeClientEvent,\n });\n\n if (!nativeClientToken && !nativeClientEvent) {\n return;\n }\n\n await runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n nativeRefreshFromJsControllerRef?.current?.cancel();\n\n await refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources: true,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n });\n}\n\n/**\n * Syncs JS SDK client changes to the native Clerk SDK so native components\n * (UserButton, UserProfileView) stay in sync after JS-owned resource changes.\n *\n * Must be rendered inside `ClerkReactProvider` so the Clerk instance has loaded\n * resources to emit.\n */\nexport function NativeClientSync({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n tokenCacheListenersRef,\n}: {\n clerkInstance: SyncableClerkInstance | null | undefined;\n nativeRefreshFromJsControllerRef: MutableRefObject<NativeRefreshFromJsController | null>;\n suppressJsClientChangedRef: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n tokenCacheListenersRef: MutableRefObject<Set<ClientTokenCacheListener>>;\n}): null {\n const isRefreshingNativeFromJsRef = useRef(false);\n const pendingNativeRefreshRef = useRef<NativeRefreshFromJsOptions | null>(null);\n const nativeRefreshGenerationRef = useRef(0);\n\n const cancelNativeRefreshFromJs = useCallback(() => {\n pendingNativeRefreshRef.current = null;\n nativeRefreshGenerationRef.current += 1;\n isRefreshingNativeFromJsRef.current = false;\n }, []);\n\n useEffect(() => {\n nativeRefreshFromJsControllerRef.current = {\n cancel: cancelNativeRefreshFromJs,\n };\n\n return () => {\n if (nativeRefreshFromJsControllerRef.current?.cancel === cancelNativeRefreshFromJs) {\n nativeRefreshFromJsControllerRef.current = null;\n }\n };\n }, [cancelNativeRefreshFromJs, nativeRefreshFromJsControllerRef]);\n\n useEffect(() => {\n if (\n !clerkInstance ||\n typeof clerkInstance.updateClient !== 'function' ||\n typeof clerkInstance.setActive !== 'function'\n ) {\n return;\n }\n\n const originalUpdateClient = clerkInstance.updateClient.bind(clerkInstance);\n let isReconcilingRemovedActiveSession = false;\n\n const updateClient: SyncableClerkInstance['updateClient'] = (newClient, options) => {\n const currentSessionId = clerkInstance.session?.id;\n const fallbackSession = getDefaultSignedInSession(newClient);\n const currentSessionWasRemoved = currentSessionId\n ? !newClient.signedInSessions.some(session => session.id === currentSessionId)\n : false;\n const alreadyReconcilingRemovedActiveSession = isReconcilingRemovedActiveSession;\n\n if ((currentSessionWasRemoved || alreadyReconcilingRemovedActiveSession) && fallbackSession) {\n // Clerk JS briefly emits signed-out when the active session disappears,\n // even if the refreshed client still has another signed-in session.\n // Keep that transient state internal so native session switching does\n // not dismiss mounted native UI before setActive settles on JS.\n isReconcilingRemovedActiveSession = true;\n originalUpdateClient(newClient, { __internal_dangerouslySkipEmit: true });\n\n if (alreadyReconcilingRemovedActiveSession) {\n return;\n }\n\n void runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n try {\n await clerkInstance.setActive?.({ session: fallbackSession });\n } catch (error) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to set remaining active JS session:', error);\n }\n originalUpdateClient(newClient, options);\n } finally {\n isReconcilingRemovedActiveSession = false;\n }\n });\n return;\n }\n\n originalUpdateClient(newClient, options);\n };\n\n clerkInstance.updateClient = updateClient;\n\n return () => {\n if (clerkInstance.updateClient === updateClient) {\n clerkInstance.updateClient = originalUpdateClient;\n }\n };\n }, [clerkInstance, suppressJsClientChangedRef]);\n\n const queueNativeRefreshFromJs = useCallback((options: NativeRefreshFromJsOptions): void => {\n if (isRefreshingNativeFromJsRef.current) {\n pendingNativeRefreshRef.current = mergePendingNativeRefreshOptions(pendingNativeRefreshRef.current, options);\n nativeRefreshGenerationRef.current += 1;\n return;\n }\n\n const initialGeneration = nativeRefreshGenerationRef.current + 1;\n nativeRefreshGenerationRef.current = initialGeneration;\n isRefreshingNativeFromJsRef.current = true;\n\n const refreshNativeFromJsClient = async (\n options: NativeRefreshFromJsOptions,\n generation: number,\n ): Promise<void> => {\n const ClerkExpo = NativeClerkModule;\n if (!ClerkExpo || generation !== nativeRefreshGenerationRef.current) {\n return;\n }\n\n const bearerToken = 'clientToken' in options ? (options.clientToken ?? null) : null;\n if (generation !== nativeRefreshGenerationRef.current) {\n return;\n }\n\n const sourceId = `${nativeClientSyncSourceIdPrefix}-${generation}`;\n await ClerkExpo.syncFromJsClientToken(bearerToken, sourceId, options.shouldRefreshClient);\n };\n\n let latestRunGeneration = initialGeneration;\n\n void (async () => {\n let pendingOptions = options;\n let generation = initialGeneration;\n do {\n latestRunGeneration = generation;\n pendingNativeRefreshRef.current = null;\n try {\n await refreshNativeFromJsClient(pendingOptions, generation);\n } catch (error: unknown) {\n if (__DEV__) {\n console.warn('[NativeClientSync] Failed to refresh native client from JS client change:', error);\n }\n }\n pendingOptions = pendingNativeRefreshRef.current ?? { shouldRefreshClient: false };\n if (pendingNativeRefreshRef.current !== null) {\n generation = nativeRefreshGenerationRef.current + 1;\n nativeRefreshGenerationRef.current = generation;\n }\n } while (pendingNativeRefreshRef.current !== null);\n })().finally(() => {\n if (latestRunGeneration === nativeRefreshGenerationRef.current || pendingNativeRefreshRef.current === null) {\n isRefreshingNativeFromJsRef.current = false;\n }\n });\n }, []);\n\n useEffect(() => {\n const listener: ClientTokenCacheListener = clientToken => {\n queueNativeRefreshFromJs({ clientToken, shouldRefreshClient: clientToken === null });\n };\n const tokenCacheListeners = tokenCacheListenersRef.current;\n\n tokenCacheListeners.add(listener);\n return () => {\n tokenCacheListeners.delete(listener);\n };\n }, [queueNativeRefreshFromJs, tokenCacheListenersRef]);\n\n useEffect(() => {\n if (!clerkInstance || typeof clerkInstance.handleUnauthenticated !== 'function') {\n return;\n }\n\n const originalHandleUnauthenticated = clerkInstance.handleUnauthenticated.bind(clerkInstance);\n let isHandlingUnauthenticated = false;\n\n const handleUnauthenticated: SyncableClerkInstance['handleUnauthenticated'] = async options => {\n if (isHandlingUnauthenticated) {\n return;\n }\n\n isHandlingUnauthenticated = true;\n try {\n return await runWithSuppressedJsClientChanges(suppressJsClientChangedRef, async () => {\n try {\n const nativeClientToken = await readNativeClientToken({ waitForToken: false });\n // Native may have already moved the server-side client to a new\n // active session. Refresh JS before allowing Clerk JS' stale-session\n // 401 path to collapse the whole client to signed out.\n const didRecover = await refreshJsClientFromNativeState({\n clerkInstance,\n nativeClientToken,\n reloadInitialResources: false,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n if (didRecover) {\n return;\n }\n } catch (error) {\n const didRecover = await recoverJsClientFromNativeToken({\n clerkInstance,\n error,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n if (didRecover) {\n return;\n }\n }\n\n return originalHandleUnauthenticated(options);\n });\n } finally {\n isHandlingUnauthenticated = false;\n }\n };\n\n clerkInstance.handleUnauthenticated = handleUnauthenticated;\n\n return () => {\n if (clerkInstance.handleUnauthenticated === handleUnauthenticated) {\n clerkInstance.handleUnauthenticated = originalHandleUnauthenticated;\n }\n };\n }, [clerkInstance, suppressJsClientChangedRef, suppressTokenCacheNotificationsRef, tokenCache]);\n\n useEffect(() => {\n if (!clerkInstance || typeof clerkInstance.addListener !== 'function') {\n return;\n }\n\n const unsubscribe = clerkInstance.addListener(\n () => {\n if (suppressJsClientChangedRef.current > 0) {\n return;\n }\n\n queueNativeRefreshFromJs({ shouldRefreshClient: true });\n },\n { skipInitialEmit: true },\n );\n\n return () => {\n unsubscribe();\n };\n }, [clerkInstance, queueNativeRefreshFromJs, suppressJsClientChangedRef]);\n\n return null;\n}\n\nexport function useNativeClientBootstrap({\n publishableKey,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n clerkInstance,\n}: {\n publishableKey: string;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n clerkInstance: SyncableClerkInstance | null | undefined;\n}) {\n const initStartedRef = useRef(false);\n const nativeClientSyncedRef = useRef(false);\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n initStartedRef.current = false;\n nativeClientSyncedRef.current = false;\n }, [publishableKey]);\n\n useEffect(() => {\n isMountedRef.current = true;\n\n if ((Platform.OS === 'ios' || Platform.OS === 'android') && publishableKey && !initStartedRef.current) {\n initStartedRef.current = true;\n\n const configureNativeClerk = async () => {\n try {\n const ClerkExpo = NativeClerkModule;\n\n if (ClerkExpo?.configure) {\n await ClerkExpo.configure(publishableKey, null);\n\n if (!isMountedRef.current) {\n return;\n }\n\n let bearerToken: string | null = null;\n try {\n bearerToken = await getCachedClientToken(tokenCache);\n } catch (e) {\n if (__DEV__) {\n console.warn('[ClerkProvider] Token cache read failed:', e);\n }\n }\n\n if (bearerToken) {\n await ClerkExpo.configure(publishableKey, bearerToken);\n\n if (!isMountedRef.current) {\n return;\n }\n }\n\n if (clerkInstance) {\n const waitForLoad = (): Promise<void> => {\n return new Promise(resolve => {\n if (clerkInstance.loaded) {\n resolve();\n } else if (typeof clerkInstance.addOnLoaded === 'function') {\n clerkInstance.addOnLoaded(() => resolve());\n } else {\n if (__DEV__) {\n console.warn('[ClerkProvider] Clerk instance has no loaded property or addOnLoaded method');\n }\n resolve();\n }\n });\n };\n\n await waitForLoad();\n\n if (!isMountedRef.current) {\n return;\n }\n\n if (!nativeClientSyncedRef.current) {\n nativeClientSyncedRef.current = true;\n await syncNativeClientToJs({\n clerkInstance,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n }\n }\n }\n } catch (error) {\n const isNativeModuleNotFound =\n error instanceof Error &&\n (error.message.includes('Cannot find native module') ||\n error.message.includes(\"TurboModuleRegistry.getEnforcing(...): 'ClerkExpo'\"));\n if (isNativeModuleNotFound) {\n if (__DEV__) {\n console.debug(\n `[ClerkProvider] Native Clerk module not available. ` +\n `To enable native features, add \"@clerk/expo\" to your app.json plugins array.`,\n );\n }\n } else if (__DEV__) {\n console.error(`[ClerkProvider] Failed to configure Clerk ${Platform.OS}:`, error);\n }\n }\n };\n void configureNativeClerk();\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [publishableKey, suppressTokenCacheNotificationsRef, tokenCache, clerkInstance]);\n\n return isMountedRef;\n}\n\nexport function useNativeClientEventSync({\n clerkInstance,\n isMountedRef,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n}: {\n clerkInstance: SyncableClerkInstance | null | undefined;\n isMountedRef: MutableRefObject<boolean>;\n nativeRefreshFromJsControllerRef: MutableRefObject<NativeRefreshFromJsController | null>;\n suppressJsClientChangedRef: MutableRefObject<number>;\n suppressTokenCacheNotificationsRef: MutableRefObject<boolean>;\n tokenCache: TokenCache | undefined;\n}) {\n const { nativeClientEvent } = useNativeClientEvents();\n\n useEffect(() => {\n if (!nativeClientEvent || !clerkInstance) {\n return;\n }\n\n if (nativeClientEvent.sourceId?.startsWith(nativeClientSyncSourceIdPrefix)) {\n return;\n }\n\n const syncNativeClientStateToJs = async () => {\n try {\n if (!isMountedRef.current) {\n return;\n }\n await syncNativeClientToJs({\n clerkInstance,\n nativeRefreshFromJsControllerRef,\n nativeClientEvent,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n });\n } catch (error) {\n console.error(`[ClerkProvider] Failed to sync native client state:`, error);\n }\n };\n\n void syncNativeClientStateToJs();\n }, [\n nativeClientEvent,\n clerkInstance,\n isMountedRef,\n nativeRefreshFromJsControllerRef,\n suppressJsClientChangedRef,\n suppressTokenCacheNotificationsRef,\n tokenCache,\n ]);\n}\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ interface Spec {
|
|
|
2
2
|
addListener?(eventName: string): void;
|
|
3
3
|
configure(publishableKey: string, bearerToken: string | null): Promise<void>;
|
|
4
4
|
getClientToken(): Promise<string | null>;
|
|
5
|
-
syncFromJsClientToken(clientToken: string | null, sourceId: string | null): Promise<void>;
|
|
5
|
+
syncFromJsClientToken(clientToken: string | null, sourceId: string | null, shouldRefreshClient?: boolean): Promise<void>;
|
|
6
6
|
removeListeners?(count: number): void;
|
|
7
7
|
}
|
|
8
8
|
declare const _default: Spec;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeClerkModule.android.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.android.ts"],"names":[],"mappings":"AAEA,UAAU,IAAI;IAGZ,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"NativeClerkModule.android.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.android.ts"],"names":[],"mappings":"AAEA,UAAU,IAAI;IAGZ,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,qBAAqB,CACnB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,eAAe,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC;;AAED,wBAAsD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeClerkModule.android.js","names":[],"sources":["../../src/specs/NativeClerkModule.android.ts"],"sourcesContent":["import { requireNativeModule } from 'expo';\n\ninterface Spec {\n // addListener/removeListeners are present on the iOS RN event emitter module.\n // Android uses Expo Modules EventEmitter instead.\n addListener?(eventName: string): void;\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n syncFromJsClientToken(clientToken: string | null
|
|
1
|
+
{"version":3,"file":"NativeClerkModule.android.js","names":[],"sources":["../../src/specs/NativeClerkModule.android.ts"],"sourcesContent":["import { requireNativeModule } from 'expo';\n\ninterface Spec {\n // addListener/removeListeners are present on the iOS RN event emitter module.\n // Android uses Expo Modules EventEmitter instead.\n addListener?(eventName: string): void;\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n syncFromJsClientToken(\n clientToken: string | null,\n sourceId: string | null,\n shouldRefreshClient?: boolean,\n ): Promise<void>;\n removeListeners?(count: number): void;\n}\n\nexport default requireNativeModule<Spec>('ClerkExpo');\n"],"mappings":";;;AAgBA,sEAAyC,WAAW"}
|
|
@@ -3,7 +3,7 @@ export interface Spec extends TurboModule {
|
|
|
3
3
|
addListener(eventName: string): void;
|
|
4
4
|
configure(publishableKey: string, bearerToken: string | null): Promise<void>;
|
|
5
5
|
getClientToken(): Promise<string | null>;
|
|
6
|
-
syncFromJsClientToken(clientToken: string | null, sourceId: string | null): Promise<void>;
|
|
6
|
+
syncFromJsClientToken(clientToken: string | null, sourceId: string | null, shouldRefreshClient?: boolean): Promise<void>;
|
|
7
7
|
removeListeners(count: number): void;
|
|
8
8
|
}
|
|
9
9
|
declare const _default: Spec | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeClerkModule.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IAGvC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"NativeClerkModule.d.ts","sourceRoot":"","sources":["../../src/specs/NativeClerkModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IAGvC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,qBAAqB,CACnB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAA0D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeClerkModule.js","names":["TurboModuleRegistry"],"sources":["../../src/specs/NativeClerkModule.ts"],"sourcesContent":["import type { TurboModule } from 'react-native';\nimport { TurboModuleRegistry } from 'react-native';\n\nexport interface Spec extends TurboModule {\n // Required by NativeEventEmitter for internal native client change events.\n // This is not part of the public @clerk/expo API.\n addListener(eventName: string): void;\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n syncFromJsClientToken(clientToken: string | null
|
|
1
|
+
{"version":3,"file":"NativeClerkModule.js","names":["TurboModuleRegistry"],"sources":["../../src/specs/NativeClerkModule.ts"],"sourcesContent":["import type { TurboModule } from 'react-native';\nimport { TurboModuleRegistry } from 'react-native';\n\nexport interface Spec extends TurboModule {\n // Required by NativeEventEmitter for internal native client change events.\n // This is not part of the public @clerk/expo API.\n addListener(eventName: string): void;\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n syncFromJsClientToken(\n clientToken: string | null,\n sourceId: string | null,\n shouldRefreshClient?: boolean,\n ): Promise<void>;\n // Required by NativeEventEmitter for internal native client change events.\n // This is not part of the public @clerk/expo API.\n removeListeners(count: number): void;\n}\n\nexport default TurboModuleRegistry.get<Spec>('ClerkExpo');\n"],"mappings":";;;AAmBA,gCAAeA,iCAAoB,IAAU,WAAW"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export declare const isNativeSupported: boolean;
|
|
2
2
|
type ClerkExpoNativeModule = {
|
|
3
|
-
addListener(eventName: string, listener?: (...args: unknown[]) => void): {
|
|
3
|
+
addListener?(eventName: string, listener?: (...args: unknown[]) => void): {
|
|
4
4
|
remove: () => void;
|
|
5
5
|
};
|
|
6
6
|
configure(publishableKey: string, bearerToken: string | null): Promise<void>;
|
|
7
7
|
getClientToken(): Promise<string | null>;
|
|
8
|
-
removeListeners(count: number): void;
|
|
9
|
-
syncFromJsClientToken(clientToken: string | null, sourceId: string | null): Promise<void>;
|
|
8
|
+
removeListeners?(count: number): void;
|
|
9
|
+
syncFromJsClientToken(clientToken: string | null, sourceId: string | null, shouldRefreshClient?: boolean): Promise<void>;
|
|
10
10
|
};
|
|
11
11
|
export declare const ClerkExpoModule: ClerkExpoNativeModule | null;
|
|
12
12
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-module.d.ts","sourceRoot":"","sources":["../../src/utils/native-module.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB,SAAqD,CAAC;AAEpF,KAAK,qBAAqB,GAAG;IAC3B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"native-module.d.ts","sourceRoot":"","sources":["../../src/utils/native-module.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB,SAAqD,CAAC;AAEpF,KAAK,qBAAqB,GAAG;IAC3B,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IACjG,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,eAAe,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,qBAAqB,CACnB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB,CAAC;AAgDF,eAAO,MAAM,eAAe,8BAAqB,CAAC"}
|
|
@@ -9,7 +9,7 @@ const isNativeSupported = react_native.Platform.OS === "ios" || react_native.Pla
|
|
|
9
9
|
function isClerkExpoModule(module) {
|
|
10
10
|
if (!module || typeof module !== "object") return false;
|
|
11
11
|
const maybeModule = module;
|
|
12
|
-
return typeof maybeModule.
|
|
12
|
+
return typeof maybeModule.configure === "function" && typeof maybeModule.getClientToken === "function" && typeof maybeModule.syncFromJsClientToken === "function";
|
|
13
13
|
}
|
|
14
14
|
function loadNativeModule() {
|
|
15
15
|
if (!isNativeSupported) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-module.js","names":["Platform","NativeClerkModule"],"sources":["../../src/utils/native-module.ts"],"sourcesContent":["import { Platform } from 'react-native';\n\nimport NativeClerkModule from '../specs/NativeClerkModule';\n\nexport const isNativeSupported = Platform.OS === 'ios' || Platform.OS === 'android';\n\ntype ClerkExpoNativeModule = {\n addListener(eventName: string, listener?: (...args: unknown[]) => void): { remove: () => void };\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n removeListeners(count: number): void;\n syncFromJsClientToken(clientToken: string | null
|
|
1
|
+
{"version":3,"file":"native-module.js","names":["Platform","NativeClerkModule"],"sources":["../../src/utils/native-module.ts"],"sourcesContent":["import { Platform } from 'react-native';\n\nimport NativeClerkModule from '../specs/NativeClerkModule';\n\nexport const isNativeSupported = Platform.OS === 'ios' || Platform.OS === 'android';\n\ntype ClerkExpoNativeModule = {\n addListener?(eventName: string, listener?: (...args: unknown[]) => void): { remove: () => void };\n configure(publishableKey: string, bearerToken: string | null): Promise<void>;\n getClientToken(): Promise<string | null>;\n removeListeners?(count: number): void;\n syncFromJsClientToken(\n clientToken: string | null,\n sourceId: string | null,\n shouldRefreshClient?: boolean,\n ): Promise<void>;\n};\n\nfunction isClerkExpoModule(module: unknown): module is ClerkExpoNativeModule {\n if (!module || typeof module !== 'object') {\n return false;\n }\n const maybeModule = module as Record<string, unknown>;\n\n return (\n typeof maybeModule.configure === 'function' &&\n typeof maybeModule.getClientToken === 'function' &&\n typeof maybeModule.syncFromJsClientToken === 'function'\n );\n}\n\nfunction loadNativeModule(): ClerkExpoNativeModule | null {\n if (!isNativeSupported) {\n return null;\n }\n let nativeModule: unknown = null;\n\n try {\n nativeModule = NativeClerkModule;\n } catch (e) {\n if (__DEV__) {\n console.warn('[ClerkExpo] Native module not available:', e);\n }\n }\n\n if (isClerkExpoModule(nativeModule)) {\n return nativeModule;\n }\n\n try {\n // Expo SDK 54 can expose installed modules through Expo's module registry even\n // when the generated TurboModule object is incomplete.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { requireNativeModule } = require('expo');\n const expoModule = requireNativeModule('ClerkExpo');\n return isClerkExpoModule(expoModule) ? expoModule : null;\n } catch (e) {\n if (__DEV__ && !nativeModule) {\n console.warn('[ClerkExpo] Native module not available:', e);\n }\n return null;\n }\n}\n\nexport const ClerkExpoModule = loadNativeModule();\n"],"mappings":";;;;;;;AAIA,MAAa,oBAAoBA,sBAAS,OAAO,SAASA,sBAAS,OAAO;AAc1E,SAAS,kBAAkB,QAAkD;CAC3E,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;CAET,MAAM,cAAc;CAEpB,OACE,OAAO,YAAY,cAAc,cACjC,OAAO,YAAY,mBAAmB,cACtC,OAAO,YAAY,0BAA0B;AAEjD;AAEA,SAAS,mBAAiD;CACxD,IAAI,CAAC,mBACH,OAAO;CAET,IAAI,eAAwB;CAE5B,IAAI;EACF,eAAeC;CACjB,SAAS,GAAG,CAIZ;CAEA,IAAI,kBAAkB,YAAY,GAChC,OAAO;CAGT,IAAI;EAIF,MAAM,EAAE,wBAAwB,QAAQ,MAAM;EAC9C,MAAM,aAAa,oBAAoB,WAAW;EAClD,OAAO,kBAAkB,UAAU,IAAI,aAAa;CACtD,SAAS,GAAG;EAIV,OAAO;CACT;AACF;AAEA,MAAa,kBAAkB,iBAAiB"}
|
package/ios/ClerkExpoModule.m
CHANGED
|
@@ -13,6 +13,7 @@ RCT_EXTERN_METHOD(getClientToken:(RCTPromiseResolveBlock)resolve
|
|
|
13
13
|
|
|
14
14
|
RCT_EXTERN_METHOD(syncFromJsClientToken:(id)clientToken
|
|
15
15
|
sourceId:(id)sourceId
|
|
16
|
+
shouldRefreshClient:(id)shouldRefreshClient
|
|
16
17
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
17
18
|
reject:(RCTPromiseRejectBlock)reject)
|
|
18
19
|
|
|
@@ -31,7 +31,7 @@ public protocol ClerkNativeBridgeProtocol {
|
|
|
31
31
|
// SDK operations
|
|
32
32
|
func configure(publishableKey: String, bearerToken: String?) async throws
|
|
33
33
|
func getClientToken() async -> String?
|
|
34
|
-
func syncFromJsClientToken(_ clientToken: String?, sourceId: String
|
|
34
|
+
func syncFromJsClientToken(_ clientToken: String?, sourceId: String?, shouldRefreshClient: Bool) async throws
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public protocol ClerkNativeBridgeReadyObserver: AnyObject {
|
|
@@ -154,6 +154,7 @@ class ClerkExpoModule: RCTEventEmitter {
|
|
|
154
154
|
|
|
155
155
|
@objc func syncFromJsClientToken(_ clientToken: Any?,
|
|
156
156
|
sourceId: Any?,
|
|
157
|
+
shouldRefreshClient: Any?,
|
|
157
158
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
158
159
|
reject: @escaping RCTPromiseRejectBlock) {
|
|
159
160
|
guard let bridge = clerkNativeBridge else {
|
|
@@ -163,9 +164,15 @@ class ClerkExpoModule: RCTEventEmitter {
|
|
|
163
164
|
|
|
164
165
|
let normalizedClientToken = clientToken as? String
|
|
165
166
|
let normalizedSourceId = sourceId as? String
|
|
167
|
+
let defaultShouldRefreshClient = normalizedClientToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true
|
|
168
|
+
let normalizedShouldRefreshClient = (shouldRefreshClient as? Bool) ?? defaultShouldRefreshClient
|
|
166
169
|
Task {
|
|
167
170
|
do {
|
|
168
|
-
try await bridge.syncFromJsClientToken(
|
|
171
|
+
try await bridge.syncFromJsClientToken(
|
|
172
|
+
normalizedClientToken,
|
|
173
|
+
sourceId: normalizedSourceId,
|
|
174
|
+
shouldRefreshClient: normalizedShouldRefreshClient
|
|
175
|
+
)
|
|
169
176
|
resolve(nil)
|
|
170
177
|
} catch {
|
|
171
178
|
reject("E_SYNC_FROM_JS_FAILED", error.localizedDescription, error)
|
|
@@ -59,10 +59,7 @@ public class ClerkGoogleSignInModule: Module {
|
|
|
59
59
|
return
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
let
|
|
63
|
-
let hint: String? = filterByAuthorized
|
|
64
|
-
? GIDSignIn.sharedInstance.currentUser?.profile?.email
|
|
65
|
-
: nil
|
|
62
|
+
let hint = params?["hint"] as? String
|
|
66
63
|
let nonce = params?["nonce"] as? String
|
|
67
64
|
|
|
68
65
|
GIDSignIn.sharedInstance.signIn(
|
|
@@ -21,8 +21,8 @@ private struct ClerkExpoHeaderMiddleware: ClerkRequestMiddleware {
|
|
|
21
21
|
|
|
22
22
|
// MARK: - Native Bridge Implementation
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
25
|
+
static let shared = ClerkNativeBridge()
|
|
26
26
|
|
|
27
27
|
private static let clerkLoadMaxAttempts = 30
|
|
28
28
|
private static let clerkLoadIntervalNs: UInt64 = 100_000_000
|
|
@@ -53,21 +53,21 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Register this app-target bridge with the ClerkExpo module.
|
|
56
|
-
@MainActor
|
|
56
|
+
@MainActor static func register() {
|
|
57
57
|
shared.loadThemes()
|
|
58
58
|
clerkNativeBridge = shared
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
@MainActor
|
|
62
|
-
|
|
62
|
+
func configure(publishableKey: String, bearerToken: String? = nil) async throws {
|
|
63
63
|
if Self.shouldReconfigure(for: publishableKey) {
|
|
64
64
|
try await Clerk.reconfigure(publishableKey: publishableKey, options: Self.makeClerkOptions())
|
|
65
65
|
Self.clerkConfigured = true
|
|
66
66
|
Self.configuredPublishableKey = publishableKey
|
|
67
67
|
startClientObserver(reset: true)
|
|
68
68
|
|
|
69
|
-
let
|
|
70
|
-
await Self.
|
|
69
|
+
let shouldWaitForClient = try await Self.syncTokenState(bearerToken: bearerToken)
|
|
70
|
+
await Self.waitForLoadedClientIfNeeded(shouldWaitForClient)
|
|
71
71
|
Self.emitClientChangedIfReceivedToken(bearerToken)
|
|
72
72
|
emitClerkNativeBridgeReady()
|
|
73
73
|
return
|
|
@@ -75,8 +75,8 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
75
75
|
|
|
76
76
|
if Self.clerkConfigured {
|
|
77
77
|
startClientObserver()
|
|
78
|
-
let
|
|
79
|
-
await Self.
|
|
78
|
+
let shouldWaitForClient = try await Self.syncTokenState(bearerToken: bearerToken)
|
|
79
|
+
await Self.waitForLoadedClientIfNeeded(shouldWaitForClient)
|
|
80
80
|
Self.emitClientChangedIfReceivedToken(bearerToken)
|
|
81
81
|
return
|
|
82
82
|
}
|
|
@@ -86,8 +86,8 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
86
86
|
Clerk.configure(publishableKey: publishableKey, options: Self.makeClerkOptions())
|
|
87
87
|
startClientObserver()
|
|
88
88
|
|
|
89
|
-
let
|
|
90
|
-
await Self.
|
|
89
|
+
let shouldWaitForClient = try await Self.syncTokenState(bearerToken: bearerToken)
|
|
90
|
+
await Self.waitForLoadedClientIfNeeded(shouldWaitForClient)
|
|
91
91
|
Self.emitClientChangedIfReceivedToken(bearerToken)
|
|
92
92
|
emitClerkNativeBridgeReady()
|
|
93
93
|
}
|
|
@@ -175,20 +175,10 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
175
175
|
return .init(keychainConfig: .init(service: service), middleware: middleware)
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
@MainActor
|
|
179
|
-
private static func waitForLoadedSession() async {
|
|
180
|
-
// Wait for Clerk to finish loading (cached data + API refresh).
|
|
181
|
-
// The static configure() fires off async refreshes; poll until loaded.
|
|
182
|
-
for _ in 0..<clerkLoadMaxAttempts {
|
|
183
|
-
if Clerk.shared.isLoaded && Clerk.shared.session != nil && Clerk.shared.user != nil {
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
try? await Task.sleep(nanoseconds: clerkLoadIntervalNs)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
178
|
@MainActor
|
|
191
179
|
private static func waitForLoadedClient() async {
|
|
180
|
+
// Wait for Clerk to finish loading client state from cached data + API refresh.
|
|
181
|
+
// The bridge sync contract is client-token based, not session based.
|
|
192
182
|
for _ in 0..<clerkLoadMaxAttempts {
|
|
193
183
|
if Clerk.shared.isLoaded {
|
|
194
184
|
return
|
|
@@ -198,20 +188,20 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
198
188
|
}
|
|
199
189
|
|
|
200
190
|
@MainActor
|
|
201
|
-
private static func
|
|
191
|
+
private static func waitForLoadedClientIfNeeded(_ shouldWait: Bool) async {
|
|
202
192
|
guard shouldWait else { return }
|
|
203
|
-
await
|
|
193
|
+
await waitForLoadedClient()
|
|
204
194
|
}
|
|
205
195
|
|
|
206
196
|
@MainActor
|
|
207
|
-
|
|
197
|
+
func getClientToken() async -> String? {
|
|
208
198
|
guard Self.clerkConfigured else { return nil }
|
|
209
199
|
return Clerk.shared.deviceToken
|
|
210
200
|
}
|
|
211
201
|
|
|
212
202
|
// MARK: - Inline View Creation
|
|
213
203
|
|
|
214
|
-
|
|
204
|
+
func makeAuthViewController(
|
|
215
205
|
mode: String,
|
|
216
206
|
dismissible: Bool,
|
|
217
207
|
onEvent: @escaping (ClerkNativeViewEvent, [String: Any]) -> Void
|
|
@@ -229,7 +219,7 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
229
219
|
)
|
|
230
220
|
}
|
|
231
221
|
|
|
232
|
-
|
|
222
|
+
func makeUserProfileViewController(
|
|
233
223
|
dismissible: Bool,
|
|
234
224
|
onEvent: @escaping (ClerkNativeViewEvent, [String: Any]) -> Void
|
|
235
225
|
) -> UIViewController? {
|
|
@@ -245,7 +235,7 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
245
235
|
)
|
|
246
236
|
}
|
|
247
237
|
|
|
248
|
-
|
|
238
|
+
func makeUserButtonViewController() -> UIViewController? {
|
|
249
239
|
guard Self.clerkConfigured else { return nil }
|
|
250
240
|
|
|
251
241
|
return makeHostingController(
|
|
@@ -257,13 +247,17 @@ public final class ClerkNativeBridge: ClerkNativeBridgeProtocol {
|
|
|
257
247
|
}
|
|
258
248
|
|
|
259
249
|
@MainActor
|
|
260
|
-
|
|
250
|
+
func syncFromJsClientToken(_ clientToken: String?, sourceId: String?, shouldRefreshClient: Bool) async throws {
|
|
261
251
|
guard Self.clerkConfigured else { return }
|
|
262
252
|
|
|
263
253
|
if let token = clientToken?.trimmingCharacters(in: .whitespacesAndNewlines), !token.isEmpty {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
254
|
+
if Clerk.shared.deviceToken != token {
|
|
255
|
+
_ = try await Clerk.shared.updateDeviceToken(token)
|
|
256
|
+
await Self.waitForLoadedClient()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if shouldRefreshClient {
|
|
267
261
|
_ = try await Clerk.shared.refreshClient()
|
|
268
262
|
await Self.waitForLoadedClient()
|
|
269
263
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clerk/expo",
|
|
3
|
-
"version": "3.4.7
|
|
3
|
+
"version": "3.4.7",
|
|
4
4
|
"description": "Clerk React Native/Expo library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -104,9 +104,9 @@
|
|
|
104
104
|
"base-64": "^1.0.0",
|
|
105
105
|
"react-native-url-polyfill": "2.0.0",
|
|
106
106
|
"tslib": "2.8.1",
|
|
107
|
-
"@clerk/clerk-js": "6.18.1
|
|
108
|
-
"@clerk/react": "6.10.3
|
|
109
|
-
"@clerk/shared": "4.19.1
|
|
107
|
+
"@clerk/clerk-js": "^6.18.1",
|
|
108
|
+
"@clerk/react": "^6.10.3",
|
|
109
|
+
"@clerk/shared": "^4.19.1"
|
|
110
110
|
},
|
|
111
111
|
"devDependencies": {
|
|
112
112
|
"@expo/config-plugins": "^54.0.4",
|
|
@@ -120,10 +120,10 @@
|
|
|
120
120
|
"expo-secure-store": "^12.8.1",
|
|
121
121
|
"expo-web-browser": "^12.8.2",
|
|
122
122
|
"react-native": "^0.85.2",
|
|
123
|
-
"@clerk/expo-passkeys": "1.1.7
|
|
123
|
+
"@clerk/expo-passkeys": "1.1.7"
|
|
124
124
|
},
|
|
125
125
|
"peerDependencies": {
|
|
126
|
-
"@clerk/expo-passkeys": "
|
|
126
|
+
"@clerk/expo-passkeys": ">=0.0.6",
|
|
127
127
|
"expo": ">=53 <57",
|
|
128
128
|
"expo-apple-authentication": ">=7.0.0",
|
|
129
129
|
"expo-auth-session": ">=5",
|
|
@@ -6,7 +6,11 @@ interface Spec {
|
|
|
6
6
|
addListener?(eventName: string): void;
|
|
7
7
|
configure(publishableKey: string, bearerToken: string | null): Promise<void>;
|
|
8
8
|
getClientToken(): Promise<string | null>;
|
|
9
|
-
syncFromJsClientToken(
|
|
9
|
+
syncFromJsClientToken(
|
|
10
|
+
clientToken: string | null,
|
|
11
|
+
sourceId: string | null,
|
|
12
|
+
shouldRefreshClient?: boolean,
|
|
13
|
+
): Promise<void>;
|
|
10
14
|
removeListeners?(count: number): void;
|
|
11
15
|
}
|
|
12
16
|
|
|
@@ -7,7 +7,11 @@ export interface Spec extends TurboModule {
|
|
|
7
7
|
addListener(eventName: string): void;
|
|
8
8
|
configure(publishableKey: string, bearerToken: string | null): Promise<void>;
|
|
9
9
|
getClientToken(): Promise<string | null>;
|
|
10
|
-
syncFromJsClientToken(
|
|
10
|
+
syncFromJsClientToken(
|
|
11
|
+
clientToken: string | null,
|
|
12
|
+
sourceId: string | null,
|
|
13
|
+
shouldRefreshClient?: boolean,
|
|
14
|
+
): Promise<void>;
|
|
11
15
|
// Required by NativeEventEmitter for internal native client change events.
|
|
12
16
|
// This is not part of the public @clerk/expo API.
|
|
13
17
|
removeListeners(count: number): void;
|