diff --git a/.changeset/smart-socks-refuse.md b/.changeset/smart-socks-refuse.md new file mode 100644 index 00000000000..41f86a007af --- /dev/null +++ b/.changeset/smart-socks-refuse.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Refactor after-auth flows to keep navigation internally diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index c2337fff6e8..e823a807a56 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -14,7 +14,7 @@ { "path": "./dist/organizationprofile*.js", "maxSize": "10KB" }, { "path": "./dist/organizationswitcher*.js", "maxSize": "5KB" }, { "path": "./dist/organizationlist*.js", "maxSize": "5.5KB" }, - { "path": "./dist/signin*.js", "maxSize": "14KB" }, + { "path": "./dist/signin*.js", "maxSize": "18KB" }, { "path": "./dist/signup*.js", "maxSize": "8.86KB" }, { "path": "./dist/userbutton*.js", "maxSize": "5KB" }, { "path": "./dist/userprofile*.js", "maxSize": "16KB" }, diff --git a/packages/clerk-js/src/core/__tests__/clerk.test.ts b/packages/clerk-js/src/core/__tests__/clerk.test.ts index d584add1208..1be58ac9236 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.test.ts @@ -2365,7 +2365,7 @@ describe('Clerk singleton', () => { await sut.load(mockedLoadOptions); await sut.setActive({ session: mockResource as any as PendingSessionResource }); - await sut.__experimental_navigateToTask(); + await sut.__internal_navigateToTaskIfAvailable(); expect(mockNavigate.mock.calls[0][0]).toBe('/sign-in#/tasks/add-organization'); }); @@ -2409,7 +2409,7 @@ describe('Clerk singleton', () => { await sut.setActive({ session: mockSession as any as ActiveSessionResource }); const redirectUrlComplete = '/welcome-to-app'; - await sut.__experimental_navigateToTask({ redirectUrlComplete }); + await sut.__internal_navigateToTaskIfAvailable({ redirectUrlComplete }); console.log(mockNavigate.mock.calls); diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index f4cf76950df..ed4b9f15569 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -1317,9 +1317,8 @@ export class Clerk implements ClerkInterface { eventBus.emit(events.TokenUpdate, { token: null }); } - // Only triggers navigation for internal AIO components routing or multi-session switch - const isSwitchingSessions = this.session?.id != session.id; - const shouldNavigateOnSetActive = this.#componentNavigationContext || isSwitchingSessions; + // Only triggers navigation for internal AIO components routing + const shouldNavigateOnSetActive = this.#componentNavigationContext; if (newSession?.currentTask && shouldNavigateOnSetActive) { await navigateToTask(session.currentTask.key, { options: this.#options, @@ -1333,16 +1332,7 @@ export class Clerk implements ClerkInterface { this.#emit(); }; - public __experimental_navigateToTask = async ({ redirectUrlComplete }: NextTaskParams = {}): Promise => { - /** - * Invalidate previously cached pages with auth state before navigating - */ - const onBeforeSetActive: SetActiveHook = - typeof window !== 'undefined' && typeof window.__unstable__onBeforeSetActive === 'function' - ? window.__unstable__onBeforeSetActive - : noop; - await onBeforeSetActive(); - + public __internal_navigateToTaskIfAvailable = async ({ redirectUrlComplete }: NextTaskParams = {}): Promise => { const session = this.session; if (!session || !this.environment) { return; @@ -1368,20 +1358,6 @@ export class Clerk implements ClerkInterface { if (tracker.isUnloading()) { return; } - - this.#setAccessors(session); - this.#emit(); - - /** - * Invoke the Next.js middleware to synchronize server and client state after resolving a session task. - * This ensures that any server-side logic depending on the session status (like middleware-based - * redirects or protected routes) correctly reflects the updated client authentication state. - */ - const onAfterSetActive: SetActiveHook = - typeof window !== 'undefined' && typeof window.__unstable__onAfterSetActive === 'function' - ? window.__unstable__onAfterSetActive - : noop; - await onAfterSetActive(); }; public addListener = (listener: ListenerCallback): UnsubscribeCallback => { diff --git a/packages/clerk-js/src/ui/components/SessionTasks/index.tsx b/packages/clerk-js/src/ui/components/SessionTasks/index.tsx index 2ab37fa68b3..23627b0bfe5 100644 --- a/packages/clerk-js/src/ui/components/SessionTasks/index.tsx +++ b/packages/clerk-js/src/ui/components/SessionTasks/index.tsx @@ -20,7 +20,7 @@ const SessionTasksStart = () => { useEffect(() => { // Simulates additional latency to avoid a abrupt UI transition when navigating to the next task const timeoutId = setTimeout(() => { - void clerk.__experimental_navigateToTask({ redirectUrlComplete }); + void clerk.__internal_navigateToTaskIfAvailable({ redirectUrlComplete }); }, 500); return () => clearTimeout(timeoutId); }, [navigate, clerk, redirectUrlComplete]); @@ -84,7 +84,9 @@ export const SessionTask = withCardStateProvider(() => { const nextTask = useCallback(() => { setIsNavigatingToTask(true); - return clerk.__experimental_navigateToTask({ redirectUrlComplete }).finally(() => setIsNavigatingToTask(false)); + return clerk + .__internal_navigateToTaskIfAvailable({ redirectUrlComplete }) + .finally(() => setIsNavigatingToTask(false)); }, [clerk, redirectUrlComplete]); if (!clerk.session?.currentTask) { diff --git a/packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx b/packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx index fae3e88de1f..5a630c3a4da 100644 --- a/packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx +++ b/packages/clerk-js/src/ui/components/UserButton/useMultisessionActions.tsx @@ -19,7 +19,7 @@ type UseMultisessionActionsParams = { } & Pick; export const useMultisessionActions = (opts: UseMultisessionActionsParams) => { - const { setActive, signOut, openUserProfile } = useClerk(); + const { setActive, signOut, openUserProfile, __internal_navigateToTaskIfAvailable } = useClerk(); const card = useCardState(); const { signedInSessions, otherSessions } = useMultipleSessions({ user: opts.user }); const { navigate } = useRouter(); @@ -69,10 +69,13 @@ export const useMultisessionActions = (opts: UseMultisessionActionsParams) => { const handleSessionClicked = (session: SignedInSessionResource) => async () => { card.setLoading(); - return setActive({ session, redirectUrl: opts.afterSwitchSessionUrl }).finally(() => { - card.setIdle(); - opts.actionCompleteCallback?.(); - }); + + return setActive({ session, redirectUrl: opts.afterSwitchSessionUrl }) + .then(() => __internal_navigateToTaskIfAvailable()) + .finally(() => { + card.setIdle(); + opts.actionCompleteCallback?.(); + }); }; const handleAddAccountClicked = () => { diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 09dd59fa1b2..dbfa9df1234 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -731,9 +731,9 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - __experimental_navigateToTask = async (params?: NextTaskParams): Promise => { + __internal_navigateToTaskIfAvailable = async (params?: NextTaskParams): Promise => { if (this.clerkjs) { - return this.clerkjs.__experimental_navigateToTask(params); + return this.clerkjs.__internal_navigateToTaskIfAvailable(params); } else { return Promise.reject(); } diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 3283aee5b92..e5cd583ff6a 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -818,9 +818,9 @@ export interface Clerk { * Navigates to the next task or redirects to completion URL. * If the current session has pending tasks, it navigates to the next task. * If all tasks are complete, it navigates to the provided completion URL or defaults to the origin redirect URL (either from sign-in or sign-up). - * @experimental + * @internal */ - __experimental_navigateToTask: (params?: NextTaskParams) => Promise; + __internal_navigateToTaskIfAvailable: (params?: NextTaskParams) => Promise; /** * This is an optional function.