Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(clerk-js): Introduce `navigate` for `setActive` by LauraBeatris · Pull Request #6486 · clerk/javascript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ddff9e4
Remove `__internal_navigateToTaskIfAvailable`
LauraBeatris Aug 7, 2025
a4892f2
Introduce `onPendingSession` and remove `#componentNavigationContext`
LauraBeatris Aug 7, 2025
4a23f61
Remove redirect to task within `withRedirect` guard
LauraBeatris Aug 7, 2025
2500054
Navigate to tasks from sign up context
LauraBeatris Aug 7, 2025
5d39a6c
Remove `NavigateToTask` control component
LauraBeatris Aug 7, 2025
72108b2
Add redirect guards for root sign-in / sign-up AIOs
LauraBeatris Aug 8, 2025
4a09b4d
Use `taskUrl` from AIOs navigation
LauraBeatris Aug 8, 2025
3e54a20
Validate task options on Clerk init
LauraBeatris Aug 8, 2025
c87cca9
Adjust unit tests with newest API
LauraBeatris Aug 8, 2025
15baab2
Remove `#handlePendingSession` branch and introduce `navigate` option
nikosdouvlis Aug 8, 2025
fb0b6f0
Replace `onPendingSession` with `navigate`
LauraBeatris Aug 8, 2025
dd5a3c5
Add unit tests for invalidation hooks
LauraBeatris Aug 8, 2025
250ded9
Fix display name of redirect guards
LauraBeatris Aug 8, 2025
3d4a2e4
Rename `navigateToTask` from `navigateIfTaskExists`
LauraBeatris Aug 8, 2025
af7a4c7
Add warning for missing params for task handling
LauraBeatris Aug 8, 2025
e189667
Fix navigation between sign-in/sign-up steps
LauraBeatris Aug 8, 2025
7486db5
Preserve `redirectUrl` on `taskUrl` for after sign-in/sign-up
LauraBeatris Aug 8, 2025
6184aab
Add changesets
LauraBeatris Aug 8, 2025
6feb7ea
Navigate to next task if any from AIOs
LauraBeatris Aug 8, 2025
83a60c9
Fix `warnMissingPendingTaskHandlers` call
LauraBeatris Aug 8, 2025
968a327
Add `@inline` to `SetActiveNavigate` type
LauraBeatris Aug 8, 2025
9bde4ec
Fix navigation on active sessions
LauraBeatris Aug 8, 2025
0279ddc
Fix mocking of `signedInSessions`
LauraBeatris Aug 8, 2025
9c42234
Update custom flow snippet from changeset
LauraBeatris Aug 8, 2025
8dfc782
Fix typedoc tests
LauraBeatris Aug 8, 2025
735fb72
Fix navigation for multi-session
LauraBeatris Aug 8, 2025
921f611
Use `navigate` for `setActive` on combined flow
LauraBeatris Aug 9, 2025
c0d8c27
Rename `RedirectToTask` control component to `RedirectToTasks`
LauraBeatris Aug 9, 2025
cf7f966
Fix E2E test for sign-up with tasks
LauraBeatris Aug 9, 2025
cb553fe
Display root sign-in for multi-session mode with tasks
LauraBeatris Aug 9, 2025
7e590ff
Fix navigating to tasks on SSO callback
LauraBeatris Aug 9, 2025
5356efe
Bump max size of `clerk.headless` bundle
LauraBeatris Aug 9, 2025
17e01a4
Remove condition to always send `redirect_url` for SSO with after-aut…
LauraBeatris Aug 11, 2025
4142162
Remove duplicated changeset
LauraBeatris Aug 11, 2025
2171310
Remove `SessionTasksContext` from `TaskChooseOrganization`
LauraBeatris Aug 11, 2025
a9ec4dd
Fix `redirectUrl` for SSO with SignIn
LauraBeatris Aug 11, 2025
8626d49
Run `onAfterSetActive` if the new session is `active`
LauraBeatris Aug 11, 2025
e1e3628
Always use the latest session for status checks
nikosdouvlis Aug 11, 2025
508f7e0
Fix early returns in setActive
nikosdouvlis Aug 11, 2025
e800a1d
Fix session status check within `setActive`
LauraBeatris Aug 12, 2025
f492e9a
Maintain base URL of sign-in/sign-up for routing
LauraBeatris Aug 12, 2025
5ad3f51
Fix navigation for SSO to maintain path and hash routing
LauraBeatris Aug 12, 2025
a85cecd
Fix `RedirectToTasks` to only redirect to tasks
LauraBeatris Aug 13, 2025
1921845
Fix navigation for combined flow
LauraBeatris Aug 13, 2025
2de7d6e
Fix changeset
LauraBeatris Aug 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/rich-donuts-agree.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Add `navigate` parameter to `clerk.setActive()` for custom navigation before the session and/or organization is set.

