@@ -3,6 +3,8 @@ import type { CaptchaWidgetType } from '@clerk/types';
33
44import { CAPTCHA_ELEMENT_ID , CAPTCHA_INVISIBLE_CLASSNAME } from './constants' ;
55
6+ const CLOUDFLARE_TURNSTILE_ORIGINAL_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js' ;
7+
68interface RenderOptions {
79 /**
810 * Every widget has a sitekey. This sitekey is associated with the corresponding widget configuration and is created upon the widget creation.
@@ -69,21 +71,31 @@ export const shouldRetryTurnstileErrorCode = (errorCode: string) => {
6971 return ! ! codesWithRetries . find ( w => errorCode . startsWith ( w ) ) ;
7072} ;
7173
72- async function loadCaptcha ( url : string ) {
74+ async function loadCaptcha ( fallbackUrl : string ) {
7375 if ( ! window . turnstile ) {
74- try {
75- await loadScript ( url , { defer : true } ) ;
76- } catch {
77- // Rethrow with specific message
78- console . error ( 'Clerk: Failed to load the CAPTCHA script from the URL: ' , url ) ;
79- throw {
80- captchaError : 'captcha_script_failed_to_load' ,
81- } ;
82- }
76+ await loadCaptchaFromCloudflareURL ( )
77+ . catch ( ( ) => loadCaptchaFromFAPIProxiedURL ( fallbackUrl ) )
78+ . catch ( ( ) => {
79+ throw { captchaError : 'captcha_script_failed_to_load' } ;
80+ } ) ;
8381 }
8482 return window . turnstile ;
8583}
8684
85+ async function loadCaptchaFromCloudflareURL ( ) {
86+ return await loadScript ( CLOUDFLARE_TURNSTILE_ORIGINAL_URL , { defer : true } ) ;
87+ }
88+
89+ async function loadCaptchaFromFAPIProxiedURL ( fallbackUrl : string ) {
90+ try {
91+ return await loadScript ( fallbackUrl , { defer : true } ) ;
92+ } catch ( err ) {
93+ // Rethrow with specific message
94+ console . error ( 'Clerk: Failed to load the CAPTCHA script from the URL: ' , fallbackUrl ) ;
95+ throw err ;
96+ }
97+ }
98+
8799/*
88100 * How this function works:
89101 * The widgetType is either 'invisible' or 'smart'.
0 commit comments