Skip to content

Commit 9bff46f

Browse files
committed
fix(clerk-js): Wrap captcha diagnostic code in try-catch to prevent production impact
1 parent fa94448 commit 9bff46f

1 file changed

Lines changed: 36 additions & 24 deletions

File tree

packages/clerk-js/src/utils/captcha/turnstile.ts

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,19 @@ export const getTurnstileToken = async (opts: CaptchaOptions) => {
7777
const { modalContainerQuerySelector, modalWrapperQuerySelector, closeModal, openModal } = opts;
7878
const captcha: Turnstile.Turnstile = await loadCaptcha(nonce);
7979

80-
// Timing and error tracking for diagnostics
81-
const startTime = Date.now();
82-
const errorTimeline: Array<{ code: string | number; t: number }> = [];
83-
// Unique ID to correlate log entries for this captcha attempt
84-
const captchaAttemptId =
85-
typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
86-
? crypto.randomUUID()
87-
: Math.random().toString(36).substring(2, 9);
80+
// Diagnostic tracking - wrapped in try-catch to never affect production behavior
81+
let startTime = 0;
82+
let errorTimeline: Array<{ code: string | number; t: number }> = [];
83+
let captchaAttemptId = '';
84+
try {
85+
startTime = Date.now();
86+
captchaAttemptId =
87+
typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
88+
? crypto.randomUUID()
89+
: Math.random().toString(36).substring(2, 9);
90+
} catch {
91+
// Silently ignore - diagnostics should never break captcha flow
92+
}
8893

8994
let captchaToken = '';
9095
let id = '';
@@ -190,7 +195,11 @@ export const getTurnstileToken = async (opts: CaptchaOptions) => {
190195
}
191196
},
192197
'error-callback': function (errorCode) {
193-
errorTimeline.push({ code: errorCode, t: Date.now() - startTime });
198+
try {
199+
errorTimeline.push({ code: errorCode, t: Date.now() - startTime });
200+
} catch {
201+
// Silently ignore - diagnostics should never break captcha flow
202+
}
194203
/**
195204
* By setting retry to 'never' the responsibility for implementing retrying is ours
196205
* https://developers.cloudflare.com/turnstile/reference/client-side-errors/#retrying
@@ -230,22 +239,25 @@ export const getTurnstileToken = async (opts: CaptchaOptions) => {
230239
captcha.remove(id);
231240
}
232241

233-
// Check if widget container exists at failure time (helps diagnose 200100 race conditions)
234-
const containerExistsAtFailure = widgetContainerQuerySelector
235-
? !!document.querySelector(widgetContainerQuerySelector)
236-
: false;
242+
// Log failure with full error history for debugging - wrapped to never affect production
243+
try {
244+
const containerExistsAtFailure = widgetContainerQuerySelector
245+
? !!document.querySelector(widgetContainerQuerySelector)
246+
: false;
237247

238-
// Log failure with full error history for debugging
239-
debugLogger.error('Turnstile captcha challenge failed', {
240-
captchaAttemptId,
241-
errorTimeline,
242-
lastErrorCode: errorTimeline.length > 0 ? errorTimeline[errorTimeline.length - 1].code : null,
243-
finalError: String(e),
244-
retriesAttempted: retries,
245-
widgetType: captchaTypeUsed,
246-
containerExistsAtFailure,
247-
totalDurationMs: Date.now() - startTime,
248-
}, 'captcha');
248+
debugLogger.error('Turnstile captcha challenge failed', {
249+
captchaAttemptId,
250+
errorTimeline,
251+
lastErrorCode: errorTimeline.length > 0 ? errorTimeline[errorTimeline.length - 1].code : null,
252+
finalError: String(e),
253+
retriesAttempted: retries,
254+
widgetType: captchaTypeUsed,
255+
containerExistsAtFailure,
256+
totalDurationMs: Date.now() - startTime,
257+
}, 'captcha');
258+
} catch {
259+
// Silently ignore - diagnostics should never break captcha flow
260+
}
249261

250262
// eslint-disable-next-line @typescript-eslint/only-throw-error
251263
throw {

0 commit comments

Comments
 (0)