@@ -491,8 +491,7 @@ export class Clerk implements ClerkInterface {
491491 * with the new token to the state listeners.
492492 */
493493 eventBus . on ( events . SessionTokenResolved , ( ) => {
494- this . #setAccessors( this . session ) ;
495- this . #emit( ) ;
494+ this . #updateAccessors( this . session ) ;
496495 } ) ;
497496
498497 if ( this . #options. sdkMetadata ) {
@@ -601,8 +600,7 @@ export class Clerk implements ClerkInterface {
601600 return ;
602601 }
603602
604- this . #setAccessors( ) ;
605- this . #emit( ) ;
603+ this . #updateAccessors( ) ;
606604
607605 await onAfterSetActive ( ) ;
608606 } ;
@@ -1449,8 +1447,7 @@ export class Clerk implements ClerkInterface {
14491447 return ;
14501448 }
14511449
1452- this . #setAccessors( newSession ) ;
1453- this . #emit( ) ;
1450+ this . #updateAccessors( newSession ) ;
14541451
14551452 // Do not revalidate server cache for pending sessions to avoid unmount of `SignIn/SignUp` AIOs when navigating to task
14561453 // newSession can be mutated by the time we get here (org change session touch)
@@ -2365,14 +2362,16 @@ export class Clerk implements ClerkInterface {
23652362 const session = this . #options. selectInitialSession
23662363 ? this . #options. selectInitialSession ( newClient )
23672364 : this . #defaultSession( newClient ) ;
2368- this . #setAccessors( session ) ;
2365+
2366+ this . #updateAccessors( session , { dangerouslySkipEmit : true } ) ;
23692367 }
2368+
23702369 this . client = newClient ;
23712370
23722371 if ( this . session ) {
2373- const session = this . #getSessionFromClient( this . session . id ) ;
2372+ const newSession = this . #getSessionFromClient( this . session . id , newClient ) ;
23742373
2375- const hasTransitionedToPendingStatus = this . session . status === 'active' && session ?. status === 'pending' ;
2374+ const hasTransitionedToPendingStatus = this . session . status === 'active' && newSession ?. status === 'pending' ;
23762375 if ( hasTransitionedToPendingStatus ) {
23772376 const onAfterSetActive : SetActiveHook =
23782377 typeof window !== 'undefined' && typeof window . __unstable__onAfterSetActive === 'function'
@@ -2385,7 +2384,10 @@ export class Clerk implements ClerkInterface {
23852384 }
23862385
23872386 // Note: this might set this.session to null
2388- this . #setAccessors( session ) ;
2387+ // We need to set these values before emitting the token update, as handling that relies on these values being set.
2388+ // We don't want to emit here though, as we want to emit the token update first. That happens synchronously, so it
2389+ // should be safe as long as we call #emit() right after.
2390+ this . #updateAccessors( newSession , { dangerouslySkipEmit : true } ) ;
23892391
23902392 // A client response contains its associated sessions, along with a fresh token, so we dispatch a token update event.
23912393 if ( ! this . session ?. lastActiveToken && ! isValidBrowserOnline ( ) ) {
@@ -2835,21 +2837,37 @@ export class Clerk implements ClerkInterface {
28352837 this . #emit( ) ;
28362838 } ;
28372839
2838- #getLastActiveOrganizationFromSession = ( ) => {
2839- const orgMemberships = this . session ?. user . organizationMemberships || [ ] ;
2840- return (
2841- orgMemberships . map ( om => om . organization ) . find ( org => org . id === this . session ?. lastActiveOrganizationId ) || null
2842- ) ;
2840+ #getLastActiveOrganizationFromSession = ( session = this . session ) => {
2841+ const orgMemberships = session ?. user . organizationMemberships || [ ] ;
2842+ return orgMemberships . map ( om => om . organization ) . find ( org => org . id === session ?. lastActiveOrganizationId ) || null ;
2843+ } ;
2844+
2845+ #getAccessorsFromSession = ( session = this . session ) => {
2846+ return {
2847+ session : session || null ,
2848+ organization : this . #getLastActiveOrganizationFromSession( session ) ,
2849+ user : session ? session . user : null ,
2850+ } ;
28432851 } ;
28442852
2845- #setAccessors = ( session ?: SignedInSessionResource | null ) => {
2846- this . session = session || null ;
2847- this . organization = this . #getLastActiveOrganizationFromSession( ) ;
2848- this . user = this . session ? this . session . user : null ;
2853+ /**
2854+ * Updates the accessors for the Clerk singleton and emits.
2855+ * If dangerouslySkipEmit is true, the emit will be skipped and you are responsible for calling #emit() yourself. This is dangerous because if there is a gap between setting these and emitting, library consumers that both read state directly and set up listeners could end up in a inconsistent state.
2856+ */
2857+ #updateAccessors = ( session ?: SignedInSessionResource | null , options ?: { dangerouslySkipEmit ?: boolean } ) => {
2858+ const { session : newSession , organization, user } = this . #getAccessorsFromSession( session ) ;
2859+
2860+ this . session = newSession ;
2861+ this . organization = organization ;
2862+ this . user = user ;
2863+
2864+ if ( ! options ?. dangerouslySkipEmit ) {
2865+ this . #emit( ) ;
2866+ }
28492867 } ;
28502868
2851- #getSessionFromClient = ( sessionId : string | undefined ) : SignedInSessionResource | null => {
2852- return this . client ?. signedInSessions . find ( x => x . id === sessionId ) || null ;
2869+ #getSessionFromClient = ( sessionId : string | undefined , client = this . client ) : SignedInSessionResource | null => {
2870+ return client ?. signedInSessions . find ( x => x . id === sessionId ) || null ;
28532871 } ;
28542872
28552873 #handleImpersonationFab = ( ) => {
0 commit comments