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