{"version":3,"file":"keys-DuxzP8MU.mjs","names":["decodedFrontendApi: string"],"sources":["../../src/keys.ts"],"sourcesContent":["import { DEV_OR_STAGING_SUFFIXES, LEGACY_DEV_INSTANCE_SUFFIXES } from './constants';\nimport { isomorphicAtob } from './isomorphicAtob';\nimport { isomorphicBtoa } from './isomorphicBtoa';\nimport type { PublishableKey } from './types';\n\n/**\n * Configuration options for parsing publishable keys.\n */\ntype ParsePublishableKeyOptions = {\n  /** Whether to throw an error if parsing fails */\n  fatal?: boolean;\n  /** Custom domain to use for satellite instances */\n  domain?: string;\n  /** Proxy URL to use instead of the decoded frontend API */\n  proxyUrl?: string;\n  /** Whether this is a satellite instance */\n  isSatellite?: boolean;\n};\n\n/** Prefix used for production publishable keys */\nconst PUBLISHABLE_KEY_LIVE_PREFIX = 'pk_live_';\n\n/** Prefix used for development publishable keys */\nconst PUBLISHABLE_KEY_TEST_PREFIX = 'pk_test_';\n\n/**\n * Regular expression that matches development frontend API keys.\n * Matches patterns like: foo-bar-13.clerk.accounts.dev.\n */\nconst PUBLISHABLE_FRONTEND_API_DEV_REGEX = /^(([a-z]+)-){2}([0-9]{1,2})\\.clerk\\.accounts([a-z.]*)(dev|com)$/i;\n\n/**\n * Converts a frontend API URL into a base64-encoded publishable key.\n *\n * @param frontendApi - The frontend API URL (e.g., 'clerk.example.com').\n * @returns A base64-encoded publishable key with appropriate prefix (pk_live_ or pk_test_).\n */\nexport function buildPublishableKey(frontendApi: string): string {\n  const isDevKey =\n    PUBLISHABLE_FRONTEND_API_DEV_REGEX.test(frontendApi) ||\n    (frontendApi.startsWith('clerk.') && LEGACY_DEV_INSTANCE_SUFFIXES.some(s => frontendApi.endsWith(s)));\n  const keyPrefix = isDevKey ? PUBLISHABLE_KEY_TEST_PREFIX : PUBLISHABLE_KEY_LIVE_PREFIX;\n  return `${keyPrefix}${isomorphicBtoa(`${frontendApi}$`)}`;\n}\n\n/**\n * Validates that a decoded publishable key has the correct format.\n * The decoded value should be a frontend API followed by exactly one '$' at the end.\n *\n * @param decoded - The decoded publishable key string to validate.\n * @returns `true` if the decoded key has valid format, `false` otherwise.\n */\nfunction isValidDecodedPublishableKey(decoded: string): boolean {\n  if (!decoded.endsWith('$')) {\n    return false;\n  }\n\n  const withoutTrailing = decoded.slice(0, -1);\n  if (withoutTrailing.includes('$')) {\n    return false;\n  }\n\n  return withoutTrailing.includes('.');\n}\n\nexport function parsePublishableKey(\n  key: string | undefined,\n  options: ParsePublishableKeyOptions & { fatal: true },\n): PublishableKey;\nexport function parsePublishableKey(\n  key: string | undefined,\n  options?: ParsePublishableKeyOptions,\n): PublishableKey | null;\n/**\n * Parses and validates a publishable key, extracting the frontend API and instance type.\n *\n * @param key - The publishable key to parse.\n * @param options - Configuration options for parsing.\n * @param options.fatal\n * @param options.domain\n * @param options.proxyUrl\n * @param options.isSatellite\n * @returns Parsed publishable key object with instanceType and frontendApi, or null if invalid.\n *\n * @throws {Error} When options.fatal is true and key is missing or invalid.\n */\nexport function parsePublishableKey(\n  key: string | undefined,\n  options: { fatal?: boolean; domain?: string; proxyUrl?: string; isSatellite?: boolean } = {},\n): PublishableKey | null {\n  key = key || '';\n\n  if (!key || !isPublishableKey(key)) {\n    if (options.fatal && !key) {\n      throw new Error(\n        'Publishable key is missing. Ensure that your publishable key is correctly configured. Double-check your environment configuration for your keys, or access them here: https://dashboard.clerk.com/last-active?path=api-keys',\n      );\n    }\n    if (options.fatal && !isPublishableKey(key)) {\n      throw new Error('Publishable key not valid.');\n    }\n    return null;\n  }\n\n  const instanceType = key.startsWith(PUBLISHABLE_KEY_LIVE_PREFIX) ? 'production' : 'development';\n\n  let decodedFrontendApi: string;\n  try {\n    decodedFrontendApi = isomorphicAtob(key.split('_')[2]);\n  } catch {\n    if (options.fatal) {\n      throw new Error('Publishable key not valid: Failed to decode key.');\n    }\n    return null;\n  }\n\n  if (!isValidDecodedPublishableKey(decodedFrontendApi)) {\n    if (options.fatal) {\n      throw new Error('Publishable key not valid: Decoded key has invalid format.');\n    }\n    return null;\n  }\n\n  let frontendApi = decodedFrontendApi.slice(0, -1);\n\n  if (options.proxyUrl) {\n    frontendApi = options.proxyUrl;\n  } else if (instanceType !== 'development' && options.domain && options.isSatellite) {\n    frontendApi = `clerk.${options.domain}`;\n  }\n\n  return {\n    instanceType,\n    frontendApi,\n  };\n}\n\n/**\n * Checks if the provided key is a valid publishable key.\n *\n * @param key - The key to be checked. Defaults to an empty string if not provided.\n * @returns `true` if 'key' is a valid publishable key, `false` otherwise.\n */\nexport function isPublishableKey(key: string = '') {\n  try {\n    const hasValidPrefix = key.startsWith(PUBLISHABLE_KEY_LIVE_PREFIX) || key.startsWith(PUBLISHABLE_KEY_TEST_PREFIX);\n\n    if (!hasValidPrefix) {\n      return false;\n    }\n\n    const parts = key.split('_');\n    if (parts.length !== 3) {\n      return false;\n    }\n\n    const encodedPart = parts[2];\n    if (!encodedPart) {\n      return false;\n    }\n\n    const decoded = isomorphicAtob(encodedPart);\n    return isValidDecodedPublishableKey(decoded);\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Creates a memoized cache for checking if URLs are development or staging environments.\n * Uses a Map to cache results for better performance on repeated checks.\n *\n * @returns An object with an isDevOrStagingUrl method that checks if a URL is dev/staging.\n */\nexport function createDevOrStagingUrlCache() {\n  const devOrStagingUrlCache = new Map<string, boolean>();\n\n  return {\n    /**\n     * Checks if a URL is a development or staging environment.\n     *\n     * @param url - The URL to check (string or URL object).\n     * @returns `true` if the URL is a development or staging environment, `false` otherwise.\n     */\n    isDevOrStagingUrl: (url: string | URL): boolean => {\n      if (!url) {\n        return false;\n      }\n\n      const hostname = typeof url === 'string' ? url : url.hostname;\n      let res = devOrStagingUrlCache.get(hostname);\n      if (res === undefined) {\n        res = DEV_OR_STAGING_SUFFIXES.some(s => hostname.endsWith(s));\n        devOrStagingUrlCache.set(hostname, res);\n      }\n      return res;\n    },\n  };\n}\n\n/**\n * Checks if a publishable key is for a development environment.\n * Supports both legacy format (test_) and new format (pk_test_).\n *\n * @param apiKey - The API key to check.\n * @returns `true` if the key is for development, `false` otherwise.\n */\nexport function isDevelopmentFromPublishableKey(apiKey: string): boolean {\n  return apiKey.startsWith('test_') || apiKey.startsWith('pk_test_');\n}\n\n/**\n * Checks if a publishable key is for a production environment.\n * Supports both legacy format (live_) and new format (pk_live_).\n *\n * @param apiKey - The API key to check.\n * @returns `true` if the key is for production, `false` otherwise.\n */\nexport function isProductionFromPublishableKey(apiKey: string): boolean {\n  return apiKey.startsWith('live_') || apiKey.startsWith('pk_live_');\n}\n\n/**\n * Checks if a secret key is for a development environment.\n * Supports both legacy format (test_) and new format (sk_test_).\n *\n * @param apiKey - The secret key to check.\n * @returns `true` if the key is for development, `false` otherwise.\n */\nexport function isDevelopmentFromSecretKey(apiKey: string): boolean {\n  return apiKey.startsWith('test_') || apiKey.startsWith('sk_test_');\n}\n\n/**\n * Checks if a secret key is for a production environment.\n * Supports both legacy format (live_) and new format (sk_live_).\n *\n * @param apiKey - The secret key to check.\n * @returns `true` if the key is for production, `false` otherwise.\n */\nexport function isProductionFromSecretKey(apiKey: string): boolean {\n  return apiKey.startsWith('live_') || apiKey.startsWith('sk_live_');\n}\n\n/**\n * Generates a unique cookie suffix based on the publishable key using SHA-1 hashing.\n * The suffix is base64-encoded and URL-safe (+ and / characters are replaced).\n *\n * @param publishableKey - The publishable key to generate suffix from.\n * @param subtle - The SubtleCrypto interface to use for hashing (defaults to globalThis.crypto.subtle).\n * @returns A promise that resolves to an 8-character URL-safe base64 string.\n */\nexport async function getCookieSuffix(\n  publishableKey: string,\n  subtle: SubtleCrypto = globalThis.crypto.subtle,\n): Promise<string> {\n  const data = new TextEncoder().encode(publishableKey);\n  const digest = await subtle.digest('sha-1', data);\n  const stringDigest = String.fromCharCode(...new Uint8Array(digest));\n  // Base 64 Encoding with URL and Filename Safe Alphabet: https://datatracker.ietf.org/doc/html/rfc4648#section-5\n  return isomorphicBtoa(stringDigest).replace(/\\+/gi, '-').replace(/\\//gi, '_').substring(0, 8);\n}\n\n/**\n * Creates a suffixed cookie name by appending the cookie suffix to the base name.\n * Used to create unique cookie names based on the publishable key.\n *\n * @param cookieName - The base cookie name.\n * @param cookieSuffix - The suffix to append (typically generated by getCookieSuffix).\n * @returns The suffixed cookie name in format: `${cookieName}_${cookieSuffix}`.\n */\nexport const getSuffixedCookieName = (cookieName: string, cookieSuffix: string): string => {\n  return `${cookieName}_${cookieSuffix}`;\n};\n"],"mappings":"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"}