{"version":3,"sources":["../src/loadClerkJsScript.ts"],"sourcesContent":["import type { ClerkOptions, SDKMetadata, Without } from '@clerk/types';\n\nimport { buildErrorThrower } from './error';\nimport { createDevOrStagingUrlCache, parsePublishableKey } from './keys';\nimport { loadScript } from './loadScript';\nimport { isValidProxyUrl, proxyUrlToAbsoluteURL } from './proxy';\nimport { addClerkPrefix } from './url';\nimport { versionSelector } from './versionSelector';\n\nconst FAILED_TO_LOAD_ERROR = 'Clerk: Failed to load Clerk';\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\n\nconst errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });\n\n/**\n * Sets the package name for error messages during ClerkJS script loading.\n *\n * @param packageName - The name of the package to use in error messages (e.g., '@clerk/clerk-react').\n * @example\n * ```typescript\n * setClerkJsLoadingErrorPackageName('@clerk/clerk-react');\n * ```\n */\nexport function setClerkJsLoadingErrorPackageName(packageName: string) {\n  errorThrower.setPackageName({ packageName });\n}\n\ntype LoadClerkJsScriptOptions = Without<ClerkOptions, 'isSatellite'> & {\n  publishableKey: string;\n  clerkJSUrl?: string;\n  clerkJSVariant?: 'headless' | '';\n  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 * 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 isClerkProperlyLoaded(): boolean {\n  if (typeof window === 'undefined' || !(window as any).Clerk) {\n    return false;\n  }\n\n  // Basic validation that window.Clerk has the expected structure\n  const clerk = (window as any).Clerk;\n  return typeof clerk === 'object' && typeof clerk.load === 'function';\n}\n\n/**\n * Waits for Clerk to be properly loaded with a timeout mechanism.\n * Uses polling to check if Clerk becomes available within the specified timeout.\n *\n * @param timeoutMs - Maximum time to wait in milliseconds.\n * @returns Promise that resolves with null if Clerk loads successfully, or rejects with an error if timeout is reached.\n */\nfunction waitForClerkWithTimeout(timeoutMs: number): 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    const checkAndResolve = () => {\n      if (resolved) return;\n\n      if (isClerkProperlyLoaded()) {\n        resolved = true;\n        cleanup(timeoutId, pollInterval);\n        resolve(null);\n      }\n    };\n\n    const handleTimeout = () => {\n      if (resolved) return;\n\n      resolved = true;\n      cleanup(timeoutId, pollInterval);\n\n      if (!isClerkProperlyLoaded()) {\n        reject(new Error(FAILED_TO_LOAD_ERROR));\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\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 */\nconst loadClerkJsScript = async (opts?: LoadClerkJsScriptOptions): Promise<HTMLScriptElement | null> => {\n  const timeout = opts?.scriptLoadTimeout ?? 15000;\n\n  if (isClerkProperlyLoaded()) {\n    return null;\n  }\n\n  const existingScript = document.querySelector<HTMLScriptElement>('script[data-clerk-js-script]');\n\n  if (existingScript) {\n    return waitForClerkWithTimeout(timeout);\n  }\n\n  if (!opts?.publishableKey) {\n    errorThrower.throwMissingPublishableKeyError();\n    return null;\n  }\n\n  const loadPromise = waitForClerkWithTimeout(timeout);\n\n  loadScript(clerkJsScriptUrl(opts), {\n    async: true,\n    crossOrigin: 'anonymous',\n    nonce: opts.nonce,\n    beforeLoad: applyClerkJsScriptAttributes(opts),\n  }).catch(() => {\n    throw new Error(FAILED_TO_LOAD_ERROR);\n  });\n\n  return loadPromise;\n};\n\n/**\n * Generates a Clerk JS script URL based on the provided options.\n *\n * @param opts - The options to use when building the Clerk JS script URL.\n * @returns The complete URL to the Clerk JS script.\n *\n * @example\n * ```typescript\n * const url = clerkJsScriptUrl({ publishableKey: 'pk_test_...' });\n * // Returns: \"https://example.clerk.accounts.dev/npm/@clerk/clerk-js@5/dist/clerk.browser.js\"\n * ```\n */\nconst clerkJsScriptUrl = (opts: LoadClerkJsScriptOptions) => {\n  const { clerkJSUrl, clerkJSVariant, clerkJSVersion, proxyUrl, domain, publishableKey } = opts;\n\n  if (clerkJSUrl) {\n    return clerkJSUrl;\n  }\n\n  let scriptHost = '';\n  if (!!proxyUrl && isValidProxyUrl(proxyUrl)) {\n    scriptHost = proxyUrlToAbsoluteURL(proxyUrl).replace(/http(s)?:\\/\\//, '');\n  } else if (domain && !isDevOrStagingUrl(parsePublishableKey(publishableKey)?.frontendApi || '')) {\n    scriptHost = addClerkPrefix(domain);\n  } else {\n    scriptHost = parsePublishableKey(publishableKey)?.frontendApi || '';\n  }\n\n  const variant = clerkJSVariant ? `${clerkJSVariant.replace(/\\.+$/, '')}.` : '';\n  const version = versionSelector(clerkJSVersion);\n  return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.${variant}browser.js`;\n};\n\n/**\n * Builds an object of Clerk JS script attributes based on the provided options.\n *\n * @param options - The options containing the values for script attributes.\n * @returns An object containing data attributes to be applied to the script element.\n */\nconst 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\n/**\n * Returns a function that applies Clerk JS script attributes to a script element.\n *\n * @param options - The options containing the values for script attributes.\n * @returns A function that accepts a script element and applies the attributes to it.\n */\nconst applyClerkJsScriptAttributes = (options: LoadClerkJsScriptOptions) => (script: HTMLScriptElement) => {\n  const attributes = buildClerkJsScriptAttributes(options);\n  for (const attribute in attributes) {\n    script.setAttribute(attribute, attributes[attribute]);\n  }\n};\n\nexport { loadClerkJsScript, buildClerkJsScriptAttributes, clerkJsScriptUrl };\nexport type { LoadClerkJsScriptOptions };\n"],"mappings":"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","names":["timeoutId","pollInterval"]}