@clerk/shared 4.30.1-canary.v20260824165645 → 4.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,7 +25,25 @@ interface ExecuteProtectCheckOptions {
25
25
  * Scripts that don't honor the signal will continue to run; this is best-effort by design.
26
26
  */
27
27
  signal?: AbortSignal;
28
+ /**
29
+ * Overrides how long to wait for the challenge module to LOAD. Per-instance and per-loader
30
+ * config, since the right value depends on the population an instance serves; a non-positive
31
+ * or non-numeric value falls back to {@link DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS}.
32
+ *
33
+ * Bounds the handoff only — never the challenge. See the note on the constant.
34
+ */
35
+ loadTimeoutMs?: number;
28
36
  }
37
+ /**
38
+ * Default bound on LOADING the challenge module.
39
+ *
40
+ * Its only job is a network that accepts a connection and then never answers, because every
41
+ * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the
42
+ * dynamic import on its own and needs no timer to notice. That makes a generous value the safe
43
+ * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a
44
+ * genuinely slow connection would fail a load that was going to succeed.
45
+ */
46
+ declare const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 60000;
29
47
  /**
30
48
  * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element
31
49
  * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof
@@ -49,4 +67,4 @@ interface ExecuteProtectCheckOptions {
49
67
  */
50
68
  declare function executeProtectCheck(protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>, container: HTMLDivElement, options?: ExecuteProtectCheckOptions): Promise<string>;
51
69
  //#endregion
52
- export { ExecuteProtectCheckOptions, executeProtectCheck };
70
+ export { DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS, ExecuteProtectCheckOptions, executeProtectCheck };
@@ -25,7 +25,25 @@ interface ExecuteProtectCheckOptions {
25
25
  * Scripts that don't honor the signal will continue to run; this is best-effort by design.
26
26
  */
27
27
  signal?: AbortSignal;
28
+ /**
29
+ * Overrides how long to wait for the challenge module to LOAD. Per-instance and per-loader
30
+ * config, since the right value depends on the population an instance serves; a non-positive
31
+ * or non-numeric value falls back to {@link DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS}.
32
+ *
33
+ * Bounds the handoff only — never the challenge. See the note on the constant.
34
+ */
35
+ loadTimeoutMs?: number;
28
36
  }
37
+ /**
38
+ * Default bound on LOADING the challenge module.
39
+ *
40
+ * Its only job is a network that accepts a connection and then never answers, because every
41
+ * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the
42
+ * dynamic import on its own and needs no timer to notice. That makes a generous value the safe
43
+ * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a
44
+ * genuinely slow connection would fail a load that was going to succeed.
45
+ */
46
+ declare const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 60000;
29
47
  /**
30
48
  * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element
31
49
  * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof
@@ -49,4 +67,4 @@ interface ExecuteProtectCheckOptions {
49
67
  */
50
68
  declare function executeProtectCheck(protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>, container: HTMLDivElement, options?: ExecuteProtectCheckOptions): Promise<string>;
51
69
  //#endregion
52
- export { ExecuteProtectCheckOptions, executeProtectCheck };
70
+ export { DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS, ExecuteProtectCheckOptions, executeProtectCheck };
@@ -4,6 +4,66 @@ require('../../_chunks/error-C-B61RHn.js');
4
4
 
5
5
  //#region src/internal/clerk-js/protectCheck.ts
6
6
  /**
7
+ * Default bound on LOADING the challenge module.
8
+ *
9
+ * Its only job is a network that accepts a connection and then never answers, because every
10
+ * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the
11
+ * dynamic import on its own and needs no timer to notice. That makes a generous value the safe
12
+ * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a
13
+ * genuinely slow connection would fail a load that was going to succeed.
14
+ */
15
+ const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 6e4;
16
+ /**
17
+ * Ceiling on the configured load bound. `setTimeout` stores its delay in a signed 32-bit int, so a
18
+ * larger value overflows and fires immediately — which would make every load fail instantly, the
19
+ * exact opposite of what an operator asking for a long timeout wanted. Clamping rather than
20
+ * rejecting keeps a fat-fingered config from breaking sign-in.
21
+ */
22
+ const MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS = 6e5;
23
+ function resolveLoadTimeoutMs(configured) {
24
+ if (typeof configured !== "number" || !Number.isFinite(configured) || configured <= 0) return DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS;
25
+ return Math.min(configured, MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS);
26
+ }
27
+ /**
28
+ * Races the dynamic import against `timeoutMs`, always clearing the timer so a fast load does not
29
+ * leave one pending.
30
+ *
31
+ * The bound stops at the import on purpose. Once `mod.default` is called the challenge owns its
32
+ * own deadline and the host imposes none: the host cannot know an honest duration for a challenge
33
+ * whose type is chosen server-side, per decision, and whose work it deliberately knows nothing
34
+ * about — waiting on a person, or moving a server-chosen number of bytes over an unknown link. A
35
+ * host-side wall over execution aborts legitimate challenges and reports them as timeouts, and
36
+ * since a re-run restarts the work, retrying cannot win on any connection slow enough to trip it.
37
+ *
38
+ * The abort signal is raced too. A stalled import cannot itself be cancelled, but without this the
39
+ * caller's abort would not settle anything: an unmounted component would keep this promise, its
40
+ * closures and its timer alive for the whole load bound, and then report a load failure for what
41
+ * was really a cancellation.
42
+ */
43
+ function importWithTimeout(url, timeoutMs, signal) {
44
+ let timeoutId;
45
+ let onAbort;
46
+ const expiry = new Promise((_, reject) => {
47
+ timeoutId = setTimeout(() => reject(/* @__PURE__ */ new Error("Protect check script load timed out")), timeoutMs);
48
+ });
49
+ const aborted = new Promise((_, reject) => {
50
+ if (!signal) return;
51
+ onAbort = () => reject(/* @__PURE__ */ new Error("Protect check aborted during load"));
52
+ signal.addEventListener("abort", onAbort, { once: true });
53
+ });
54
+ return Promise.race([
55
+ import(
56
+ /* webpackIgnore: true */
57
+ url
58
+ ),
59
+ expiry,
60
+ aborted
61
+ ]).finally(() => {
62
+ clearTimeout(timeoutId);
63
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
64
+ });
65
+ }
66
+ /**
7
67
  * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.
8
68
  *
9
69
  * Rejects:
@@ -50,17 +110,15 @@ function assertValidSdkUrl(sdkUrl) {
50
110
  * - `protect_check_execution_failed` — the script's default export threw
51
111
  */
