{"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"}