Skip to content

Commit b5dbb58

Browse files
authored
Merge branch 'release/core-2' into ss/add-types-waitlist-entry
2 parents be7b175 + 5740640 commit b5dbb58

7 files changed

Lines changed: 47 additions & 62 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Disable ConsoleTransport for debug logger by default
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Fix infinite loading spinner when navigating to factor-two sign-in route without an active 2FA session

.changeset/legal-crabs-shout.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/clerk-js': minor
3+
'@clerk/backend': minor
4+
---
5+
6+
Add `providerUserId` field to `ExternalAccount` resource as the preferred way to access the unique user ID from the OAuth provider. The existing `externalId` field is now deprecated in favor of `providerUserId` for better clarity and consistency across the API.

packages/backend/src/api/resources/ExternalAccount.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@ export class ExternalAccount {
1616
* The provider name (e.g., `google`).
1717
*/
1818
readonly provider: string,
19+
/**
20+
* The unique ID of the user in the provider.
21+
*/
22+
readonly providerUserId: string,
1923
/**
2024
* The identification with which this external account is associated.
2125
*/
2226
readonly identificationId: string,
2327
/**
2428
* The unique ID of the user in the provider.
29+
* @deprecated Use providerUserId instead
2530
*/
2631
readonly externalId: string,
2732
/**
@@ -70,6 +75,7 @@ export class ExternalAccount {
7075
return new ExternalAccount(
7176
data.id,
7277
data.provider,
78+
data.provider_user_id,
7379
data.identification_id,
7480
data.provider_user_id,
7581
data.approved_scopes,
Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,10 @@
11
import type { DebugLogEntry, DebugTransport } from '../types';
22

3-
/**
4-
* ANSI color codes for console output
5-
*/
6-
const COLORS = {
7-
blue: '\x1b[34m',
8-
bright: '\x1b[1m',
9-
cyan: '\x1b[36m',
10-
dim: '\x1b[2m',
11-
gray: '\x1b[90m',
12-
green: '\x1b[32m',
13-
magenta: '\x1b[35m',
14-
red: '\x1b[31m',
15-
reset: '\x1b[0m',
16-
white: '\x1b[37m',
17-
yellow: '\x1b[33m',
18-
} as const;
19-
20-
/**
21-
* Color mapping for different log levels
22-
*/
23-
const LEVEL_COLORS = {
24-
debug: COLORS.green,
25-
error: COLORS.red,
26-
info: COLORS.blue,
27-
warn: COLORS.yellow,
28-
} as const;
29-
303
/**
314
* A transport that writes debug logs to the host environment's console
32-
* (e.g. browser devtools or Node.js stdout) with ANSI color accents.
5+
* (e.g. browser devtools or Node.js stdout).
6+
*
7+
* Currently disabled by default (noop).
338
*
349
* @public
3510
*/
@@ -40,40 +15,7 @@ export class ConsoleTransport implements DebugTransport {
4015
*
4116
* @param entry - The debug log entry to print
4217
*/
43-
send(entry: DebugLogEntry): Promise<void> {
44-
const timestamp = new Date(entry.timestamp).toISOString();
45-
const level = entry.level.toUpperCase();
46-
const source = entry.source ? `[${entry.source}]` : '';
47-
const context = entry.context ? ` ${JSON.stringify(entry.context)}` : '';
48-
49-
const levelColor = LEVEL_COLORS[entry.level] || COLORS.white;
50-
51-
const prefix = `${COLORS.bright}${COLORS.cyan}[Clerk Debug]${COLORS.reset}`;
52-
const timestampColored = `${COLORS.dim}${timestamp}${COLORS.reset}`;
53-
const levelColored = `${levelColor}${level}${COLORS.reset}`;
54-
const sourceColored = source ? `${COLORS.gray}${source}${COLORS.reset}` : '';
55-
const messageColored = `${COLORS.white}${entry.message}${COLORS.reset}`;
56-
const contextColored = context ? `${COLORS.dim}${context}${COLORS.reset}` : '';
57-
58-
const message = `${prefix} ${timestampColored} ${levelColored}${sourceColored}: ${messageColored}${contextColored}`;
59-
60-
switch (entry.level) {
61-
case 'error':
62-
console.error(message);
63-
break;
64-
case 'warn':
65-
console.warn(message);
66-
break;
67-
case 'info':
68-
console.info(message);
69-
break;
70-
case 'debug':
71-
console.debug(message);
72-
break;
73-
default:
74-
console.log(message);
75-
}
76-
18+
send(_entry: DebugLogEntry): Promise<void> {
7719
return Promise.resolve();
7820
}
7921
}

packages/clerk-js/src/core/resources/__tests__/ExternalAccount.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ describe('External account', () => {
99
const externalAccountJSON = {
1010
object: 'external_account',
1111
id: targetId,
12+
provider_user_id: 'test_provider_user_id',
13+
identification_id: 'test_identification_id',
1214
};
1315

1416
// @ts-ignore
@@ -35,6 +37,8 @@ describe('External account', () => {
3537
object: 'external_account',
3638
id: targetId,
3739
deleted: true,
40+
provider_user_id: 'test_provider_user_id',
41+
identification_id: 'test_identification_id',
3842
};
3943

4044
// @ts-ignore

packages/clerk-js/src/ui/components/SignIn/SignInFactorTwo.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useClerk } from '@clerk/shared/react';
12
import type { SignInFactor } from '@clerk/shared/types';
23
import React from 'react';
34

@@ -6,6 +7,7 @@ import { LoadingCard } from '@/ui/elements/LoadingCard';
67

78
import { withRedirectToAfterSignIn, withRedirectToSignInTask } from '../../common';
89
import { useCoreSignIn } from '../../contexts';
10+
import { useRouter } from '../../router';
911
import { SignInFactorTwoAlternativeMethods } from './SignInFactorTwoAlternativeMethods';
1012
import { SignInFactorTwoBackupCodeCard } from './SignInFactorTwoBackupCodeCard';
1113
import { SignInFactorTwoEmailCodeCard } from './SignInFactorTwoEmailCodeCard';
@@ -26,7 +28,9 @@ const factorKey = (factor: SignInFactor | null | undefined) => {
2628
};
2729

2830
function SignInFactorTwoInternal(): JSX.Element {
31+
const { __internal_setActiveInProgress } = useClerk();
2932
const signIn = useCoreSignIn();
33+
const router = useRouter();
3034
const availableFactors = signIn.supportedSecondFactors;
3135

3236
const lastPreparedFactorKeyRef = React.useRef('');
@@ -45,6 +49,19 @@ function SignInFactorTwoInternal(): JSX.Element {
4549
toggleAllStrategies();
4650
};
4751

52+
React.useEffect(() => {
53+
if (__internal_setActiveInProgress) {
54+
return;
55+
}
56+
57+
// If the sign-in was reset or doesn't exist, redirect back to the start.
58+
// Don't redirect for 'complete' status - setActive will handle navigation.
59+
if (signIn.status === null || signIn.status === 'needs_identifier' || signIn.status === 'needs_first_factor') {
60+
void router.navigate('../');
61+
}
62+
// eslint-disable-next-line react-hooks/exhaustive-deps -- Match SignInFactorOne pattern: only run on mount and when setActiveInProgress changes
63+
}, [__internal_setActiveInProgress]);
64+
4865
if (!currentFactor) {
4966
return <LoadingCard />;
5067
}

0 commit comments

Comments
 (0)