52
112
  async function executeProtectCheck(protectCheck, container, options = {}) {
53
- const { signal, setWidgetVisible } = options;
113
+ const { signal, setWidgetVisible, loadTimeoutMs } = options;
54
114
  const { sdkUrl, token, uiHints } = protectCheck;
55
115
  const validated = assertValidSdkUrl(sdkUrl);
56
116
  if (signal?.aborted) throw new require_clerkRuntimeError.ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
57
117
  let mod;
58
118
  try {
59
- mod = await import(
60
- /* webpackIgnore: true */
61
- validated.toString()
62
- );
119
+ mod = await importWithTimeout(validated.toString(), resolveLoadTimeoutMs(loadTimeoutMs), signal);
63
120
  } catch {
121
+ if (signal?.aborted) throw new require_clerkRuntimeError.ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
64
122
  throw new require_clerkRuntimeError.ClerkRuntimeError("Protect check script failed to load. This is commonly caused by a Content Security Policy that blocks the script origin (add it to your script-src directive), a network error, or an invalid module.", { code: "protect_check_script_load_failed" });
65
123
  }
66
124
  if (signal?.aborted) throw new require_clerkRuntimeError.ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
@@ -83,5 +141,6 @@ async function executeProtectCheck(protectCheck, container, options = {}) {
83
141
  }
84
142
 
85
143
  //#endregion
144
+ exports.DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS;
86
145
  exports.executeProtectCheck = executeProtectCheck;
87
146
  //# sourceMappingURL=protectCheck.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"protectCheck.js","names":["ClerkRuntimeError"],"sources":["../../../src/internal/clerk-js/protectCheck.ts"],"sourcesContent":["import { ClerkRuntimeError } from '../../error';\nimport type { ProtectCheckResource } from '../../types';\n\nexport interface ExecuteProtectCheckOptions {\n /**\n * Host-provided visibility handshake, forwarded to the script verbatim as\n * `setWidgetVisible` in the init payload. The script calls it right before revealing UI in\n * the container (and with `false` once its widget is done); the returned promise resolves\n * only after the host has applied the change to the DOM (e.g. removed its own loading\n * spinner), so the script can sequence its reveal without a frame of overlap. A script that\n * knows its widget is imminent may call it immediately to avoid a spinner flash. Scripts\n * must treat the field as optional — older hosts don't provide it.\n */\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n /**\n * Signals that the caller no longer needs the proof token (component unmounted, user\n * navigated away, etc.). When the signal aborts:\n * - If the script has not yet been imported, `executeProtectCheck` rejects with\n * `protect_check_aborted` without loading the script.\n * - The signal is forwarded to the script as `{ signal }` in the second argument so\n * cooperating SDKs can cancel any in-flight UI / network work.\n * - Even if the script ignores the signal and resolves with a token, the helper\n * re-checks `signal.aborted` after the await and rejects with `protect_check_aborted`\n * so the caller never observes a \"successful\" abort.\n *\n * Scripts that don't honor the signal will continue to run; this is best-effort by design.\n */\n signal?: AbortSignal;\n}\n\ninterface ScriptInitOptions {\n token: string;\n uiHints?: Record<string, string>;\n signal?: AbortSignal;\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n}\n\ntype ScriptDefault = (container: HTMLDivElement, init: ScriptInitOptions) => Promise<string>;\n\n/**\n * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.\n *\n * Rejects:\n * - Anything that fails URL parsing (relative paths, garbage strings)\n * - Non-`https:` schemes — including `http:`, `data:`, `blob:`, `javascript:`. The server\n * always returns an HTTPS URL, but the dynamic-import primitive accepts `data:`/`blob:`\n * modules which would let a tampered response inject arbitrary code into the host page.\n * - URLs containing credentials (`user:pass@host`) — phishing surface, no legitimate use.\n *\n * Throws `ClerkRuntimeError` with code `protect_check_invalid_sdk_url`. We deliberately do\n * NOT silently strip an invalid `protect_check` from the resource: the gate must remain\n * present so the user can't bypass it by manipulating the response. Fail-closed.\n */\nfunction assertValidSdkUrl(sdkUrl: string): URL {\n let parsed: URL;\n try {\n parsed = new URL(sdkUrl);\n } catch {\n throw new ClerkRuntimeError('Protect check sdk_url is not a valid URL', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.protocol !== 'https:') {\n throw new ClerkRuntimeError('Protect check sdk_url must use HTTPS', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.username || parsed.password) {\n throw new ClerkRuntimeError('Protect check sdk_url must not contain credentials', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n return parsed;\n}\n\n/**\n * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element\n * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof\n * token the SDK produces.\n *\n * The SDK script must:\n * - Be a valid ES module served over HTTPS\n * - Have a default export of the shape `(container, { token, uiHints, signal }) => Promise<string>`\n * - Honor the `signal` to abort any pending work (best-effort)\n *\n * Only the minimal fields (`token`, optional `ui_hints`) are surfaced to the script — the\n * full sign-up/sign-in resource is intentionally NOT passed, to minimize the trust surface\n * granted to third-party Protect scripts.\n *\n * Failure modes are surfaced as `ClerkRuntimeError` with one of:\n * - `protect_check_invalid_sdk_url` — URL fails the safety checks above\n * - `protect_check_aborted` — caller aborted before or during execution\n * - `protect_check_script_load_failed` — network error, CSP block, or invalid module\n * - `protect_check_invalid_script` — module loaded but no callable default export\n * - `protect_check_execution_failed` — the script's default export threw\n */\nexport async function executeProtectCheck(\n protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>,\n container: HTMLDivElement,\n options: ExecuteProtectCheckOptions = {},\n): Promise<string> {\n const { signal, setWidgetVisible } = options;\n const { sdkUrl, token, uiHints } = protectCheck;\n\n const validated = assertValidSdkUrl(sdkUrl);\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await import(/* webpackIgnore: true */ validated.toString());\n } catch {\n // Surface a generic message and deliberately omit the original error: Chromium/Firefox embed\n // the sdk_url in the dynamic-import failure text, which a tampered response could plant in the UI.\n throw new ClerkRuntimeError(\n 'Protect check script failed to load. This is commonly caused by a Content Security ' +\n 'Policy that blocks the script origin (add it to your script-src directive), a ' +\n 'network error, or an invalid module.',\n { code: 'protect_check_script_load_failed' },\n );\n }\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n if (typeof mod.default !== 'function') {\n throw new ClerkRuntimeError('Protect check script does not export a default function', {\n code: 'protect_check_invalid_script',\n });\n }\n\n let proofToken: string;\n try {\n proofToken = await (mod.default as ScriptDefault)(container, { token, uiHints, signal, setWidgetVisible });\n } catch (err) {\n // Distinguish abort-induced rejections from genuine script errors: only relabel as\n // `protect_check_aborted` when the error looks like an abort (`AbortError`), otherwise\n // surface the script's actual failure so production diagnostics aren't masked.\n const looksLikeAbort = err instanceof Error && err.name === 'AbortError';\n if (signal?.aborted && looksLikeAbort) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n const original = err instanceof Error ? err.message : String(err);\n throw new ClerkRuntimeError(`Protect check script execution failed: ${original}`, {\n code: 'protect_check_execution_failed',\n });\n }\n\n // The script may have ignored the signal and resolved with a token after the abort fired.\n // Re-check here so callers get a consistent contract: if you aborted, you never see a token.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n return proofToken;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqDA,SAAS,kBAAkB,QAAqB;CAC9C,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,MAAM;CACzB,QAAQ;EACN,MAAM,IAAIA,4CAAkB,4CAA4C,EACtE,MAAM,gCACR,CAAC;CACH;CACA,IAAI,OAAO,aAAa,UACtB,MAAM,IAAIA,4CAAkB,wCAAwC,EAClE,MAAM,gCACR,CAAC;CAEH,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAIA,4CAAkB,sDAAsD,EAChF,MAAM,gCACR,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,eAAsB,oBACpB,cACA,WACA,UAAsC,CAAC,GACtB;CACjB,MAAM,EAAE,QAAQ,qBAAqB;CACrC,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,YAAY,kBAAkB,MAAM;CAE1C,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI;CACJ,IAAI;EACF,MAAM,MAAM;;GAAiC,UAAU,SAAS;;CAClE,QAAQ;EAGN,MAAM,IAAIA,4CACR,yMAGA,EAAE,MAAM,mCAAmC,CAC7C;CACF;CAEA,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI,OAAO,IAAI,YAAY,YACzB,MAAM,IAAIA,4CAAkB,2DAA2D,EACrF,MAAM,+BACR,CAAC;CAGH,IAAI;CACJ,IAAI;EACF,aAAa,MAAO,IAAI,QAA0B,WAAW;GAAE;GAAO;GAAS;GAAQ;EAAiB,CAAC;CAC3G,SAAS,KAAK;EAIZ,MAAM,iBAAiB,eAAe,SAAS,IAAI,SAAS;EAC5D,IAAI,QAAQ,WAAW,gBACrB,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAGlG,MAAM,IAAIA,4CAAkB,0CADX,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACkB,EAChF,MAAM,iCACR,CAAC;CACH;CAIA,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,OAAO;AACT"}
1
+ {"version":3,"file":"protectCheck.js","names":["ClerkRuntimeError"],"sources":["../../../src/internal/clerk-js/protectCheck.ts"],"sourcesContent":["import { ClerkRuntimeError } from '../../error';\nimport type { ProtectCheckResource } from '../../types';\n\nexport interface ExecuteProtectCheckOptions {\n /**\n * Host-provided visibility handshake, forwarded to the script verbatim as\n * `setWidgetVisible` in the init payload. The script calls it right before revealing UI in\n * the container (and with `false` once its widget is done); the returned promise resolves\n * only after the host has applied the change to the DOM (e.g. removed its own loading\n * spinner), so the script can sequence its reveal without a frame of overlap. A script that\n * knows its widget is imminent may call it immediately to avoid a spinner flash. Scripts\n * must treat the field as optional — older hosts don't provide it.\n */\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n /**\n * Signals that the caller no longer needs the proof token (component unmounted, user\n * navigated away, etc.). When the signal aborts:\n * - If the script has not yet been imported, `executeProtectCheck` rejects with\n * `protect_check_aborted` without loading the script.\n * - The signal is forwarded to the script as `{ signal }` in the second argument so\n * cooperating SDKs can cancel any in-flight UI / network work.\n * - Even if the script ignores the signal and resolves with a token, the helper\n * re-checks `signal.aborted` after the await and rejects with `protect_check_aborted`\n * so the caller never observes a \"successful\" abort.\n *\n * Scripts that don't honor the signal will continue to run; this is best-effort by design.\n */\n signal?: AbortSignal;\n /**\n * Overrides how long to wait for the challenge module to LOAD. Per-instance and per-loader\n * config, since the right value depends on the population an instance serves; a non-positive\n * or non-numeric value falls back to {@link DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS}.\n *\n * Bounds the handoff only — never the challenge. See the note on the constant.\n */\n loadTimeoutMs?: number;\n}\n\n/**\n * Default bound on LOADING the challenge module.\n *\n * Its only job is a network that accepts a connection and then never answers, because every\n * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the\n * dynamic import on its own and needs no timer to notice. That makes a generous value the safe\n * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a\n * genuinely slow connection would fail a load that was going to succeed.\n */\nexport const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 60_000;\n\n/**\n * Ceiling on the configured load bound. `setTimeout` stores its delay in a signed 32-bit int, so a\n * larger value overflows and fires immediately — which would make every load fail instantly, the\n * exact opposite of what an operator asking for a long timeout wanted. Clamping rather than\n * rejecting keeps a fat-fingered config from breaking sign-in.\n */\nconst MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS = 600_000;\n\nfunction resolveLoadTimeoutMs(configured: number | undefined): number {\n if (typeof configured !== 'number' || !Number.isFinite(configured) || configured <= 0) {\n return DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS;\n }\n return Math.min(configured, MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS);\n}\n\n/**\n * Races the dynamic import against `timeoutMs`, always clearing the timer so a fast load does not\n * leave one pending.\n *\n * The bound stops at the import on purpose. Once `mod.default` is called the challenge owns its\n * own deadline and the host imposes none: the host cannot know an honest duration for a challenge\n * whose type is chosen server-side, per decision, and whose work it deliberately knows nothing\n * about — waiting on a person, or moving a server-chosen number of bytes over an unknown link. A\n * host-side wall over execution aborts legitimate challenges and reports them as timeouts, and\n * since a re-run restarts the work, retrying cannot win on any connection slow enough to trip it.\n *\n * The abort signal is raced too. A stalled import cannot itself be cancelled, but without this the\n * caller's abort would not settle anything: an unmounted component would keep this promise, its\n * closures and its timer alive for the whole load bound, and then report a load failure for what\n * was really a cancellation.\n */\nfunction importWithTimeout(\n url: string,\n timeoutMs: number,\n signal: AbortSignal | undefined,\n): Promise<Record<string, unknown>> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n const expiry = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('Protect check script load timed out')), timeoutMs);\n });\n const aborted = new Promise<never>((_, reject) => {\n if (!signal) {\n return;\n }\n onAbort = () => reject(new Error('Protect check aborted during load'));\n signal.addEventListener('abort', onAbort, { once: true });\n });\n\n return Promise.race([import(/* webpackIgnore: true */ url), expiry, aborted]).finally(() => {\n clearTimeout(timeoutId);\n if (signal && onAbort) {\n signal.removeEventListener('abort', onAbort);\n }\n }) as Promise<Record<string, unknown>>;\n}\n\ninterface ScriptInitOptions {\n token: string;\n uiHints?: Record<string, string>;\n signal?: AbortSignal;\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n}\n\ntype ScriptDefault = (container: HTMLDivElement, init: ScriptInitOptions) => Promise<string>;\n\n/**\n * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.\n *\n * Rejects:\n * - Anything that fails URL parsing (relative paths, garbage strings)\n * - Non-`https:` schemes — including `http:`, `data:`, `blob:`, `javascript:`. The server\n * always returns an HTTPS URL, but the dynamic-import primitive accepts `data:`/`blob:`\n * modules which would let a tampered response inject arbitrary code into the host page.\n * - URLs containing credentials (`user:pass@host`) — phishing surface, no legitimate use.\n *\n * Throws `ClerkRuntimeError` with code `protect_check_invalid_sdk_url`. We deliberately do\n * NOT silently strip an invalid `protect_check` from the resource: the gate must remain\n * present so the user can't bypass it by manipulating the response. Fail-closed.\n */\nfunction assertValidSdkUrl(sdkUrl: string): URL {\n let parsed: URL;\n try {\n parsed = new URL(sdkUrl);\n } catch {\n throw new ClerkRuntimeError('Protect check sdk_url is not a valid URL', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.protocol !== 'https:') {\n throw new ClerkRuntimeError('Protect check sdk_url must use HTTPS', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.username || parsed.password) {\n throw new ClerkRuntimeError('Protect check sdk_url must not contain credentials', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n return parsed;\n}\n\n/**\n * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element\n * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof\n * token the SDK produces.\n *\n * The SDK script must:\n * - Be a valid ES module served over HTTPS\n * - Have a default export of the shape `(container, { token, uiHints, signal }) => Promise<string>`\n * - Honor the `signal` to abort any pending work (best-effort)\n *\n * Only the minimal fields (`token`, optional `ui_hints`) are surfaced to the script — the\n * full sign-up/sign-in resource is intentionally NOT passed, to minimize the trust surface\n * granted to third-party Protect scripts.\n *\n * Failure modes are surfaced as `ClerkRuntimeError` with one of:\n * - `protect_check_invalid_sdk_url` — URL fails the safety checks above\n * - `protect_check_aborted` — caller aborted before or during execution\n * - `protect_check_script_load_failed` — network error, CSP block, or invalid module\n * - `protect_check_invalid_script` — module loaded but no callable default export\n * - `protect_check_execution_failed` — the script's default export threw\n */\nexport async function executeProtectCheck(\n protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>,\n container: HTMLDivElement,\n options: ExecuteProtectCheckOptions = {},\n): Promise<string> {\n const { signal, setWidgetVisible, loadTimeoutMs } = options;\n const { sdkUrl, token, uiHints } = protectCheck;\n\n const validated = assertValidSdkUrl(sdkUrl);\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await importWithTimeout(validated.toString(), resolveLoadTimeoutMs(loadTimeoutMs), signal);\n } catch {\n // An abort that landed mid-load is a cancellation, not a load failure. Checked first so the\n // caller gets the same contract it does everywhere else: if you aborted, you never see\n // anything but `protect_check_aborted`.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n // Surface a generic message and deliberately omit the original error: Chromium/Firefox embed\n // the sdk_url in the dynamic-import failure text, which a tampered response could plant in the UI.\n throw new ClerkRuntimeError(\n 'Protect check script failed to load. This is commonly caused by a Content Security ' +\n 'Policy that blocks the script origin (add it to your script-src directive), a ' +\n 'network error, or an invalid module.',\n { code: 'protect_check_script_load_failed' },\n );\n }\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n if (typeof mod.default !== 'function') {\n throw new ClerkRuntimeError('Protect check script does not export a default function', {\n code: 'protect_check_invalid_script',\n });\n }\n\n let proofToken: string;\n try {\n proofToken = await (mod.default as ScriptDefault)(container, { token, uiHints, signal, setWidgetVisible });\n } catch (err) {\n // Distinguish abort-induced rejections from genuine script errors: only relabel as\n // `protect_check_aborted` when the error looks like an abort (`AbortError`), otherwise\n // surface the script's actual failure so production diagnostics aren't masked.\n const looksLikeAbort = err instanceof Error && err.name === 'AbortError';\n if (signal?.aborted && looksLikeAbort) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n const original = err instanceof Error ? err.message : String(err);\n throw new ClerkRuntimeError(`Protect check script execution failed: ${original}`, {\n code: 'protect_check_execution_failed',\n });\n }\n\n // The script may have ignored the signal and resolved with a token after the abort fired.\n // Re-check here so callers get a consistent contract: if you aborted, you never see a token.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n return proofToken;\n}\n"],"mappings":";;;;;;;;;;;;;;AA+CA,MAAa,wCAAwC;;;;;;;AAQrD,MAAM,oCAAoC;AAE1C,SAAS,qBAAqB,YAAwC;CACpE,IAAI,OAAO,eAAe,YAAY,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,GAClF,OAAO;CAET,OAAO,KAAK,IAAI,YAAY,iCAAiC;AAC/D;;;;;;;;;;;;;;;;;AAkBA,SAAS,kBACP,KACA,WACA,QACkC;CAClC,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,IAAI,SAAgB,GAAG,WAAW;EAC/C,YAAY,iBAAiB,uBAAO,IAAI,MAAM,qCAAqC,CAAC,GAAG,SAAS;CAClG,CAAC;CACD,MAAM,UAAU,IAAI,SAAgB,GAAG,WAAW;EAChD,IAAI,CAAC,QACH;EAEF,gBAAgB,uBAAO,IAAI,MAAM,mCAAmC,CAAC;EACrE,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;CAED,OAAO,QAAQ,KAAK;EAAC;;GAAiC;;EAAM;EAAQ;CAAO,CAAC,CAAC,CAAC,cAAc;EAC1F,aAAa,SAAS;EACtB,IAAI,UAAU,SACZ,OAAO,oBAAoB,SAAS,OAAO;CAE/C,CAAC;AACH;;;;;;;;;;;;;;;AAyBA,SAAS,kBAAkB,QAAqB;CAC9C,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,MAAM;CACzB,QAAQ;EACN,MAAM,IAAIA,4CAAkB,4CAA4C,EACtE,MAAM,gCACR,CAAC;CACH;CACA,IAAI,OAAO,aAAa,UACtB,MAAM,IAAIA,4CAAkB,wCAAwC,EAClE,MAAM,gCACR,CAAC;CAEH,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAIA,4CAAkB,sDAAsD,EAChF,MAAM,gCACR,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,eAAsB,oBACpB,cACA,WACA,UAAsC,CAAC,GACtB;CACjB,MAAM,EAAE,QAAQ,kBAAkB,kBAAkB;CACpD,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,YAAY,kBAAkB,MAAM;CAE1C,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,kBAAkB,UAAU,SAAS,GAAG,qBAAqB,aAAa,GAAG,MAAM;CACjG,QAAQ;EAIN,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAIlG,MAAM,IAAIA,4CACR,yMAGA,EAAE,MAAM,mCAAmC,CAC7C;CACF;CAEA,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI,OAAO,IAAI,YAAY,YACzB,MAAM,IAAIA,4CAAkB,2DAA2D,EACrF,MAAM,+BACR,CAAC;CAGH,IAAI;CACJ,IAAI;EACF,aAAa,MAAO,IAAI,QAA0B,WAAW;GAAE;GAAO;GAAS;GAAQ;EAAiB,CAAC;CAC3G,SAAS,KAAK;EAIZ,MAAM,iBAAiB,eAAe,SAAS,IAAI,SAAS;EAC5D,IAAI,QAAQ,WAAW,gBACrB,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAGlG,MAAM,IAAIA,4CAAkB,0CADX,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACkB,EAChF,MAAM,iCACR,CAAC;CACH;CAIA,IAAI,QAAQ,SACV,MAAM,IAAIA,4CAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,OAAO;AACT"}
@@ -3,6 +3,66 @@ import "../../_chunks/error-CYyD2kei.mjs";
3
3
 
4
4
  //#region src/internal/clerk-js/protectCheck.ts
5
5
  /**
6
+ * Default bound on LOADING the challenge module.
7
+ *
8
+ * Its only job is a network that accepts a connection and then never answers, because every
9
+ * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the
10
+ * dynamic import on its own and needs no timer to notice. That makes a generous value the safe
11
+ * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a
12
+ * genuinely slow connection would fail a load that was going to succeed.
13
+ */
14
+ const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 6e4;
15
+ /**
16
+ * Ceiling on the configured load bound. `setTimeout` stores its delay in a signed 32-bit int, so a
17
+ * larger value overflows and fires immediately — which would make every load fail instantly, the
18
+ * exact opposite of what an operator asking for a long timeout wanted. Clamping rather than
19
+ * rejecting keeps a fat-fingered config from breaking sign-in.
20
+ */
21
+ const MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS = 6e5;
22
+ function resolveLoadTimeoutMs(configured) {
23
+ if (typeof configured !== "number" || !Number.isFinite(configured) || configured <= 0) return DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS;
24
+ return Math.min(configured, MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS);
25
+ }
26
+ /**
27
+ * Races the dynamic import against `timeoutMs`, always clearing the timer so a fast load does not
28
+ * leave one pending.
29
+ *
30
+ * The bound stops at the import on purpose. Once `mod.default` is called the challenge owns its
31
+ * own deadline and the host imposes none: the host cannot know an honest duration for a challenge
32
+ * whose type is chosen server-side, per decision, and whose work it deliberately knows nothing
33
+ * about — waiting on a person, or moving a server-chosen number of bytes over an unknown link. A
34
+ * host-side wall over execution aborts legitimate challenges and reports them as timeouts, and
35
+ * since a re-run restarts the work, retrying cannot win on any connection slow enough to trip it.
36
+ *
37
+ * The abort signal is raced too. A stalled import cannot itself be cancelled, but without this the
38
+ * caller's abort would not settle anything: an unmounted component would keep this promise, its
39
+ * closures and its timer alive for the whole load bound, and then report a load failure for what
40
+ * was really a cancellation.
41
+ */
42
+ function importWithTimeout(url, timeoutMs, signal) {
43
+ let timeoutId;
44
+ let onAbort;
45
+ const expiry = new Promise((_, reject) => {
46
+ timeoutId = setTimeout(() => reject(/* @__PURE__ */ new Error("Protect check script load timed out")), timeoutMs);
47
+ });
48
+ const aborted = new Promise((_, reject) => {
49
+ if (!signal) return;
50
+ onAbort = () => reject(/* @__PURE__ */ new Error("Protect check aborted during load"));
51
+ signal.addEventListener("abort", onAbort, { once: true });
52
+ });
53
+ return Promise.race([
54
+ import(
55
+ /* webpackIgnore: true */
56
+ url
57
+ ),
58
+ expiry,
59
+ aborted
60
+ ]).finally(() => {
61
+ clearTimeout(timeoutId);
62
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
63
+ });
64
+ }
65
+ /**
6
66
  * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.
7
67
  *
8
68
  * Rejects:
@@ -49,17 +109,15 @@ function assertValidSdkUrl(sdkUrl) {
49
109
  * - `protect_check_execution_failed` — the script's default export threw
50
110
  */
51
111
  async function executeProtectCheck(protectCheck, container, options = {}) {
52
- const { signal, setWidgetVisible } = options;
112
+ const { signal, setWidgetVisible, loadTimeoutMs } = options;
53
113
  const { sdkUrl, token, uiHints } = protectCheck;
54
114
  const validated = assertValidSdkUrl(sdkUrl);
55
115
  if (signal?.aborted) throw new ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
56
116
  let mod;
57
117
  try {
58
- mod = await import(
59
- /* webpackIgnore: true */
60
- validated.toString()
61
- );
118
+ mod = await importWithTimeout(validated.toString(), resolveLoadTimeoutMs(loadTimeoutMs), signal);
62
119
  } catch {
120
+ if (signal?.aborted) throw new ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
63
121
  throw new ClerkRuntimeError("Protect check script failed to load. This is commonly caused by a Content Security Policy that blocks the script origin (add it to your script-src directive), a network error, or an invalid module.", { code: "protect_check_script_load_failed" });
64
122
  }
65
123
  if (signal?.aborted) throw new ClerkRuntimeError("Protect check aborted by caller", { code: "protect_check_aborted" });
@@ -82,5 +140,5 @@ async function executeProtectCheck(protectCheck, container, options = {}) {
82
140
  }
83
141
 
84
142
  //#endregion
85
- export { executeProtectCheck };
143
+ export { DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS, executeProtectCheck };
86
144
  //# sourceMappingURL=protectCheck.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"protectCheck.mjs","names":[],"sources":["../../../src/internal/clerk-js/protectCheck.ts"],"sourcesContent":["import { ClerkRuntimeError } from '../../error';\nimport type { ProtectCheckResource } from '../../types';\n\nexport interface ExecuteProtectCheckOptions {\n /**\n * Host-provided visibility handshake, forwarded to the script verbatim as\n * `setWidgetVisible` in the init payload. The script calls it right before revealing UI in\n * the container (and with `false` once its widget is done); the returned promise resolves\n * only after the host has applied the change to the DOM (e.g. removed its own loading\n * spinner), so the script can sequence its reveal without a frame of overlap. A script that\n * knows its widget is imminent may call it immediately to avoid a spinner flash. Scripts\n * must treat the field as optional — older hosts don't provide it.\n */\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n /**\n * Signals that the caller no longer needs the proof token (component unmounted, user\n * navigated away, etc.). When the signal aborts:\n * - If the script has not yet been imported, `executeProtectCheck` rejects with\n * `protect_check_aborted` without loading the script.\n * - The signal is forwarded to the script as `{ signal }` in the second argument so\n * cooperating SDKs can cancel any in-flight UI / network work.\n * - Even if the script ignores the signal and resolves with a token, the helper\n * re-checks `signal.aborted` after the await and rejects with `protect_check_aborted`\n * so the caller never observes a \"successful\" abort.\n *\n * Scripts that don't honor the signal will continue to run; this is best-effort by design.\n */\n signal?: AbortSignal;\n}\n\ninterface ScriptInitOptions {\n token: string;\n uiHints?: Record<string, string>;\n signal?: AbortSignal;\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n}\n\ntype ScriptDefault = (container: HTMLDivElement, init: ScriptInitOptions) => Promise<string>;\n\n/**\n * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.\n *\n * Rejects:\n * - Anything that fails URL parsing (relative paths, garbage strings)\n * - Non-`https:` schemes — including `http:`, `data:`, `blob:`, `javascript:`. The server\n * always returns an HTTPS URL, but the dynamic-import primitive accepts `data:`/`blob:`\n * modules which would let a tampered response inject arbitrary code into the host page.\n * - URLs containing credentials (`user:pass@host`) — phishing surface, no legitimate use.\n *\n * Throws `ClerkRuntimeError` with code `protect_check_invalid_sdk_url`. We deliberately do\n * NOT silently strip an invalid `protect_check` from the resource: the gate must remain\n * present so the user can't bypass it by manipulating the response. Fail-closed.\n */\nfunction assertValidSdkUrl(sdkUrl: string): URL {\n let parsed: URL;\n try {\n parsed = new URL(sdkUrl);\n } catch {\n throw new ClerkRuntimeError('Protect check sdk_url is not a valid URL', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.protocol !== 'https:') {\n throw new ClerkRuntimeError('Protect check sdk_url must use HTTPS', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.username || parsed.password) {\n throw new ClerkRuntimeError('Protect check sdk_url must not contain credentials', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n return parsed;\n}\n\n/**\n * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element\n * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof\n * token the SDK produces.\n *\n * The SDK script must:\n * - Be a valid ES module served over HTTPS\n * - Have a default export of the shape `(container, { token, uiHints, signal }) => Promise<string>`\n * - Honor the `signal` to abort any pending work (best-effort)\n *\n * Only the minimal fields (`token`, optional `ui_hints`) are surfaced to the script — the\n * full sign-up/sign-in resource is intentionally NOT passed, to minimize the trust surface\n * granted to third-party Protect scripts.\n *\n * Failure modes are surfaced as `ClerkRuntimeError` with one of:\n * - `protect_check_invalid_sdk_url` — URL fails the safety checks above\n * - `protect_check_aborted` — caller aborted before or during execution\n * - `protect_check_script_load_failed` — network error, CSP block, or invalid module\n * - `protect_check_invalid_script` — module loaded but no callable default export\n * - `protect_check_execution_failed` — the script's default export threw\n */\nexport async function executeProtectCheck(\n protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>,\n container: HTMLDivElement,\n options: ExecuteProtectCheckOptions = {},\n): Promise<string> {\n const { signal, setWidgetVisible } = options;\n const { sdkUrl, token, uiHints } = protectCheck;\n\n const validated = assertValidSdkUrl(sdkUrl);\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await import(/* webpackIgnore: true */ validated.toString());\n } catch {\n // Surface a generic message and deliberately omit the original error: Chromium/Firefox embed\n // the sdk_url in the dynamic-import failure text, which a tampered response could plant in the UI.\n throw new ClerkRuntimeError(\n 'Protect check script failed to load. This is commonly caused by a Content Security ' +\n 'Policy that blocks the script origin (add it to your script-src directive), a ' +\n 'network error, or an invalid module.',\n { code: 'protect_check_script_load_failed' },\n );\n }\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n if (typeof mod.default !== 'function') {\n throw new ClerkRuntimeError('Protect check script does not export a default function', {\n code: 'protect_check_invalid_script',\n });\n }\n\n let proofToken: string;\n try {\n proofToken = await (mod.default as ScriptDefault)(container, { token, uiHints, signal, setWidgetVisible });\n } catch (err) {\n // Distinguish abort-induced rejections from genuine script errors: only relabel as\n // `protect_check_aborted` when the error looks like an abort (`AbortError`), otherwise\n // surface the script's actual failure so production diagnostics aren't masked.\n const looksLikeAbort = err instanceof Error && err.name === 'AbortError';\n if (signal?.aborted && looksLikeAbort) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n const original = err instanceof Error ? err.message : String(err);\n throw new ClerkRuntimeError(`Protect check script execution failed: ${original}`, {\n code: 'protect_check_execution_failed',\n });\n }\n\n // The script may have ignored the signal and resolved with a token after the abort fired.\n // Re-check here so callers get a consistent contract: if you aborted, you never see a token.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n return proofToken;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqDA,SAAS,kBAAkB,QAAqB;CAC9C,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,MAAM;CACzB,QAAQ;EACN,MAAM,IAAI,kBAAkB,4CAA4C,EACtE,MAAM,gCACR,CAAC;CACH;CACA,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,kBAAkB,wCAAwC,EAClE,MAAM,gCACR,CAAC;CAEH,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAI,kBAAkB,sDAAsD,EAChF,MAAM,gCACR,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,eAAsB,oBACpB,cACA,WACA,UAAsC,CAAC,GACtB;CACjB,MAAM,EAAE,QAAQ,qBAAqB;CACrC,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,YAAY,kBAAkB,MAAM;CAE1C,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI;CACJ,IAAI;EACF,MAAM,MAAM;;GAAiC,UAAU,SAAS;;CAClE,QAAQ;EAGN,MAAM,IAAI,kBACR,yMAGA,EAAE,MAAM,mCAAmC,CAC7C;CACF;CAEA,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI,OAAO,IAAI,YAAY,YACzB,MAAM,IAAI,kBAAkB,2DAA2D,EACrF,MAAM,+BACR,CAAC;CAGH,IAAI;CACJ,IAAI;EACF,aAAa,MAAO,IAAI,QAA0B,WAAW;GAAE;GAAO;GAAS;GAAQ;EAAiB,CAAC;CAC3G,SAAS,KAAK;EAIZ,MAAM,iBAAiB,eAAe,SAAS,IAAI,SAAS;EAC5D,IAAI,QAAQ,WAAW,gBACrB,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAGlG,MAAM,IAAI,kBAAkB,0CADX,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACkB,EAChF,MAAM,iCACR,CAAC;CACH;CAIA,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,OAAO;AACT"}
1
+ {"version":3,"file":"protectCheck.mjs","names":[],"sources":["../../../src/internal/clerk-js/protectCheck.ts"],"sourcesContent":["import { ClerkRuntimeError } from '../../error';\nimport type { ProtectCheckResource } from '../../types';\n\nexport interface ExecuteProtectCheckOptions {\n /**\n * Host-provided visibility handshake, forwarded to the script verbatim as\n * `setWidgetVisible` in the init payload. The script calls it right before revealing UI in\n * the container (and with `false` once its widget is done); the returned promise resolves\n * only after the host has applied the change to the DOM (e.g. removed its own loading\n * spinner), so the script can sequence its reveal without a frame of overlap. A script that\n * knows its widget is imminent may call it immediately to avoid a spinner flash. Scripts\n * must treat the field as optional — older hosts don't provide it.\n */\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n /**\n * Signals that the caller no longer needs the proof token (component unmounted, user\n * navigated away, etc.). When the signal aborts:\n * - If the script has not yet been imported, `executeProtectCheck` rejects with\n * `protect_check_aborted` without loading the script.\n * - The signal is forwarded to the script as `{ signal }` in the second argument so\n * cooperating SDKs can cancel any in-flight UI / network work.\n * - Even if the script ignores the signal and resolves with a token, the helper\n * re-checks `signal.aborted` after the await and rejects with `protect_check_aborted`\n * so the caller never observes a \"successful\" abort.\n *\n * Scripts that don't honor the signal will continue to run; this is best-effort by design.\n */\n signal?: AbortSignal;\n /**\n * Overrides how long to wait for the challenge module to LOAD. Per-instance and per-loader\n * config, since the right value depends on the population an instance serves; a non-positive\n * or non-numeric value falls back to {@link DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS}.\n *\n * Bounds the handoff only — never the challenge. See the note on the constant.\n */\n loadTimeoutMs?: number;\n}\n\n/**\n * Default bound on LOADING the challenge module.\n *\n * Its only job is a network that accepts a connection and then never answers, because every\n * other load failure — a CSP block, DNS, a 404, a body that isn't a valid module — rejects the\n * dynamic import on its own and needs no timer to notice. That makes a generous value the safe\n * one: nothing legitimate is waiting on this timer, while a value tight enough to fire on a\n * genuinely slow connection would fail a load that was going to succeed.\n */\nexport const DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS = 60_000;\n\n/**\n * Ceiling on the configured load bound. `setTimeout` stores its delay in a signed 32-bit int, so a\n * larger value overflows and fires immediately — which would make every load fail instantly, the\n * exact opposite of what an operator asking for a long timeout wanted. Clamping rather than\n * rejecting keeps a fat-fingered config from breaking sign-in.\n */\nconst MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS = 600_000;\n\nfunction resolveLoadTimeoutMs(configured: number | undefined): number {\n if (typeof configured !== 'number' || !Number.isFinite(configured) || configured <= 0) {\n return DEFAULT_PROTECT_CHECK_LOAD_TIMEOUT_MS;\n }\n return Math.min(configured, MAX_PROTECT_CHECK_LOAD_TIMEOUT_MS);\n}\n\n/**\n * Races the dynamic import against `timeoutMs`, always clearing the timer so a fast load does not\n * leave one pending.\n *\n * The bound stops at the import on purpose. Once `mod.default` is called the challenge owns its\n * own deadline and the host imposes none: the host cannot know an honest duration for a challenge\n * whose type is chosen server-side, per decision, and whose work it deliberately knows nothing\n * about — waiting on a person, or moving a server-chosen number of bytes over an unknown link. A\n * host-side wall over execution aborts legitimate challenges and reports them as timeouts, and\n * since a re-run restarts the work, retrying cannot win on any connection slow enough to trip it.\n *\n * The abort signal is raced too. A stalled import cannot itself be cancelled, but without this the\n * caller's abort would not settle anything: an unmounted component would keep this promise, its\n * closures and its timer alive for the whole load bound, and then report a load failure for what\n * was really a cancellation.\n */\nfunction importWithTimeout(\n url: string,\n timeoutMs: number,\n signal: AbortSignal | undefined,\n): Promise<Record<string, unknown>> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n\n const expiry = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error('Protect check script load timed out')), timeoutMs);\n });\n const aborted = new Promise<never>((_, reject) => {\n if (!signal) {\n return;\n }\n onAbort = () => reject(new Error('Protect check aborted during load'));\n signal.addEventListener('abort', onAbort, { once: true });\n });\n\n return Promise.race([import(/* webpackIgnore: true */ url), expiry, aborted]).finally(() => {\n clearTimeout(timeoutId);\n if (signal && onAbort) {\n signal.removeEventListener('abort', onAbort);\n }\n }) as Promise<Record<string, unknown>>;\n}\n\ninterface ScriptInitOptions {\n token: string;\n uiHints?: Record<string, string>;\n signal?: AbortSignal;\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n}\n\ntype ScriptDefault = (container: HTMLDivElement, init: ScriptInitOptions) => Promise<string>;\n\n/**\n * Validates the `sdk_url` returned by the server before passing it to dynamic `import()`.\n *\n * Rejects:\n * - Anything that fails URL parsing (relative paths, garbage strings)\n * - Non-`https:` schemes — including `http:`, `data:`, `blob:`, `javascript:`. The server\n * always returns an HTTPS URL, but the dynamic-import primitive accepts `data:`/`blob:`\n * modules which would let a tampered response inject arbitrary code into the host page.\n * - URLs containing credentials (`user:pass@host`) — phishing surface, no legitimate use.\n *\n * Throws `ClerkRuntimeError` with code `protect_check_invalid_sdk_url`. We deliberately do\n * NOT silently strip an invalid `protect_check` from the resource: the gate must remain\n * present so the user can't bypass it by manipulating the response. Fail-closed.\n */\nfunction assertValidSdkUrl(sdkUrl: string): URL {\n let parsed: URL;\n try {\n parsed = new URL(sdkUrl);\n } catch {\n throw new ClerkRuntimeError('Protect check sdk_url is not a valid URL', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.protocol !== 'https:') {\n throw new ClerkRuntimeError('Protect check sdk_url must use HTTPS', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n if (parsed.username || parsed.password) {\n throw new ClerkRuntimeError('Protect check sdk_url must not contain credentials', {\n code: 'protect_check_invalid_sdk_url',\n });\n }\n return parsed;\n}\n\n/**\n * Loads the Protect challenge SDK from `protectCheck.sdkUrl`, hands it the container element\n * and the spec-defined init payload (`token`, `uiHints`, `signal`), and returns the proof\n * token the SDK produces.\n *\n * The SDK script must:\n * - Be a valid ES module served over HTTPS\n * - Have a default export of the shape `(container, { token, uiHints, signal }) => Promise<string>`\n * - Honor the `signal` to abort any pending work (best-effort)\n *\n * Only the minimal fields (`token`, optional `ui_hints`) are surfaced to the script — the\n * full sign-up/sign-in resource is intentionally NOT passed, to minimize the trust surface\n * granted to third-party Protect scripts.\n *\n * Failure modes are surfaced as `ClerkRuntimeError` with one of:\n * - `protect_check_invalid_sdk_url` — URL fails the safety checks above\n * - `protect_check_aborted` — caller aborted before or during execution\n * - `protect_check_script_load_failed` — network error, CSP block, or invalid module\n * - `protect_check_invalid_script` — module loaded but no callable default export\n * - `protect_check_execution_failed` — the script's default export threw\n */\nexport async function executeProtectCheck(\n protectCheck: Pick<ProtectCheckResource, 'sdkUrl' | 'token' | 'uiHints'>,\n container: HTMLDivElement,\n options: ExecuteProtectCheckOptions = {},\n): Promise<string> {\n const { signal, setWidgetVisible, loadTimeoutMs } = options;\n const { sdkUrl, token, uiHints } = protectCheck;\n\n const validated = assertValidSdkUrl(sdkUrl);\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await importWithTimeout(validated.toString(), resolveLoadTimeoutMs(loadTimeoutMs), signal);\n } catch {\n // An abort that landed mid-load is a cancellation, not a load failure. Checked first so the\n // caller gets the same contract it does everywhere else: if you aborted, you never see\n // anything but `protect_check_aborted`.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n // Surface a generic message and deliberately omit the original error: Chromium/Firefox embed\n // the sdk_url in the dynamic-import failure text, which a tampered response could plant in the UI.\n throw new ClerkRuntimeError(\n 'Protect check script failed to load. This is commonly caused by a Content Security ' +\n 'Policy that blocks the script origin (add it to your script-src directive), a ' +\n 'network error, or an invalid module.',\n { code: 'protect_check_script_load_failed' },\n );\n }\n\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n if (typeof mod.default !== 'function') {\n throw new ClerkRuntimeError('Protect check script does not export a default function', {\n code: 'protect_check_invalid_script',\n });\n }\n\n let proofToken: string;\n try {\n proofToken = await (mod.default as ScriptDefault)(container, { token, uiHints, signal, setWidgetVisible });\n } catch (err) {\n // Distinguish abort-induced rejections from genuine script errors: only relabel as\n // `protect_check_aborted` when the error looks like an abort (`AbortError`), otherwise\n // surface the script's actual failure so production diagnostics aren't masked.\n const looksLikeAbort = err instanceof Error && err.name === 'AbortError';\n if (signal?.aborted && looksLikeAbort) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n const original = err instanceof Error ? err.message : String(err);\n throw new ClerkRuntimeError(`Protect check script execution failed: ${original}`, {\n code: 'protect_check_execution_failed',\n });\n }\n\n // The script may have ignored the signal and resolved with a token after the abort fired.\n // Re-check here so callers get a consistent contract: if you aborted, you never see a token.\n if (signal?.aborted) {\n throw new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n }\n\n return proofToken;\n}\n"],"mappings":";;;;;;;;;;;;;AA+CA,MAAa,wCAAwC;;;;;;;AAQrD,MAAM,oCAAoC;AAE1C,SAAS,qBAAqB,YAAwC;CACpE,IAAI,OAAO,eAAe,YAAY,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,GAClF,OAAO;CAET,OAAO,KAAK,IAAI,YAAY,iCAAiC;AAC/D;;;;;;;;;;;;;;;;;AAkBA,SAAS,kBACP,KACA,WACA,QACkC;CAClC,IAAI;CACJ,IAAI;CAEJ,MAAM,SAAS,IAAI,SAAgB,GAAG,WAAW;EAC/C,YAAY,iBAAiB,uBAAO,IAAI,MAAM,qCAAqC,CAAC,GAAG,SAAS;CAClG,CAAC;CACD,MAAM,UAAU,IAAI,SAAgB,GAAG,WAAW;EAChD,IAAI,CAAC,QACH;EAEF,gBAAgB,uBAAO,IAAI,MAAM,mCAAmC,CAAC;EACrE,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;CAED,OAAO,QAAQ,KAAK;EAAC;;GAAiC;;EAAM;EAAQ;CAAO,CAAC,CAAC,CAAC,cAAc;EAC1F,aAAa,SAAS;EACtB,IAAI,UAAU,SACZ,OAAO,oBAAoB,SAAS,OAAO;CAE/C,CAAC;AACH;;;;;;;;;;;;;;;AAyBA,SAAS,kBAAkB,QAAqB;CAC9C,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,MAAM;CACzB,QAAQ;EACN,MAAM,IAAI,kBAAkB,4CAA4C,EACtE,MAAM,gCACR,CAAC;CACH;CACA,IAAI,OAAO,aAAa,UACtB,MAAM,IAAI,kBAAkB,wCAAwC,EAClE,MAAM,gCACR,CAAC;CAEH,IAAI,OAAO,YAAY,OAAO,UAC5B,MAAM,IAAI,kBAAkB,sDAAsD,EAChF,MAAM,gCACR,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;AAuBA,eAAsB,oBACpB,cACA,WACA,UAAsC,CAAC,GACtB;CACjB,MAAM,EAAE,QAAQ,kBAAkB,kBAAkB;CACpD,MAAM,EAAE,QAAQ,OAAO,YAAY;CAEnC,MAAM,YAAY,kBAAkB,MAAM;CAE1C,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,kBAAkB,UAAU,SAAS,GAAG,qBAAqB,aAAa,GAAG,MAAM;CACjG,QAAQ;EAIN,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAIlG,MAAM,IAAI,kBACR,yMAGA,EAAE,MAAM,mCAAmC,CAC7C;CACF;CAEA,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,IAAI,OAAO,IAAI,YAAY,YACzB,MAAM,IAAI,kBAAkB,2DAA2D,EACrF,MAAM,+BACR,CAAC;CAGH,IAAI;CACJ,IAAI;EACF,aAAa,MAAO,IAAI,QAA0B,WAAW;GAAE;GAAO;GAAS;GAAQ;EAAiB,CAAC;CAC3G,SAAS,KAAK;EAIZ,MAAM,iBAAiB,eAAe,SAAS,IAAI,SAAS;EAC5D,IAAI,QAAQ,WAAW,gBACrB,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;EAGlG,MAAM,IAAI,kBAAkB,0CADX,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACkB,EAChF,MAAM,iCACR,CAAC;CACH;CAIA,IAAI,QAAQ,SACV,MAAM,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;CAGlG,OAAO;AACT"}
@@ -140,7 +140,7 @@ const clerkJSScriptUrl = (opts) => {
140
140
  const clerkUIScriptUrl = (opts) => {
141
141
  const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;
142
142
  if (__internal_clerkUIUrl) return __internal_clerkUIUrl;
143
- const version = require_versionSelector.versionSelector(__internal_clerkUIVersion, "1.30.8-canary.v20260824165645");
143
+ const version = require_versionSelector.versionSelector(__internal_clerkUIVersion, "1.30.8");
144
144
  if (proxyUrl && require_proxy.isProxyUrlRelative(proxyUrl)) return buildRelativeProxyScriptUrl(proxyUrl, "ui", version, "ui.browser.js");
145
145
  return `https://${buildScriptHost({
146
146
  publishableKey,
@@ -1 +1 @@
1
- {"version":3,"file":"loadClerkJsScript.js","names":["createDevOrStagingUrlCache","buildErrorThrower","ClerkRuntimeError","versionSelector","isProxyUrlRelative","isValidProxyUrl","proxyUrlToAbsoluteURL","parsePublishableKey","addClerkPrefix"],"sources":["../src/loadClerkJsScript.ts"],"sourcesContent":["import { buildErrorThrower, ClerkRuntimeError } from './error';\nimport { createDevOrStagingUrlCache, parsePublishableKey } from './keys';\nimport { loadScript } from './loadScript';\nimport { isProxyUrlRelative, isValidProxyUrl, proxyUrlToAbsoluteURL } from './proxy';\nimport type { SDKMetadata } from './types';\nimport { addClerkPrefix } from './url';\nimport { versionSelector } from './versionSelector';\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\n\nconst errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });\n\nexport type LoadClerkJSScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkJSUrl?: string;\n /** @internal */\n __internal_clerkJSVersion?: string;\n sdkMetadata?: SDKMetadata;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n /**\n * Timeout in milliseconds to wait for clerk-js to load before considering it failed.\n *\n * @default 15000 (15 seconds)\n */\n scriptLoadTimeout?: number;\n};\n\n/**\n * @deprecated Use `LoadClerkJSScriptOptions` instead. This alias will be removed in a future major version.\n */\nexport type LoadClerkJsScriptOptions = LoadClerkJSScriptOptions;\n\nexport type LoadClerkUIScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkUIUrl?: string;\n /** @internal */\n __internal_clerkUIVersion?: string;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n scriptLoadTimeout?: number;\n};\n\n/**\n * Validates that window.Clerk exists and is properly initialized.\n * This ensures we don't have false positives where the script loads but Clerk is malformed.\n *\n * @returns `true` if window.Clerk exists and has the expected structure with a load method.\n */\nfunction isClerkGlobalProperlyLoaded(prop: 'Clerk' | '__internal_ClerkUICtor'): boolean {\n if (typeof window === 'undefined' || !(window as any)[prop]) {\n return false;\n }\n\n // Basic validation that window.Clerk has the expected structure\n const val = (window as any)[prop];\n return !!val;\n}\nconst isClerkProperlyLoaded = () => isClerkGlobalProperlyLoaded('Clerk');\nconst isClerkUIProperlyLoaded = () => isClerkGlobalProperlyLoaded('__internal_ClerkUICtor');\n\n/**\n * Checks if an existing script has a request error using Performance API.\n *\n * @param scriptUrl - The URL of the script to check.\n * @returns True if the script has failed to load due to a network/HTTP error.\n */\nfunction hasScriptRequestError(scriptUrl: string): boolean {\n if (typeof window === 'undefined' || !window.performance) {\n return false;\n }\n\n const entries = performance.getEntriesByName(scriptUrl, 'resource') as PerformanceResourceTiming[];\n\n if (entries.length === 0) {\n return false;\n }\n\n const scriptEntry = entries[entries.length - 1];\n\n // transferSize === 0 with responseEnd === 0 indicates network failure\n // transferSize === 0 with responseEnd > 0 might be a 4xx/5xx error or blocked request\n if (scriptEntry.transferSize === 0 && scriptEntry.decodedBodySize === 0) {\n // If there was no response at all, it's definitely an error\n if (scriptEntry.responseEnd === 0) {\n return true;\n }\n // If we got a response but no content, likely an HTTP error (4xx/5xx)\n if (scriptEntry.responseEnd > 0 && scriptEntry.responseStart > 0) {\n return true;\n }\n\n if ('responseStatus' in scriptEntry) {\n const status = (scriptEntry as any).responseStatus;\n if (status >= 400) {\n return true;\n }\n if (scriptEntry.responseStatus === 0) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Hotloads the Clerk JS script with robust failure detection.\n *\n * Uses a timeout-based approach to ensure absolute certainty about load success/failure.\n * If the script fails to load within the timeout period, or loads but doesn't create\n * a proper Clerk instance, the promise rejects with an error.\n *\n * @param opts - The options used to build the Clerk JS script URL and load the script.\n * Must include a `publishableKey` if no existing script is found.\n * @returns Promise that resolves with null if Clerk loads successfully, or rejects with an error.\n *\n * @example\n * ```typescript\n * try {\n * await loadClerkJsScript({ publishableKey: 'pk_test_...' });\n * console.log('Clerk loaded successfully');\n * } catch (error) {\n * console.error('Failed to load Clerk:', error.message);\n * }\n * ```\n */\nexport const loadClerkJSScript = async (opts?: LoadClerkJSScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk JS' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_js',\n cause: error,\n });\n\n if (isClerkProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkJSScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-js-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkJSScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const loadClerkUIScript = async (opts?: LoadClerkUIScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk UI' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_ui',\n cause: error,\n });\n\n if (isClerkUIProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkUIScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-ui-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkUIScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const clerkJSScriptUrl = (opts: LoadClerkJSScriptOptions) => {\n const { __internal_clerkJSUrl, __internal_clerkJSVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkJSUrl) {\n return __internal_clerkJSUrl;\n }\n\n const version = versionSelector(__internal_clerkJSVersion);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'clerk-js', version, 'clerk.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.browser.js`;\n};\n\nexport const clerkUIScriptUrl = (opts: LoadClerkUIScriptOptions) => {\n const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkUIUrl) {\n return __internal_clerkUIUrl;\n }\n\n const version = versionSelector(__internal_clerkUIVersion, UI_PACKAGE_VERSION);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'ui', version, 'ui.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/ui@${version}/dist/ui.browser.js`;\n};\n\nexport const buildClerkJSScriptAttributes = (options: LoadClerkJSScriptOptions) => {\n const obj: Record<string, string> = {};\n\n if (options.publishableKey) {\n obj['data-clerk-publishable-key'] = options.publishableKey;\n }\n\n if (options.proxyUrl) {\n obj['data-clerk-proxy-url'] = options.proxyUrl;\n }\n\n if (options.domain) {\n obj['data-clerk-domain'] = options.domain;\n }\n\n if (options.nonce) {\n obj.nonce = options.nonce;\n }\n\n return obj;\n};\n\nexport const buildClerkUIScriptAttributes = (options: LoadClerkUIScriptOptions) => {\n // TODO @nikos do we need this?\n return buildClerkJSScriptAttributes(options);\n};\n\nconst applyAttributesToScript = (attributes: Record<string, string>) => (script: HTMLScriptElement) => {\n for (const attribute in attributes) {\n script.setAttribute(attribute, attributes[attribute]);\n }\n};\n\nconst stripTrailingSlashes = (value: string) => {\n while (value.endsWith('/')) {\n value = value.slice(0, -1);\n }\n\n return value;\n};\n\nconst buildRelativeProxyScriptUrl = (proxyUrl: string, packageName: string, version: string, fileName: string) => {\n return `${stripTrailingSlashes(proxyUrl)}/npm/@clerk/${packageName}@${version}/dist/${fileName}`;\n};\n\nexport const buildScriptHost = (opts: { publishableKey: string; proxyUrl?: string; domain?: string }) => {\n const { proxyUrl, domain, publishableKey } = opts;\n\n if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {\n const resolvedProxyUrl = proxyUrlToAbsoluteURL(proxyUrl);\n\n if (isProxyUrlRelative(resolvedProxyUrl)) {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n\n return resolvedProxyUrl.replace(/http(s)?:\\/\\//, '');\n } else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {\n return addClerkPrefix(domain);\n } else {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n};\n\nfunction waitForPredicateWithTimeout(\n timeoutMs: number,\n predicate: () => boolean,\n rejectWith: Error,\n existingScript?: HTMLScriptElement,\n): Promise<HTMLScriptElement | null> {\n return new Promise((resolve, reject) => {\n let resolved = false;\n\n const cleanup = (timeoutId: ReturnType<typeof setTimeout>, pollInterval: ReturnType<typeof setInterval>) => {\n clearTimeout(timeoutId);\n clearInterval(pollInterval);\n };\n\n // Bail out early if the script fails to load, instead of waiting for the entire timeout\n existingScript?.addEventListener('error', () => {\n cleanup(timeoutId, pollInterval);\n reject(rejectWith);\n });\n\n const checkAndResolve = () => {\n if (resolved) {\n return;\n }\n\n if (predicate()) {\n resolved = true;\n cleanup(timeoutId, pollInterval);\n resolve(null);\n }\n };\n\n const handleTimeout = () => {\n if (resolved) {\n return;\n }\n\n resolved = true;\n cleanup(timeoutId, pollInterval);\n\n if (!predicate()) {\n reject(rejectWith);\n } else {\n resolve(null);\n }\n };\n\n const timeoutId = setTimeout(handleTimeout, timeoutMs);\n\n checkAndResolve();\n\n const pollInterval = setInterval(() => {\n if (resolved) {\n clearInterval(pollInterval);\n return;\n }\n checkAndResolve();\n }, 100);\n });\n}\n\nexport function setClerkJSLoadingErrorPackageName(packageName: string) {\n errorThrower.setPackageName({ packageName });\n}\n\n/**\n * @deprecated Use `loadClerkJSScript` instead. This alias will be removed in a future major version.\n */\nexport const loadClerkJsScript = loadClerkJSScript;\n\n/**\n * @deprecated Use `clerkJSScriptUrl` instead. This alias will be removed in a future major version.\n */\nexport const clerkJsScriptUrl = clerkJSScriptUrl;\n\n/**\n * @deprecated Use `buildClerkJSScriptAttributes` instead. This alias will be removed in a future major version.\n */\nexport const buildClerkJsScriptAttributes = buildClerkJSScriptAttributes;\n\n/**\n * @deprecated Use `setClerkJSLoadingErrorPackageName` instead. This alias will be removed in a future major version.\n */\nexport const setClerkJsLoadingErrorPackageName = setClerkJSLoadingErrorPackageName;\n"],"mappings":"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"}
1
+ {"version":3,"file":"loadClerkJsScript.js","names":["createDevOrStagingUrlCache","buildErrorThrower","ClerkRuntimeError","versionSelector","isProxyUrlRelative","isValidProxyUrl","proxyUrlToAbsoluteURL","parsePublishableKey","addClerkPrefix"],"sources":["../src/loadClerkJsScript.ts"],"sourcesContent":["import { buildErrorThrower, ClerkRuntimeError } from './error';\nimport { createDevOrStagingUrlCache, parsePublishableKey } from './keys';\nimport { loadScript } from './loadScript';\nimport { isProxyUrlRelative, isValidProxyUrl, proxyUrlToAbsoluteURL } from './proxy';\nimport type { SDKMetadata } from './types';\nimport { addClerkPrefix } from './url';\nimport { versionSelector } from './versionSelector';\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\n\nconst errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });\n\nexport type LoadClerkJSScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkJSUrl?: string;\n /** @internal */\n __internal_clerkJSVersion?: string;\n sdkMetadata?: SDKMetadata;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n /**\n * Timeout in milliseconds to wait for clerk-js to load before considering it failed.\n *\n * @default 15000 (15 seconds)\n */\n scriptLoadTimeout?: number;\n};\n\n/**\n * @deprecated Use `LoadClerkJSScriptOptions` instead. This alias will be removed in a future major version.\n */\nexport type LoadClerkJsScriptOptions = LoadClerkJSScriptOptions;\n\nexport type LoadClerkUIScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkUIUrl?: string;\n /** @internal */\n __internal_clerkUIVersion?: string;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n scriptLoadTimeout?: number;\n};\n\n/**\n * Validates that window.Clerk exists and is properly initialized.\n * This ensures we don't have false positives where the script loads but Clerk is malformed.\n *\n * @returns `true` if window.Clerk exists and has the expected structure with a load method.\n */\nfunction isClerkGlobalProperlyLoaded(prop: 'Clerk' | '__internal_ClerkUICtor'): boolean {\n if (typeof window === 'undefined' || !(window as any)[prop]) {\n return false;\n }\n\n // Basic validation that window.Clerk has the expected structure\n const val = (window as any)[prop];\n return !!val;\n}\nconst isClerkProperlyLoaded = () => isClerkGlobalProperlyLoaded('Clerk');\nconst isClerkUIProperlyLoaded = () => isClerkGlobalProperlyLoaded('__internal_ClerkUICtor');\n\n/**\n * Checks if an existing script has a request error using Performance API.\n *\n * @param scriptUrl - The URL of the script to check.\n * @returns True if the script has failed to load due to a network/HTTP error.\n */\nfunction hasScriptRequestError(scriptUrl: string): boolean {\n if (typeof window === 'undefined' || !window.performance) {\n return false;\n }\n\n const entries = performance.getEntriesByName(scriptUrl, 'resource') as PerformanceResourceTiming[];\n\n if (entries.length === 0) {\n return false;\n }\n\n const scriptEntry = entries[entries.length - 1];\n\n // transferSize === 0 with responseEnd === 0 indicates network failure\n // transferSize === 0 with responseEnd > 0 might be a 4xx/5xx error or blocked request\n if (scriptEntry.transferSize === 0 && scriptEntry.decodedBodySize === 0) {\n // If there was no response at all, it's definitely an error\n if (scriptEntry.responseEnd === 0) {\n return true;\n }\n // If we got a response but no content, likely an HTTP error (4xx/5xx)\n if (scriptEntry.responseEnd > 0 && scriptEntry.responseStart > 0) {\n return true;\n }\n\n if ('responseStatus' in scriptEntry) {\n const status = (scriptEntry as any).responseStatus;\n if (status >= 400) {\n return true;\n }\n if (scriptEntry.responseStatus === 0) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Hotloads the Clerk JS script with robust failure detection.\n *\n * Uses a timeout-based approach to ensure absolute certainty about load success/failure.\n * If the script fails to load within the timeout period, or loads but doesn't create\n * a proper Clerk instance, the promise rejects with an error.\n *\n * @param opts - The options used to build the Clerk JS script URL and load the script.\n * Must include a `publishableKey` if no existing script is found.\n * @returns Promise that resolves with null if Clerk loads successfully, or rejects with an error.\n *\n * @example\n * ```typescript\n * try {\n * await loadClerkJsScript({ publishableKey: 'pk_test_...' });\n * console.log('Clerk loaded successfully');\n * } catch (error) {\n * console.error('Failed to load Clerk:', error.message);\n * }\n * ```\n */\nexport const loadClerkJSScript = async (opts?: LoadClerkJSScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk JS' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_js',\n cause: error,\n });\n\n if (isClerkProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkJSScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-js-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkJSScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const loadClerkUIScript = async (opts?: LoadClerkUIScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk UI' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_ui',\n cause: error,\n });\n\n if (isClerkUIProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkUIScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-ui-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkUIScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const clerkJSScriptUrl = (opts: LoadClerkJSScriptOptions) => {\n const { __internal_clerkJSUrl, __internal_clerkJSVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkJSUrl) {\n return __internal_clerkJSUrl;\n }\n\n const version = versionSelector(__internal_clerkJSVersion);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'clerk-js', version, 'clerk.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.browser.js`;\n};\n\nexport const clerkUIScriptUrl = (opts: LoadClerkUIScriptOptions) => {\n const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkUIUrl) {\n return __internal_clerkUIUrl;\n }\n\n const version = versionSelector(__internal_clerkUIVersion, UI_PACKAGE_VERSION);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'ui', version, 'ui.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/ui@${version}/dist/ui.browser.js`;\n};\n\nexport const buildClerkJSScriptAttributes = (options: LoadClerkJSScriptOptions) => {\n const obj: Record<string, string> = {};\n\n if (options.publishableKey) {\n obj['data-clerk-publishable-key'] = options.publishableKey;\n }\n\n if (options.proxyUrl) {\n obj['data-clerk-proxy-url'] = options.proxyUrl;\n }\n\n if (options.domain) {\n obj['data-clerk-domain'] = options.domain;\n }\n\n if (options.nonce) {\n obj.nonce = options.nonce;\n }\n\n return obj;\n};\n\nexport const buildClerkUIScriptAttributes = (options: LoadClerkUIScriptOptions) => {\n // TODO @nikos do we need this?\n return buildClerkJSScriptAttributes(options);\n};\n\nconst applyAttributesToScript = (attributes: Record<string, string>) => (script: HTMLScriptElement) => {\n for (const attribute in attributes) {\n script.setAttribute(attribute, attributes[attribute]);\n }\n};\n\nconst stripTrailingSlashes = (value: string) => {\n while (value.endsWith('/')) {\n value = value.slice(0, -1);\n }\n\n return value;\n};\n\nconst buildRelativeProxyScriptUrl = (proxyUrl: string, packageName: string, version: string, fileName: string) => {\n return `${stripTrailingSlashes(proxyUrl)}/npm/@clerk/${packageName}@${version}/dist/${fileName}`;\n};\n\nexport const buildScriptHost = (opts: { publishableKey: string; proxyUrl?: string; domain?: string }) => {\n const { proxyUrl, domain, publishableKey } = opts;\n\n if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {\n const resolvedProxyUrl = proxyUrlToAbsoluteURL(proxyUrl);\n\n if (isProxyUrlRelative(resolvedProxyUrl)) {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n\n return resolvedProxyUrl.replace(/http(s)?:\\/\\//, '');\n } else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {\n return addClerkPrefix(domain);\n } else {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n};\n\nfunction waitForPredicateWithTimeout(\n timeoutMs: number,\n predicate: () => boolean,\n rejectWith: Error,\n existingScript?: HTMLScriptElement,\n): Promise<HTMLScriptElement | null> {\n return new Promise((resolve, reject) => {\n let resolved = false;\n\n const cleanup = (timeoutId: ReturnType<typeof setTimeout>, pollInterval: ReturnType<typeof setInterval>) => {\n clearTimeout(timeoutId);\n clearInterval(pollInterval);\n };\n\n // Bail out early if the script fails to load, instead of waiting for the entire timeout\n existingScript?.addEventListener('error', () => {\n cleanup(timeoutId, pollInterval);\n reject(rejectWith);\n });\n\n const checkAndResolve = () => {\n if (resolved) {\n return;\n }\n\n if (predicate()) {\n resolved = true;\n cleanup(timeoutId, pollInterval);\n resolve(null);\n }\n };\n\n const handleTimeout = () => {\n if (resolved) {\n return;\n }\n\n resolved = true;\n cleanup(timeoutId, pollInterval);\n\n if (!predicate()) {\n reject(rejectWith);\n } else {\n resolve(null);\n }\n };\n\n const timeoutId = setTimeout(handleTimeout, timeoutMs);\n\n checkAndResolve();\n\n const pollInterval = setInterval(() => {\n if (resolved) {\n clearInterval(pollInterval);\n return;\n }\n checkAndResolve();\n }, 100);\n });\n}\n\nexport function setClerkJSLoadingErrorPackageName(packageName: string) {\n errorThrower.setPackageName({ packageName });\n}\n\n/**\n * @deprecated Use `loadClerkJSScript` instead. This alias will be removed in a future major version.\n */\nexport const loadClerkJsScript = loadClerkJSScript;\n\n/**\n * @deprecated Use `clerkJSScriptUrl` instead. This alias will be removed in a future major version.\n */\nexport const clerkJsScriptUrl = clerkJSScriptUrl;\n\n/**\n * @deprecated Use `buildClerkJSScriptAttributes` instead. This alias will be removed in a future major version.\n */\nexport const buildClerkJsScriptAttributes = buildClerkJSScriptAttributes;\n\n/**\n * @deprecated Use `setClerkJSLoadingErrorPackageName` instead. This alias will be removed in a future major version.\n */\nexport const setClerkJsLoadingErrorPackageName = setClerkJSLoadingErrorPackageName;\n"],"mappings":"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"}
@@ -139,7 +139,7 @@ const clerkJSScriptUrl = (opts) => {
139
139
  const clerkUIScriptUrl = (opts) => {
140
140
  const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;
141
141
  if (__internal_clerkUIUrl) return __internal_clerkUIUrl;
142
- const version = versionSelector(__internal_clerkUIVersion, "1.30.8-canary.v20260824165645");
142
+ const version = versionSelector(__internal_clerkUIVersion, "1.30.8");
143
143
  if (proxyUrl && isProxyUrlRelative(proxyUrl)) return buildRelativeProxyScriptUrl(proxyUrl, "ui", version, "ui.browser.js");
144
144
  return `https://${buildScriptHost({
145
145
  publishableKey,
@@ -1 +1 @@
1
- {"version":3,"file":"loadClerkJsScript.mjs","names":[],"sources":["../src/loadClerkJsScript.ts"],"sourcesContent":["import { buildErrorThrower, ClerkRuntimeError } from './error';\nimport { createDevOrStagingUrlCache, parsePublishableKey } from './keys';\nimport { loadScript } from './loadScript';\nimport { isProxyUrlRelative, isValidProxyUrl, proxyUrlToAbsoluteURL } from './proxy';\nimport type { SDKMetadata } from './types';\nimport { addClerkPrefix } from './url';\nimport { versionSelector } from './versionSelector';\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\n\nconst errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });\n\nexport type LoadClerkJSScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkJSUrl?: string;\n /** @internal */\n __internal_clerkJSVersion?: string;\n sdkMetadata?: SDKMetadata;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n /**\n * Timeout in milliseconds to wait for clerk-js to load before considering it failed.\n *\n * @default 15000 (15 seconds)\n */\n scriptLoadTimeout?: number;\n};\n\n/**\n * @deprecated Use `LoadClerkJSScriptOptions` instead. This alias will be removed in a future major version.\n */\nexport type LoadClerkJsScriptOptions = LoadClerkJSScriptOptions;\n\nexport type LoadClerkUIScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkUIUrl?: string;\n /** @internal */\n __internal_clerkUIVersion?: string;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n scriptLoadTimeout?: number;\n};\n\n/**\n * Validates that window.Clerk exists and is properly initialized.\n * This ensures we don't have false positives where the script loads but Clerk is malformed.\n *\n * @returns `true` if window.Clerk exists and has the expected structure with a load method.\n */\nfunction isClerkGlobalProperlyLoaded(prop: 'Clerk' | '__internal_ClerkUICtor'): boolean {\n if (typeof window === 'undefined' || !(window as any)[prop]) {\n return false;\n }\n\n // Basic validation that window.Clerk has the expected structure\n const val = (window as any)[prop];\n return !!val;\n}\nconst isClerkProperlyLoaded = () => isClerkGlobalProperlyLoaded('Clerk');\nconst isClerkUIProperlyLoaded = () => isClerkGlobalProperlyLoaded('__internal_ClerkUICtor');\n\n/**\n * Checks if an existing script has a request error using Performance API.\n *\n * @param scriptUrl - The URL of the script to check.\n * @returns True if the script has failed to load due to a network/HTTP error.\n */\nfunction hasScriptRequestError(scriptUrl: string): boolean {\n if (typeof window === 'undefined' || !window.performance) {\n return false;\n }\n\n const entries = performance.getEntriesByName(scriptUrl, 'resource') as PerformanceResourceTiming[];\n\n if (entries.length === 0) {\n return false;\n }\n\n const scriptEntry = entries[entries.length - 1];\n\n // transferSize === 0 with responseEnd === 0 indicates network failure\n // transferSize === 0 with responseEnd > 0 might be a 4xx/5xx error or blocked request\n if (scriptEntry.transferSize === 0 && scriptEntry.decodedBodySize === 0) {\n // If there was no response at all, it's definitely an error\n if (scriptEntry.responseEnd === 0) {\n return true;\n }\n // If we got a response but no content, likely an HTTP error (4xx/5xx)\n if (scriptEntry.responseEnd > 0 && scriptEntry.responseStart > 0) {\n return true;\n }\n\n if ('responseStatus' in scriptEntry) {\n const status = (scriptEntry as any).responseStatus;\n if (status >= 400) {\n return true;\n }\n if (scriptEntry.responseStatus === 0) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Hotloads the Clerk JS script with robust failure detection.\n *\n * Uses a timeout-based approach to ensure absolute certainty about load success/failure.\n * If the script fails to load within the timeout period, or loads but doesn't create\n * a proper Clerk instance, the promise rejects with an error.\n *\n * @param opts - The options used to build the Clerk JS script URL and load the script.\n * Must include a `publishableKey` if no existing script is found.\n * @returns Promise that resolves with null if Clerk loads successfully, or rejects with an error.\n *\n * @example\n * ```typescript\n * try {\n * await loadClerkJsScript({ publishableKey: 'pk_test_...' });\n * console.log('Clerk loaded successfully');\n * } catch (error) {\n * console.error('Failed to load Clerk:', error.message);\n * }\n * ```\n */\nexport const loadClerkJSScript = async (opts?: LoadClerkJSScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk JS' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_js',\n cause: error,\n });\n\n if (isClerkProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkJSScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-js-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkJSScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const loadClerkUIScript = async (opts?: LoadClerkUIScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk UI' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_ui',\n cause: error,\n });\n\n if (isClerkUIProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkUIScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-ui-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkUIScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const clerkJSScriptUrl = (opts: LoadClerkJSScriptOptions) => {\n const { __internal_clerkJSUrl, __internal_clerkJSVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkJSUrl) {\n return __internal_clerkJSUrl;\n }\n\n const version = versionSelector(__internal_clerkJSVersion);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'clerk-js', version, 'clerk.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.browser.js`;\n};\n\nexport const clerkUIScriptUrl = (opts: LoadClerkUIScriptOptions) => {\n const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkUIUrl) {\n return __internal_clerkUIUrl;\n }\n\n const version = versionSelector(__internal_clerkUIVersion, UI_PACKAGE_VERSION);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'ui', version, 'ui.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/ui@${version}/dist/ui.browser.js`;\n};\n\nexport const buildClerkJSScriptAttributes = (options: LoadClerkJSScriptOptions) => {\n const obj: Record<string, string> = {};\n\n if (options.publishableKey) {\n obj['data-clerk-publishable-key'] = options.publishableKey;\n }\n\n if (options.proxyUrl) {\n obj['data-clerk-proxy-url'] = options.proxyUrl;\n }\n\n if (options.domain) {\n obj['data-clerk-domain'] = options.domain;\n }\n\n if (options.nonce) {\n obj.nonce = options.nonce;\n }\n\n return obj;\n};\n\nexport const buildClerkUIScriptAttributes = (options: LoadClerkUIScriptOptions) => {\n // TODO @nikos do we need this?\n return buildClerkJSScriptAttributes(options);\n};\n\nconst applyAttributesToScript = (attributes: Record<string, string>) => (script: HTMLScriptElement) => {\n for (const attribute in attributes) {\n script.setAttribute(attribute, attributes[attribute]);\n }\n};\n\nconst stripTrailingSlashes = (value: string) => {\n while (value.endsWith('/')) {\n value = value.slice(0, -1);\n }\n\n return value;\n};\n\nconst buildRelativeProxyScriptUrl = (proxyUrl: string, packageName: string, version: string, fileName: string) => {\n return `${stripTrailingSlashes(proxyUrl)}/npm/@clerk/${packageName}@${version}/dist/${fileName}`;\n};\n\nexport const buildScriptHost = (opts: { publishableKey: string; proxyUrl?: string; domain?: string }) => {\n const { proxyUrl, domain, publishableKey } = opts;\n\n if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {\n const resolvedProxyUrl = proxyUrlToAbsoluteURL(proxyUrl);\n\n if (isProxyUrlRelative(resolvedProxyUrl)) {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n\n return resolvedProxyUrl.replace(/http(s)?:\\/\\//, '');\n } else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {\n return addClerkPrefix(domain);\n } else {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n};\n\nfunction waitForPredicateWithTimeout(\n timeoutMs: number,\n predicate: () => boolean,\n rejectWith: Error,\n existingScript?: HTMLScriptElement,\n): Promise<HTMLScriptElement | null> {\n return new Promise((resolve, reject) => {\n let resolved = false;\n\n const cleanup = (timeoutId: ReturnType<typeof setTimeout>, pollInterval: ReturnType<typeof setInterval>) => {\n clearTimeout(timeoutId);\n clearInterval(pollInterval);\n };\n\n // Bail out early if the script fails to load, instead of waiting for the entire timeout\n existingScript?.addEventListener('error', () => {\n cleanup(timeoutId, pollInterval);\n reject(rejectWith);\n });\n\n const checkAndResolve = () => {\n if (resolved) {\n return;\n }\n\n if (predicate()) {\n resolved = true;\n cleanup(timeoutId, pollInterval);\n resolve(null);\n }\n };\n\n const handleTimeout = () => {\n if (resolved) {\n return;\n }\n\n resolved = true;\n cleanup(timeoutId, pollInterval);\n\n if (!predicate()) {\n reject(rejectWith);\n } else {\n resolve(null);\n }\n };\n\n const timeoutId = setTimeout(handleTimeout, timeoutMs);\n\n checkAndResolve();\n\n const pollInterval = setInterval(() => {\n if (resolved) {\n clearInterval(pollInterval);\n return;\n }\n checkAndResolve();\n }, 100);\n });\n}\n\nexport function setClerkJSLoadingErrorPackageName(packageName: string) {\n errorThrower.setPackageName({ packageName });\n}\n\n/**\n * @deprecated Use `loadClerkJSScript` instead. This alias will be removed in a future major version.\n */\nexport const loadClerkJsScript = loadClerkJSScript;\n\n/**\n * @deprecated Use `clerkJSScriptUrl` instead. This alias will be removed in a future major version.\n */\nexport const clerkJsScriptUrl = clerkJSScriptUrl;\n\n/**\n * @deprecated Use `buildClerkJSScriptAttributes` instead. This alias will be removed in a future major version.\n */\nexport const buildClerkJsScriptAttributes = buildClerkJSScriptAttributes;\n\n/**\n * @deprecated Use `setClerkJSLoadingErrorPackageName` instead. This alias will be removed in a future major version.\n */\nexport const setClerkJsLoadingErrorPackageName = setClerkJSLoadingErrorPackageName;\n"],"mappings":"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"}
1
+ {"version":3,"file":"loadClerkJsScript.mjs","names":[],"sources":["../src/loadClerkJsScript.ts"],"sourcesContent":["import { buildErrorThrower, ClerkRuntimeError } from './error';\nimport { createDevOrStagingUrlCache, parsePublishableKey } from './keys';\nimport { loadScript } from './loadScript';\nimport { isProxyUrlRelative, isValidProxyUrl, proxyUrlToAbsoluteURL } from './proxy';\nimport type { SDKMetadata } from './types';\nimport { addClerkPrefix } from './url';\nimport { versionSelector } from './versionSelector';\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\n\nconst errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });\n\nexport type LoadClerkJSScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkJSUrl?: string;\n /** @internal */\n __internal_clerkJSVersion?: string;\n sdkMetadata?: SDKMetadata;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n /**\n * Timeout in milliseconds to wait for clerk-js to load before considering it failed.\n *\n * @default 15000 (15 seconds)\n */\n scriptLoadTimeout?: number;\n};\n\n/**\n * @deprecated Use `LoadClerkJSScriptOptions` instead. This alias will be removed in a future major version.\n */\nexport type LoadClerkJsScriptOptions = LoadClerkJSScriptOptions;\n\nexport type LoadClerkUIScriptOptions = {\n publishableKey: string;\n /** @internal */\n __internal_clerkUIUrl?: string;\n /** @internal */\n __internal_clerkUIVersion?: string;\n proxyUrl?: string;\n domain?: string;\n nonce?: string;\n scriptLoadTimeout?: number;\n};\n\n/**\n * Validates that window.Clerk exists and is properly initialized.\n * This ensures we don't have false positives where the script loads but Clerk is malformed.\n *\n * @returns `true` if window.Clerk exists and has the expected structure with a load method.\n */\nfunction isClerkGlobalProperlyLoaded(prop: 'Clerk' | '__internal_ClerkUICtor'): boolean {\n if (typeof window === 'undefined' || !(window as any)[prop]) {\n return false;\n }\n\n // Basic validation that window.Clerk has the expected structure\n const val = (window as any)[prop];\n return !!val;\n}\nconst isClerkProperlyLoaded = () => isClerkGlobalProperlyLoaded('Clerk');\nconst isClerkUIProperlyLoaded = () => isClerkGlobalProperlyLoaded('__internal_ClerkUICtor');\n\n/**\n * Checks if an existing script has a request error using Performance API.\n *\n * @param scriptUrl - The URL of the script to check.\n * @returns True if the script has failed to load due to a network/HTTP error.\n */\nfunction hasScriptRequestError(scriptUrl: string): boolean {\n if (typeof window === 'undefined' || !window.performance) {\n return false;\n }\n\n const entries = performance.getEntriesByName(scriptUrl, 'resource') as PerformanceResourceTiming[];\n\n if (entries.length === 0) {\n return false;\n }\n\n const scriptEntry = entries[entries.length - 1];\n\n // transferSize === 0 with responseEnd === 0 indicates network failure\n // transferSize === 0 with responseEnd > 0 might be a 4xx/5xx error or blocked request\n if (scriptEntry.transferSize === 0 && scriptEntry.decodedBodySize === 0) {\n // If there was no response at all, it's definitely an error\n if (scriptEntry.responseEnd === 0) {\n return true;\n }\n // If we got a response but no content, likely an HTTP error (4xx/5xx)\n if (scriptEntry.responseEnd > 0 && scriptEntry.responseStart > 0) {\n return true;\n }\n\n if ('responseStatus' in scriptEntry) {\n const status = (scriptEntry as any).responseStatus;\n if (status >= 400) {\n return true;\n }\n if (scriptEntry.responseStatus === 0) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Hotloads the Clerk JS script with robust failure detection.\n *\n * Uses a timeout-based approach to ensure absolute certainty about load success/failure.\n * If the script fails to load within the timeout period, or loads but doesn't create\n * a proper Clerk instance, the promise rejects with an error.\n *\n * @param opts - The options used to build the Clerk JS script URL and load the script.\n * Must include a `publishableKey` if no existing script is found.\n * @returns Promise that resolves with null if Clerk loads successfully, or rejects with an error.\n *\n * @example\n * ```typescript\n * try {\n * await loadClerkJsScript({ publishableKey: 'pk_test_...' });\n * console.log('Clerk loaded successfully');\n * } catch (error) {\n * console.error('Failed to load Clerk:', error.message);\n * }\n * ```\n */\nexport const loadClerkJSScript = async (opts?: LoadClerkJSScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk JS' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_js',\n cause: error,\n });\n\n if (isClerkProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkJSScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-js-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkJSScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const loadClerkUIScript = async (opts?: LoadClerkUIScriptOptions): Promise<HTMLScriptElement | null> => {\n const timeout = opts?.scriptLoadTimeout ?? 15000;\n const rejectWith = (error?: Error) =>\n new ClerkRuntimeError('Failed to load Clerk UI' + (error?.message ? `, ${error.message}` : ''), {\n code: 'failed_to_load_clerk_ui',\n cause: error,\n });\n\n if (isClerkUIProperlyLoaded()) {\n return null;\n }\n\n if (!opts?.publishableKey) {\n errorThrower.throwMissingPublishableKeyError();\n return null;\n }\n\n const scriptUrl = clerkUIScriptUrl(opts);\n const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-ui-script]');\n\n if (existingScript) {\n if (hasScriptRequestError(scriptUrl)) {\n existingScript.remove();\n } else {\n try {\n await waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith(), existingScript);\n return null;\n } catch {\n existingScript.remove();\n }\n }\n }\n\n const loadPromise = waitForPredicateWithTimeout(timeout, isClerkUIProperlyLoaded, rejectWith());\n\n loadScript(scriptUrl, {\n async: true,\n crossOrigin: 'anonymous',\n nonce: opts.nonce,\n beforeLoad: applyAttributesToScript(buildClerkUIScriptAttributes(opts)),\n }).catch(error => {\n throw rejectWith(error);\n });\n\n return loadPromise;\n};\n\nexport const clerkJSScriptUrl = (opts: LoadClerkJSScriptOptions) => {\n const { __internal_clerkJSUrl, __internal_clerkJSVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkJSUrl) {\n return __internal_clerkJSUrl;\n }\n\n const version = versionSelector(__internal_clerkJSVersion);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'clerk-js', version, 'clerk.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.browser.js`;\n};\n\nexport const clerkUIScriptUrl = (opts: LoadClerkUIScriptOptions) => {\n const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;\n\n if (__internal_clerkUIUrl) {\n return __internal_clerkUIUrl;\n }\n\n const version = versionSelector(__internal_clerkUIVersion, UI_PACKAGE_VERSION);\n\n if (proxyUrl && isProxyUrlRelative(proxyUrl)) {\n return buildRelativeProxyScriptUrl(proxyUrl, 'ui', version, 'ui.browser.js');\n }\n\n const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });\n return `https://${scriptHost}/npm/@clerk/ui@${version}/dist/ui.browser.js`;\n};\n\nexport const buildClerkJSScriptAttributes = (options: LoadClerkJSScriptOptions) => {\n const obj: Record<string, string> = {};\n\n if (options.publishableKey) {\n obj['data-clerk-publishable-key'] = options.publishableKey;\n }\n\n if (options.proxyUrl) {\n obj['data-clerk-proxy-url'] = options.proxyUrl;\n }\n\n if (options.domain) {\n obj['data-clerk-domain'] = options.domain;\n }\n\n if (options.nonce) {\n obj.nonce = options.nonce;\n }\n\n return obj;\n};\n\nexport const buildClerkUIScriptAttributes = (options: LoadClerkUIScriptOptions) => {\n // TODO @nikos do we need this?\n return buildClerkJSScriptAttributes(options);\n};\n\nconst applyAttributesToScript = (attributes: Record<string, string>) => (script: HTMLScriptElement) => {\n for (const attribute in attributes) {\n script.setAttribute(attribute, attributes[attribute]);\n }\n};\n\nconst stripTrailingSlashes = (value: string) => {\n while (value.endsWith('/')) {\n value = value.slice(0, -1);\n }\n\n return value;\n};\n\nconst buildRelativeProxyScriptUrl = (proxyUrl: string, packageName: string, version: string, fileName: string) => {\n return `${stripTrailingSlashes(proxyUrl)}/npm/@clerk/${packageName}@${version}/dist/${fileName}`;\n};\n\nexport const buildScriptHost = (opts: { publishableKey: string; proxyUrl?: string; domain?: string }) => {\n const { proxyUrl, domain, publishableKey } = opts;\n\n if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {\n const resolvedProxyUrl = proxyUrlToAbsoluteURL(proxyUrl);\n\n if (isProxyUrlRelative(resolvedProxyUrl)) {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n\n return resolvedProxyUrl.replace(/http(s)?:\\/\\//, '');\n } else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {\n return addClerkPrefix(domain);\n } else {\n return parsePublishableKey(publishableKey)?.frontendApi || '';\n }\n};\n\nfunction waitForPredicateWithTimeout(\n timeoutMs: number,\n predicate: () => boolean,\n rejectWith: Error,\n existingScript?: HTMLScriptElement,\n): Promise<HTMLScriptElement | null> {\n return new Promise((resolve, reject) => {\n let resolved = false;\n\n const cleanup = (timeoutId: ReturnType<typeof setTimeout>, pollInterval: ReturnType<typeof setInterval>) => {\n clearTimeout(timeoutId);\n clearInterval(pollInterval);\n };\n\n // Bail out early if the script fails to load, instead of waiting for the entire timeout\n existingScript?.addEventListener('error', () => {\n cleanup(timeoutId, pollInterval);\n reject(rejectWith);\n });\n\n const checkAndResolve = () => {\n if (resolved) {\n return;\n }\n\n if (predicate()) {\n resolved = true;\n cleanup(timeoutId, pollInterval);\n resolve(null);\n }\n };\n\n const handleTimeout = () => {\n if (resolved) {\n return;\n }\n\n resolved = true;\n cleanup(timeoutId, pollInterval);\n\n if (!predicate()) {\n reject(rejectWith);\n } else {\n resolve(null);\n }\n };\n\n const timeoutId = setTimeout(handleTimeout, timeoutMs);\n\n checkAndResolve();\n\n const pollInterval = setInterval(() => {\n if (resolved) {\n clearInterval(pollInterval);\n return;\n }\n checkAndResolve();\n }, 100);\n });\n}\n\nexport function setClerkJSLoadingErrorPackageName(packageName: string) {\n errorThrower.setPackageName({ packageName });\n}\n\n/**\n * @deprecated Use `loadClerkJSScript` instead. This alias will be removed in a future major version.\n */\nexport const loadClerkJsScript = loadClerkJSScript;\n\n/**\n * @deprecated Use `clerkJSScriptUrl` instead. This alias will be removed in a future major version.\n */\nexport const clerkJsScriptUrl = clerkJSScriptUrl;\n\n/**\n * @deprecated Use `buildClerkJSScriptAttributes` instead. This alias will be removed in a future major version.\n */\nexport const buildClerkJsScriptAttributes = buildClerkJSScriptAttributes;\n\n/**\n * @deprecated Use `setClerkJSLoadingErrorPackageName` instead. This alias will be removed in a future major version.\n */\nexport const setClerkJsLoadingErrorPackageName = setClerkJSLoadingErrorPackageName;\n"],"mappings":"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"}
@@ -285,6 +285,15 @@ interface Clerk {
285
285
  * @internal
286
286
  */
287
287
  __internal_moduleManager: ModuleManager | undefined;
288
+ /**
289
+ * The verification-module load timeout asked for by the loader this browser was assigned, or
290
+ * undefined when it asked for nothing. The assignment is randomized per page load, so it cannot
291
+ * be recomputed from the environment config; callers fall back to the instance-wide value on
292
+ * that config, and then to the SDK default.
293
+ *
294
+ * @internal
295
+ */
296
+ __internal_protectChallengeLoadTimeoutMs?: number;
288
297
  frontendApi: string;
289
298
  /** Your Clerk [Publishable Key](!publishable-key). */
290
299
  publishableKey: string;
@@ -285,6 +285,15 @@ interface Clerk {
285
285
  * @internal
286
286
  */
287
287
  __internal_moduleManager: ModuleManager | undefined;
288
+ /**
289
+ * The verification-module load timeout asked for by the loader this browser was assigned, or
290
+ * undefined when it asked for nothing. The assignment is randomized per page load, so it cannot
291
+ * be recomputed from the environment config; callers fall back to the instance-wide value on
292
+ * that config, and then to the SDK default.
293
+ *
294
+ * @internal
295
+ */
296
+ __internal_protectChallengeLoadTimeoutMs?: number;
288
297
  frontendApi: string;
289
298
  /** Your Clerk [Publishable Key](!publishable-key). */
290
299
  publishableKey: string;
@@ -38,11 +38,34 @@ interface ProtectLoader {
38
38
  * 5000 and is capped at 10000 by the SDK, so this cannot stall a sign-in.
39
39
  */
40
40
  token_timeout_ms?: number;
41
+ /**
42
+ * Overrides {@link ProtectConfigJSON.challenge_load_timeout_ms} for browsers that got this
43
+ * loader.
44
+ *
45
+ * Per loader because loaders roll out gradually: while a new one ramps, two are live for the
46
+ * same instance at once, and the new one may need a different value from the one it replaces.
47
+ *
48
+ * Precedence is across the APPLIED SET, not per loader: the first applied loader with a finite,
49
+ * positive value wins, and the instance-wide value applies only when no applied loader specifies
50
+ * such a value. An instance running two loaders at once should therefore either set this on both
51
+ * or on neither — setting it on one makes it apply to browsers that got the other, which is rarely
52
+ * what is meant.
53
+ */
54
+ challenge_load_timeout_ms?: number;
41
55
  }
42
56
  interface ProtectConfigJSON {
43
57
  object: 'protect_config';
44
58
  id: string;
45
59
  loaders?: ProtectLoader[];
60
+ /**
61
+ * How long to wait for a verification module to LOAD before giving up, in milliseconds. Absent
62
+ * means "use the SDK default".
63
+ *
64
+ * It bounds only the load. Once a verification module is running it governs its own duration,
65
+ * so this is not a bound on how long verification may take — the two are deliberately separate
66
+ * budgets, and only the first is the SDK's to set.
67
+ */
68
+ challenge_load_timeout_ms?: number;
46
69
  /**
47
70
  * Unix seconds. A session token acquired while an older value was configured is discarded and
48
71
  * re-acquired, so raising this makes every browser fetch a fresh one as its environment
@@ -60,6 +83,8 @@ interface ProtectConfigResource extends ClerkResource {
60
83
  loaders?: ProtectLoader[];
61
84
  /** See {@link ProtectConfigJSON.tokens_invalid_before}. */
62
85
  tokens_invalid_before?: number;
86
+ /** See {@link ProtectConfigJSON.challenge_load_timeout_ms}. */
87
+ challenge_load_timeout_ms?: number;
63
88
  __internal_toSnapshot: () => ProtectConfigJSONSnapshot;
64
89
  }
65
90
  /**
@@ -38,11 +38,34 @@ interface ProtectLoader {
38
38
  * 5000 and is capped at 10000 by the SDK, so this cannot stall a sign-in.
39
39
  */
40
40
  token_timeout_ms?: number;
41
+ /**
42
+ * Overrides {@link ProtectConfigJSON.challenge_load_timeout_ms} for browsers that got this
43
+ * loader.
44
+ *
45
+ * Per loader because loaders roll out gradually: while a new one ramps, two are live for the
46
+ * same instance at once, and the new one may need a different value from the one it replaces.
47
+ *
48
+ * Precedence is across the APPLIED SET, not per loader: the first applied loader with a finite,
49
+ * positive value wins, and the instance-wide value applies only when no applied loader specifies
50
+ * such a value. An instance running two loaders at once should therefore either set this on both
51
+ * or on neither — setting it on one makes it apply to browsers that got the other, which is rarely
52
+ * what is meant.
53
+ */
54
+ challenge_load_timeout_ms?: number;
41
55
  }
42
56
  interface ProtectConfigJSON {
43
57
  object: 'protect_config';
44
58
  id: string;
45
59
  loaders?: ProtectLoader[];
60
+ /**
61
+ * How long to wait for a verification module to LOAD before giving up, in milliseconds. Absent
62
+ * means "use the SDK default".
63
+ *
64
+ * It bounds only the load. Once a verification module is running it governs its own duration,
65
+ * so this is not a bound on how long verification may take — the two are deliberately separate
66
+ * budgets, and only the first is the SDK's to set.
67
+ */
68
+ challenge_load_timeout_ms?: number;
46
69
  /**
47
70
  * Unix seconds. A session token acquired while an older value was configured is discarded and
48
71
  * re-acquired, so raising this makes every browser fetch a fresh one as its environment
@@ -60,6 +83,8 @@ interface ProtectConfigResource extends ClerkResource {
60
83
  loaders?: ProtectLoader[];
61
84
  /** See {@link ProtectConfigJSON.tokens_invalid_before}. */
62
85
  tokens_invalid_before?: number;
86
+ /** See {@link ProtectConfigJSON.challenge_load_timeout_ms}. */
87
+ challenge_load_timeout_ms?: number;
63
88
  __internal_toSnapshot: () => ProtectConfigJSONSnapshot;
64
89
  }
65
90
  /**
@@ -12,7 +12,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
12
12
  * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided
13
13
  * @returns The npm tag, version or major version to use
14
14
  */
15
- const versionSelector = (clerkJSVersion, packageVersion = "6.30.1-canary.v20260824165645") => {
15
+ const versionSelector = (clerkJSVersion, packageVersion = "6.30.1") => {
16
16
  if (clerkJSVersion) return clerkJSVersion;
17
17
  const prereleaseTag = getPrereleaseTag(packageVersion);
18
18
  if (prereleaseTag) {
@@ -1 +1 @@
1
- {"version":3,"file":"versionSelector.js","names":[],"sources":["../src/versionSelector.ts"],"sourcesContent":["/**\n * This version selector is a bit complicated, so here is the flow:\n * 1. Use the clerkJSVersion prop on the provider\n * 2. Use the exact `@clerk/clerk-js` version if it is a `@snapshot` prerelease\n * 3. Use the prerelease tag of `@clerk/clerk-js` or the packageVersion provided\n * 4. Fallback to the major version of `@clerk/clerk-js` or the packageVersion provided\n *\n * @param clerkJSVersion - The optional clerkJSVersion prop on the provider\n * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided\n * @returns The npm tag, version or major version to use\n */\nexport const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => {\n if (clerkJSVersion) {\n return clerkJSVersion;\n }\n\n const prereleaseTag = getPrereleaseTag(packageVersion);\n if (prereleaseTag) {\n if (prereleaseTag === 'snapshot') {\n return packageVersion;\n }\n\n return prereleaseTag;\n }\n\n return getMajorVersion(packageVersion);\n};\n\nconst getPrereleaseTag = (packageVersion: string) =>\n packageVersion\n .trim()\n .replace(/^v/, '')\n .match(/-(.+?)(\\.|$)/)?.[1];\n\nexport const getMajorVersion = (packageVersion: string) => packageVersion.trim().replace(/^v/, '').split('.')[0];\n"],"mappings":";;;;;;;;;;;;;;AAWA,MAAa,mBAAmB,gBAAoC,qDAAwC;CAC1G,IAAI,gBACF,OAAO;CAGT,MAAM,gBAAgB,iBAAiB,cAAc;CACrD,IAAI,eAAe;EACjB,IAAI,kBAAkB,YACpB,OAAO;EAGT,OAAO;CACT;CAEA,OAAO,gBAAgB,cAAc;AACvC;AAEA,MAAM,oBAAoB,mBACxB,eACG,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE,CAAC,CACjB,MAAM,cAAc,CAAC,GAAG;AAE7B,MAAa,mBAAmB,mBAA2B,eAAe,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"versionSelector.js","names":[],"sources":["../src/versionSelector.ts"],"sourcesContent":["/**\n * This version selector is a bit complicated, so here is the flow:\n * 1. Use the clerkJSVersion prop on the provider\n * 2. Use the exact `@clerk/clerk-js` version if it is a `@snapshot` prerelease\n * 3. Use the prerelease tag of `@clerk/clerk-js` or the packageVersion provided\n * 4. Fallback to the major version of `@clerk/clerk-js` or the packageVersion provided\n *\n * @param clerkJSVersion - The optional clerkJSVersion prop on the provider\n * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided\n * @returns The npm tag, version or major version to use\n */\nexport const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => {\n if (clerkJSVersion) {\n return clerkJSVersion;\n }\n\n const prereleaseTag = getPrereleaseTag(packageVersion);\n if (prereleaseTag) {\n if (prereleaseTag === 'snapshot') {\n return packageVersion;\n }\n\n return prereleaseTag;\n }\n\n return getMajorVersion(packageVersion);\n};\n\nconst getPrereleaseTag = (packageVersion: string) =>\n packageVersion\n .trim()\n .replace(/^v/, '')\n .match(/-(.+?)(\\.|$)/)?.[1];\n\nexport const getMajorVersion = (packageVersion: string) => packageVersion.trim().replace(/^v/, '').split('.')[0];\n"],"mappings":";;;;;;;;;;;;;;AAWA,MAAa,mBAAmB,gBAAoC,8BAAwC;CAC1G,IAAI,gBACF,OAAO;CAGT,MAAM,gBAAgB,iBAAiB,cAAc;CACrD,IAAI,eAAe;EACjB,IAAI,kBAAkB,YACpB,OAAO;EAGT,OAAO;CACT;CAEA,OAAO,gBAAgB,cAAc;AACvC;AAEA,MAAM,oBAAoB,mBACxB,eACG,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE,CAAC,CACjB,MAAM,cAAc,CAAC,GAAG;AAE7B,MAAa,mBAAmB,mBAA2B,eAAe,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC"}
@@ -10,7 +10,7 @@
10
10
  * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided
11
11
  * @returns The npm tag, version or major version to use
12
12
  */
13
- const versionSelector = (clerkJSVersion, packageVersion = "6.30.1-canary.v20260824165645") => {
13
+ const versionSelector = (clerkJSVersion, packageVersion = "6.30.1") => {
14
14
  if (clerkJSVersion) return clerkJSVersion;
15
15
  const prereleaseTag = getPrereleaseTag(packageVersion);
16
16
  if (prereleaseTag) {
@@ -1 +1 @@
1
- {"version":3,"file":"versionSelector.mjs","names":[],"sources":["../src/versionSelector.ts"],"sourcesContent":["/**\n * This version selector is a bit complicated, so here is the flow:\n * 1. Use the clerkJSVersion prop on the provider\n * 2. Use the exact `@clerk/clerk-js` version if it is a `@snapshot` prerelease\n * 3. Use the prerelease tag of `@clerk/clerk-js` or the packageVersion provided\n * 4. Fallback to the major version of `@clerk/clerk-js` or the packageVersion provided\n *\n * @param clerkJSVersion - The optional clerkJSVersion prop on the provider\n * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided\n * @returns The npm tag, version or major version to use\n */\nexport const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => {\n if (clerkJSVersion) {\n return clerkJSVersion;\n }\n\n const prereleaseTag = getPrereleaseTag(packageVersion);\n if (prereleaseTag) {\n if (prereleaseTag === 'snapshot') {\n return packageVersion;\n }\n\n return prereleaseTag;\n }\n\n return getMajorVersion(packageVersion);\n};\n\nconst getPrereleaseTag = (packageVersion: string) =>\n packageVersion\n .trim()\n .replace(/^v/, '')\n .match(/-(.+?)(\\.|$)/)?.[1];\n\nexport const getMajorVersion = (packageVersion: string) => packageVersion.trim().replace(/^v/, '').split('.')[0];\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,mBAAmB,gBAAoC,qDAAwC;CAC1G,IAAI,gBACF,OAAO;CAGT,MAAM,gBAAgB,iBAAiB,cAAc;CACrD,IAAI,eAAe;EACjB,IAAI,kBAAkB,YACpB,OAAO;EAGT,OAAO;CACT;CAEA,OAAO,gBAAgB,cAAc;AACvC;AAEA,MAAM,oBAAoB,mBACxB,eACG,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE,CAAC,CACjB,MAAM,cAAc,CAAC,GAAG;AAE7B,MAAa,mBAAmB,mBAA2B,eAAe,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"versionSelector.mjs","names":[],"sources":["../src/versionSelector.ts"],"sourcesContent":["/**\n * This version selector is a bit complicated, so here is the flow:\n * 1. Use the clerkJSVersion prop on the provider\n * 2. Use the exact `@clerk/clerk-js` version if it is a `@snapshot` prerelease\n * 3. Use the prerelease tag of `@clerk/clerk-js` or the packageVersion provided\n * 4. Fallback to the major version of `@clerk/clerk-js` or the packageVersion provided\n *\n * @param clerkJSVersion - The optional clerkJSVersion prop on the provider\n * @param packageVersion - The version of `@clerk/clerk-js` that will be used if an explicit version is not provided\n * @returns The npm tag, version or major version to use\n */\nexport const versionSelector = (clerkJSVersion: string | undefined, packageVersion = JS_PACKAGE_VERSION) => {\n if (clerkJSVersion) {\n return clerkJSVersion;\n }\n\n const prereleaseTag = getPrereleaseTag(packageVersion);\n if (prereleaseTag) {\n if (prereleaseTag === 'snapshot') {\n return packageVersion;\n }\n\n return prereleaseTag;\n }\n\n return getMajorVersion(packageVersion);\n};\n\nconst getPrereleaseTag = (packageVersion: string) =>\n packageVersion\n .trim()\n .replace(/^v/, '')\n .match(/-(.+?)(\\.|$)/)?.[1];\n\nexport const getMajorVersion = (packageVersion: string) => packageVersion.trim().replace(/^v/, '').split('.')[0];\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,mBAAmB,gBAAoC,8BAAwC;CAC1G,IAAI,gBACF,OAAO;CAGT,MAAM,gBAAgB,iBAAiB,cAAc;CACrD,IAAI,eAAe;EACjB,IAAI,kBAAkB,YACpB,OAAO;EAGT,OAAO;CACT;CAEA,OAAO,gBAAgB,cAAc;AACvC;AAEA,MAAM,oBAAoB,mBACxB,eACG,KAAK,CAAC,CACN,QAAQ,MAAM,EAAE,CAAC,CACjB,MAAM,cAAc,CAAC,GAAG;AAE7B,MAAa,mBAAmB,mBAA2B,eAAe,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clerk/shared",
3
- "version": "4.30.1-canary.v20260824165645",
3
+ "version": "4.30.1",
4
4
  "description": "Internal package utils used by the Clerk SDKs",
5
5
  "repository": {
6
6
  "type": "git",