It's useful for handling pending session tasks for after-auth flows:

```typescript
await clerk.setActive({
session,
navigate: async ({ session }) => {
const currentTask = session.currentTask;
if (currentTask) {
await router.push(`/onboarding/${currentTask.key}`)
return;
}

await router.push('/dashboard')
}
});
```
10 changes: 10 additions & 0 deletions .changeset/warm-rocks-flow.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
---
'@clerk/tanstack-react-start': minor
'@clerk/react-router': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
'@clerk/remix': minor
'@clerk/vue': minor
---

Rename `RedirectToTask` control component to `RedirectToTasks`
2 changes: 1 addition & 1 deletion integration/tests/session-tasks-sign-in.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,7 +83,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
32 changes: 25 additions & 7 deletions integration/tests/session-tasks-sign-up.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
import { createClerkClient } from '@clerk/backend';
import { expect, test } from '@playwright/test';

import { appConfigs } from '../presets';
import { instanceKeys } from '../presets/envs';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';
import { createUserService } from '../testUtils/usersService';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
'session tasks after sign-up flow @nextjs',
({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;
let regularFakeUser: FakeUser;
let fakeUserForOAuth: FakeUser;

test.beforeEach(() => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser({
regularFakeUser = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
});
fakeUserForOAuth = u.services.users.createFakeUser({
fictionalEmail: true,
withPhoneNumber: true,
withUsername: true,
Expand All@@ -23,7 +32,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
test.afterAll(async () => {
const u = createTestUtils({ app });
await u.services.organizations.deleteAll();
await fakeUser.deleteIfExists();
await regularFakeUser.deleteIfExists();

// Delete user from OAuth provider instance
const client = createClerkClient({
secretKey: instanceKeys.get('oauth-provider').sk,
publishableKey: instanceKeys.get('oauth-provider').pk,
});
const users = createUserService(client);
await users.deleteIfExists({ email: fakeUserForOAuth.email });

await app.teardown();
});

Expand All@@ -38,8 +56,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
const u = createTestUtils({ app, page, context });
await u.po.signUp.goTo();
await u.po.signUp.signUpWithEmailAndPassword({
email: fakeUser.email,
password: fakeUser.password,
email: regularFakeUser.email,
password: regularFakeUser.password,
});
await u.po.expect.toBeSignedIn();

Expand DownExpand Up@@ -68,12 +86,12 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSessionTasks] })(
await u.po.signIn.getGoToSignUp().click();

await u.po.signUp.waitForMounted();
await u.po.signUp.setEmailAddress(fakeUser.email);
await u.po.signUp.setEmailAddress(fakeUserForOAuth.email);
await u.po.signUp.continue();
await u.po.signUp.enterTestOtpCode();

// Resolves task
await u.po.signIn.waitForMounted();
await u.po.signUp.waitForMounted();
Comment thread
LauraBeatris marked this conversation as resolved.
const fakeOrganization = Object.assign(u.services.organizations.createFakeOrganization(), {
slug: u.services.organizations.createFakeOrganization().slug + '-with-sign-in-sso',
});
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "622.25KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "76KB" },
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "58KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
Expand Down
Loading
Loading