diff --git a/.changeset/sharp-trains-ring.md b/.changeset/sharp-trains-ring.md new file mode 100644 index 0000000000..832311930e --- /dev/null +++ b/.changeset/sharp-trains-ring.md @@ -0,0 +1,6 @@ +--- +'@clerk/clerk-js': minor +'@clerk/types': minor +--- + +Add `routerDebug` option in `Clerk.load()` to log the destination URLs when navigating diff --git a/packages/clerk-js/src/core/clerk.test.ts b/packages/clerk-js/src/core/clerk.test.ts index 832ef69c00..7bf3a01634 100644 --- a/packages/clerk-js/src/core/clerk.test.ts +++ b/packages/clerk-js/src/core/clerk.test.ts @@ -516,16 +516,23 @@ describe('Clerk singleton', () => { describe('.navigate(to)', () => { let sut: Clerk; + let logSpy; beforeEach(() => { + logSpy = jest.spyOn(console, 'log'); sut = new Clerk(productionPublishableKey); }); + afterEach(() => { + logSpy?.mockRestore(); + }); + it('uses window location if a custom navigate is not defined', async () => { await sut.load(); const toUrl = 'http://test.host/'; await sut.navigate(toUrl); expect(mockHref).toHaveBeenCalledWith(toUrl); + expect(logSpy).not.toBeCalled(); }); it('uses window location if a custom navigate is defined but destination has different origin', async () => { @@ -533,6 +540,7 @@ describe('Clerk singleton', () => { const toUrl = 'https://www.origindifferent.com/'; await sut.navigate(toUrl); expect(mockHref).toHaveBeenCalledWith(toUrl); + expect(logSpy).not.toBeCalled(); }); it('wraps custom navigate method in a promise if provided and it sync', async () => { @@ -542,6 +550,29 @@ describe('Clerk singleton', () => { expect(res.then).toBeDefined(); expect(mockHref).not.toHaveBeenCalled(); expect(mockNavigate).toHaveBeenCalledWith('/path#hash'); + expect(logSpy).not.toBeCalled(); + }); + + it('logs navigation external navigation when routerDebug is enabled', async () => { + await sut.load({ routerDebug: true }); + const toUrl = 'http://test.host/'; + await sut.navigate(toUrl); + expect(mockHref).toHaveBeenCalledWith(toUrl); + + expect(logSpy).toBeCalledTimes(1); + expect(logSpy).toBeCalledWith(`Clerk is navigating to: ${toUrl}`); + }); + + it('logs navigation custom navigation when routerDebug is enabled', async () => { + await sut.load({ routerPush: mockNavigate, routerDebug: true }); + const toUrl = 'http://test.host/path#hash'; + const res = sut.navigate(toUrl); + expect(res.then).toBeDefined(); + expect(mockHref).not.toHaveBeenCalled(); + expect(mockNavigate).toHaveBeenCalledWith('/path#hash'); + + expect(logSpy).toBeCalledTimes(1); + expect(logSpy).toBeCalledWith(`Clerk is navigating to: ${toUrl}`); }); }); diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index d75ef10043..68f4cb3eba 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -165,8 +165,7 @@ export class Clerk implements ClerkInterface { #environment?: EnvironmentResource | null; //@ts-expect-error with being undefined even though it's not possible - related to issue with ts and error thrower #fapiClient: FapiClient; - //@ts-expect-error with undefined even though it's not possible - related to issue with ts and error thrower - #instanceType: InstanceType; + #instanceType?: InstanceType; #isReady = false; #listeners: Array<(emission: Resources) => void> = []; @@ -675,6 +674,10 @@ export class Clerk implements ClerkInterface { const customNavigate = options?.replace && this.#options.routerReplace ? this.#options.routerReplace : this.#options.routerPush; + if (this.#options.routerDebug) { + console.log(`Clerk is navigating to: ${toURL}`); + } + if (toURL.origin !== window.location.origin || !customNavigate) { windowNavigate(toURL); return; diff --git a/packages/types/src/clerk.retheme.ts b/packages/types/src/clerk.retheme.ts index 6cd8dea7cf..166d5fdb4a 100644 --- a/packages/types/src/clerk.retheme.ts +++ b/packages/types/src/clerk.retheme.ts @@ -496,8 +496,6 @@ export type BuildUrlWithAuthParams = { useQueryParam?: boolean | null; }; -// TODO: Make sure Isomorphic Clerk navigate can work with the correct type: -// (to: string) => Promise export type CustomNavigation = (to: string, options?: NavigateOptions) => Promise | void; export type ClerkThemeOptions = DeepSnakeToCamel>; @@ -505,8 +503,12 @@ export type ClerkThemeOptions = DeepSnakeToCamel>; export interface ClerkOptions { appearance?: Appearance; localization?: LocalizationResource; + /** + * Navigation + */ routerPush?: (to: string) => Promise | unknown; routerReplace?: (to: string) => Promise | unknown; + routerDebug?: boolean; polling?: boolean; selectInitialSession?: (client: ClientResource) => ActiveSessionResource | null; /** Controls if ClerkJS will load with the standard browser setup using Clerk cookies */ diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 578d387d8e..c38968c9d0 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -496,8 +496,6 @@ export type BuildUrlWithAuthParams = { useQueryParam?: boolean | null; }; -// TODO: Make sure Isomorphic Clerk navigate can work with the correct type: -// (to: string) => Promise export type CustomNavigation = (to: string, options?: NavigateOptions) => Promise | void; export type ClerkThemeOptions = DeepSnakeToCamel>; @@ -505,8 +503,13 @@ export type ClerkThemeOptions = DeepSnakeToCamel>; export interface ClerkOptions { appearance?: Appearance; localization?: LocalizationResource; + /** + * Navigation + */ routerPush?: (to: string) => Promise | unknown; routerReplace?: (to: string) => Promise | unknown; + routerDebug?: boolean; + polling?: boolean; selectInitialSession?: (client: ClientResource) => ActiveSessionResource | null; /** Controls if ClerkJS will load with the standard browser setup using Clerk cookies */