diff --git a/.changeset/sixty-bikes-visit.md b/.changeset/sixty-bikes-visit.md new file mode 100644 index 0000000000..49586676fc --- /dev/null +++ b/.changeset/sixty-bikes-visit.md @@ -0,0 +1,7 @@ +--- +"@clerk/clerk-js": minor +"@clerk/astro": minor +"@clerk/types": minor +--- + +Inject `windowNavigate` through router functions. diff --git a/packages/astro/src/internal/create-clerk-instance.ts b/packages/astro/src/internal/create-clerk-instance.ts index 8d56018fa0..dd72be8d92 100644 --- a/packages/astro/src/internal/create-clerk-instance.ts +++ b/packages/astro/src/internal/create-clerk-instance.ts @@ -9,31 +9,22 @@ import { runOnce } from './run-once'; let initOptions: ClerkOptions | undefined; -// TODO-SHARED: copied from `clerk-js` -export const CLERK_BEFORE_UNLOAD_EVENT = 'clerk:beforeunload'; - setClerkJsLoadingErrorPackageName(PACKAGE_NAME); -function windowNavigate(to: URL | string): void { - const toURL = new URL(to, window.location.href); - window.dispatchEvent(new CustomEvent(CLERK_BEFORE_UNLOAD_EVENT)); - window.location.href = toURL.href; -} - function createNavigationHandler( windowNav: typeof window.history.pushState | typeof window.history.replaceState, ): Exclude | Exclude { - return (to, metadata) => { - if (metadata?.__internal_metadata?.navigationType === 'internal') { + return (to, opts) => { + if (opts?.__internal_metadata?.navigationType === 'internal') { windowNav(history.state, '', to); } else { - windowNavigate(to); + opts?.windowNavigate(to); } }; } /** - * Prevents firing clerk.load multiple times + * Prevents firing clerk.load() multiple times */ const createClerkInstance = runOnce(createClerkInstanceInternal); diff --git a/packages/clerk-js/src/core/__tests__/clerk.redirects.test.ts b/packages/clerk-js/src/core/__tests__/clerk.redirects.test.ts index 0f6dad0113..3d8bd18413 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.redirects.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.redirects.test.ts @@ -124,34 +124,30 @@ describe('Clerk singleton - Redirects', () => { it('redirects to signInUrl for development instance', async () => { await clerkForDevelopmentInstance.redirectToSignIn({ redirectUrl: '/example' }); - expect(mockNavigate).toHaveBeenCalledWith( - '/sign-in#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', - undefined, - ); + expect(mockNavigate).toHaveBeenCalledWith('/sign-in#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', { + windowNavigate: expect.any(Function), + }); }); it('redirects to signInUrl for production instance', async () => { await clerkForProductionInstance.redirectToSignIn({ redirectUrl: '/example' }); - expect(mockNavigate).toHaveBeenCalledWith( - '/sign-in#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', - undefined, - ); + expect(mockNavigate).toHaveBeenCalledWith('/sign-in#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', { + windowNavigate: expect.any(Function), + }); }); it('redirects to signUpUrl for development instance', async () => { await clerkForDevelopmentInstance.redirectToSignUp({ redirectUrl: '/example' }); - expect(mockNavigate).toHaveBeenCalledWith( - '/sign-up#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', - undefined, - ); + expect(mockNavigate).toHaveBeenCalledWith('/sign-up#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', { + windowNavigate: expect.any(Function), + }); }); it('redirects to signUpUrl for production instance', async () => { await clerkForProductionInstance.redirectToSignUp({ redirectUrl: '/example' }); - expect(mockNavigate).toHaveBeenCalledWith( - '/sign-up#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', - undefined, - ); + expect(mockNavigate).toHaveBeenCalledWith('/sign-up#/?redirect_url=http%3A%2F%2Ftest.host%2Fexample', { + windowNavigate: expect.any(Function), + }); }); it('redirects to userProfileUrl', async () => { diff --git a/packages/clerk-js/src/core/__tests__/clerk.test.ts b/packages/clerk-js/src/core/__tests__/clerk.test.ts index 442f8d73bc..fd6777fdba 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.test.ts @@ -784,7 +784,9 @@ describe('Clerk singleton', () => { await waitFor(() => { expect(mockSignUpCreate).not.toHaveBeenCalledWith({ transfer: true }); expect(mockSetActive).not.toHaveBeenCalled(); - expect(mockNavigate).toHaveBeenCalledWith('/sign-in', undefined); + expect(mockNavigate).toHaveBeenCalledWith('/sign-in', { + windowNavigate: expect.any(Function), + }); }); }); diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index ac4b6a44a5..0597b2420c 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -828,7 +828,10 @@ export class Clerk implements ClerkInterface { return; } - const metadata = options?.metadata ? { __internal_metadata: options?.metadata } : undefined; + const metadata = { + ...(options?.metadata ? { __internal_metadata: options?.metadata } : {}), + windowNavigate, + }; // React router only wants the path, search or hash portion. return await customNavigate(stripOrigin(toURL), metadata); }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index b7478735c7..2b03f2b673 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -641,7 +641,10 @@ type NavigationType = type RouterMetadata = { routing?: RoutingStrategy; navigationType?: NavigationType }; -type RouterFn = (to: string, metadata?: { __internal_metadata?: RouterMetadata }) => Promise | unknown; +type RouterFn = ( + to: string, + metadata?: { __internal_metadata?: RouterMetadata; windowNavigate: (to: URL | string) => void }, +) => Promise | unknown; export type WithoutRouting = Omit;