Skip to content

Commit

Permalink
Introduce new base skeleton for URL resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
LauraBeatris committed Feb 25, 2025
1 parent e15d124 commit a6cfc60
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 20 deletions.
4 changes: 2 additions & 2 deletions integration/tests/session-tasks.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { appConfigs } from '../presets';
import { testAgainstRunningApps } from '../testUtils';

// TODO ORGS-566 - write integration tests for after-auth flow
// TODO ORGS-566 - Write integration tests for after-auth flow
testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('after-auth flows @generic @nextjs', () => {
describe('after sign-in', () => {
// /sign-in -> /sign-in/select-organization
Expand All @@ -25,7 +25,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('after-aut
it.todo('on single-session mode, sign-up redirects back to tasks when accessed with a pending session');
});

describe('middle app', () => {
describe('when user is using the app and session transitions to active to pending', () => {
// /my-dashboard/recipes -> /sign-in/select-organization
it.todo('on session transition to pending with tasks, redirects to tasks');

Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/src/core/__tests__/clerk.redirects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ describe('Clerk singleton - Redirects', () => {

describe('.redirectToTasks', () => {
describe('after sign-in with pending session', () => {
it.todo('redirects to tasks URL with after sign-in URL appended as query param');
it('redirects to tasks URL with after sign-in URL appended as query param');
});

describe('after sign-up with pending session', () => {
Expand All @@ -325,7 +325,7 @@ describe('Clerk singleton - Redirects', () => {
it.todo('redirects to tasks URL with after sign-up URL appended as query param');
});

describe('user already exists and session transitions from active to pending on middle app', () => {
describe('from a protected route', () => {
it.todo('redirects to tasks URL with app origin appended as query param');
});
});
Expand Down
64 changes: 52 additions & 12 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1007,8 +1007,6 @@ export class Clerk implements ClerkInterface {
return;
}

console.log('Clerk.navigate is navigating to', { to });

/**
* Trigger all navigation listeners. In order for modal UI components to close.
*/
Expand Down Expand Up @@ -1042,6 +1040,7 @@ export class Clerk implements ClerkInterface {
...(options?.metadata ? { __internal_metadata: options?.metadata } : {}),
windowNavigate,
};

// React router only wants the path, search or hash portion.
return await customNavigate(stripOrigin(toURL), metadata);
};
Expand Down Expand Up @@ -1120,13 +1119,55 @@ export class Clerk implements ClerkInterface {
}

public buildTasksUrl(): string {
const signInUrl = this.#options.signInUrl || this.environment?.displayConfig.signInUrl;
const signUpUrl = this.#options.signUpUrl || this.environment?.displayConfig.signUpUrl;
const currentTask = this.session?.currentTask;

if (!currentTask) {
return '';
}

return buildURL({ hashPath: sessionTaskKeyToRoutePaths[currentTask.key] }, { stringify: true });
let redirectUrl = '';
const referrerIsSignInUrl = signInUrl && window.location.href.includes(signInUrl);
const referrerIsSignUpUrl = signUpUrl && window.location.href.includes(signUpUrl);

if (referrerIsSignInUrl) {
redirectUrl = this.buildAfterSignInUrl();
} else if (referrerIsSignUpUrl) {
redirectUrl = this.buildAfterSignUpUrl();
} else {
/**
* User already has a active session and gets transition to a pending status
* on the client update
*
* It could happen on instance configuration changes that lead to new tasks that
* need to get resolved by the user, eg: Force MFA
*/
// Preserves the origin path, eg: /my-app/recipes -> /sign-in/select-organization -> /my-app/recipes
redirectUrl = window.location.href;
}

/**
* For after sign-in or after sign-up, it's agnostic to the original base path
* in order to avoid having to check for the referrer
*
* If it's coming from a protected route where the user already exists, then
* the base path becomes the sign in URL
*/
const shouldAppendBasePath = !referrerIsSignInUrl && !referrerIsSignUpUrl;

console.log({ shouldAppendBasePath, referrerIsSignInUrl, referrerIsSignUpUrl });

return buildURL(
{
...(shouldAppendBasePath ? { base: signInUrl } : {}),
hashPath: sessionTaskKeyToRoutePaths[currentTask.key],
hashSearchParams: {
redirect_url: redirectUrl,
},
},
{ stringify: true },
);
}

public buildAfterMultiSessionSingleSignOutUrl(): string {
Expand Down Expand Up @@ -1252,6 +1293,7 @@ export class Clerk implements ClerkInterface {

public redirectToTasks = async (): Promise<unknown> => {
if (inBrowser()) {
console.log('navigate to tasks');
return this.navigate(this.buildTasksUrl());
}
return;
Expand Down Expand Up @@ -1750,10 +1792,6 @@ export class Clerk implements ClerkInterface {
if (this.session) {
const session = this.#getSessionFromClient(this.session.id);

// TODO - Resolve after-task redirection
// TODO - Resolve issue on closing modals on navigation within Clerk.navigate
// sign-in/select-organization -> /home
// sign-in -> sign-in/select-organization
const hasResolvedPreviousTask = this.session.currentTask != session?.currentTask;

// Note: this might set this.session to null
Expand All @@ -1762,15 +1800,15 @@ export class Clerk implements ClerkInterface {
// A client response contains its associated sessions, along with a fresh token, so we dispatch a token update event.
eventBus.dispatch(events.TokenUpdate, { token: this.session?.lastActiveToken });

this.#emit();

// Tasks handling must be reactive on client piggybacking to support
// immediate instance-level configuration changes by app owners
if (session?.currentTask) {
eventBus.dispatch(events.NewSessionTask, session);
} else if (session && hasResolvedPreviousTask) {
eventBus.dispatch(events.ResolvedSessionTask, session);
}

this.#emit();
}
};

Expand Down Expand Up @@ -2114,13 +2152,15 @@ export class Clerk implements ClerkInterface {
});

eventBus.on(events.NewSessionTask, () => {
console.log('new session task');
void this.redirectToTasks();
});

eventBus.on(events.ResolvedSessionTask, () => {
console.log('resolved task');
void this.redirectToAfterSignIn();
// `redirect_url` gets appended based on the origin (after sign-in vs after sign-up),
// if it gets accidentally deleted, then fallbacks to the sign in URL
const redirectUrl = new URLSearchParams(window.location.search).get('redirect_url') ?? this.buildSignInUrl();
console.log({ redirectUrl }, 'Resolving session task 🍪');
void this.navigate(redirectUrl);
});
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import { handleError } from '../../utils';
import { completeSignUpFlow } from './util';

export const SignUpEmailLinkCard = () => {
console.log('rendering');

const { t } = useLocalizations();
const signUp = useCoreSignUp();
const signUpContext = useSignUpContext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { SignUpEmailCodeCard } from './SignUpEmailCodeCard';
import { SignUpEmailLinkCard } from './SignUpEmailLinkCard';

export const SignUpVerifyEmail = withCardStateProvider(() => {
console.log('rendering');

const { userSettings } = useEnvironment();
const { attributes } = userSettings;
const emailLinkStrategyEnabled = attributes.email_address.verifications.includes('email_link');
Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/src/ui/router/BaseRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const BaseRouter = ({

const isCrossOrigin = toURL.origin !== window.location.origin;
const isOutsideOfUIComponent = !toURL.pathname.startsWith('/' + basePath);
console.log({ isCrossOrigin, isOutsideOfUIComponent });

if (isOutsideOfUIComponent || isCrossOrigin) {
const res = await clerkNavigate(toURL.href);
Expand Down

0 comments on commit a6cfc60

Please sign in to comment.