{"version":3,"file":"telemetry-DE2JFEBf.mjs","names":["#cache","#generateKey","#cacheTtl","sanitizedEvent: Omit<TelemetryEvent, 'sk' | 'pk' | 'payload'> & TelemetryEvent['payload']","#getCache","#storageKey","err: unknown","#maxSize","DEFAULT_CONFIG: Partial<TelemetryCollectorConfig>","#config","#metadata","#eventThrottler","#preparePayload","#logEvent","#shouldRecord","#buffer","#scheduleFlush","#shouldRecordLog","normalizedTimestamp: Date | null","timestampInput: unknown","#getSDKMetadata","logData: TelemetryLogData","#sanitizeContext","#shouldBeSampled","#flush","#pendingFlush","EVENT_SAMPLING_RATE","EVENT_SAMPLING_RATE","EVENT_SAMPLING_RATE","themeName: string | undefined"],"sources":["../../src/telemetry/throttler.ts","../../src/telemetry/collector.ts","../../src/telemetry/events/component-mounted.ts","../../src/telemetry/events/method-called.ts","../../src/telemetry/events/framework-metadata.ts","../../src/telemetry/events/theme-usage.ts"],"sourcesContent":["import type { TelemetryEvent } from '../types';\n\ntype TtlInMilliseconds = number;\n\nconst DEFAULT_CACHE_TTL_MS = 86400000; // 24 hours\n\n/**\n * Interface for cache storage used by the telemetry throttler.\n * Implementations can use localStorage, in-memory storage, or any other storage mechanism.\n */\nexport interface ThrottlerCache {\n  getItem(key: string): TtlInMilliseconds | undefined;\n  setItem(key: string, value: TtlInMilliseconds): void;\n  removeItem(key: string): void;\n}\n\n/**\n * Manages throttling for telemetry events using a configurable cache implementation\n * to mitigate event flooding in frequently executed code paths.\n */\nexport class TelemetryEventThrottler {\n  #cache: ThrottlerCache;\n  #cacheTtl = DEFAULT_CACHE_TTL_MS;\n\n  constructor(cache: ThrottlerCache) {\n    this.#cache = cache;\n  }\n\n  isEventThrottled(payload: TelemetryEvent): boolean {\n    const now = Date.now();\n    const key = this.#generateKey(payload);\n    const entry = this.#cache.getItem(key);\n\n    if (!entry) {\n      this.#cache.setItem(key, now);\n      return false;\n    }\n\n    const shouldInvalidate = now - entry > this.#cacheTtl;\n    if (shouldInvalidate) {\n      this.#cache.setItem(key, now);\n      return false;\n    }\n\n    return true;\n  }\n\n  /**\n   * Generates a consistent unique key for telemetry events by sorting payload properties.\n   * This ensures that payloads with identical content in different orders produce the same key.\n   */\n  #generateKey(event: TelemetryEvent): string {\n    const { sk: _sk, pk: _pk, payload, ...rest } = event;\n\n    const sanitizedEvent: Omit<TelemetryEvent, 'sk' | 'pk' | 'payload'> & TelemetryEvent['payload'] = {\n      ...payload,\n      ...rest,\n    };\n\n    return JSON.stringify(\n      Object.keys({\n        ...payload,\n        ...rest,\n      })\n        .sort()\n        .map(key => sanitizedEvent[key]),\n    );\n  }\n}\n\n/**\n * LocalStorage-based cache implementation for browser environments.\n */\nexport class LocalStorageThrottlerCache implements ThrottlerCache {\n  #storageKey = 'clerk_telemetry_throttler';\n\n  getItem(key: string): TtlInMilliseconds | undefined {\n    return this.#getCache()[key];\n  }\n\n  setItem(key: string, value: TtlInMilliseconds): void {\n    try {\n      const cache = this.#getCache();\n      cache[key] = value;\n      localStorage.setItem(this.#storageKey, JSON.stringify(cache));\n    } catch (err: unknown) {\n      const isQuotaExceededError =\n        err instanceof DOMException &&\n        // Check error names for different browsers\n        (err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED');\n\n      if (isQuotaExceededError && localStorage.length > 0) {\n        // Clear our cache if quota exceeded\n        localStorage.removeItem(this.#storageKey);\n      }\n    }\n  }\n\n  removeItem(key: string): void {\n    try {\n      const cache = this.#getCache();\n      delete cache[key];\n      localStorage.setItem(this.#storageKey, JSON.stringify(cache));\n    } catch {\n      // Silently fail if we can't remove\n    }\n  }\n\n  #getCache(): Record<string, TtlInMilliseconds> {\n    try {\n      const cacheString = localStorage.getItem(this.#storageKey);\n      if (!cacheString) {\n        return {};\n      }\n      return JSON.parse(cacheString);\n    } catch {\n      return {};\n    }\n  }\n\n  static isSupported(): boolean {\n    return typeof window !== 'undefined' && !!window.localStorage;\n  }\n}\n\n/**\n * In-memory cache implementation for non-browser environments (e.g., React Native).\n */\nexport class InMemoryThrottlerCache implements ThrottlerCache {\n  #cache: Map<string, TtlInMilliseconds> = new Map();\n  #maxSize = 10000; // Defensive limit to prevent memory issues\n\n  getItem(key: string): TtlInMilliseconds | undefined {\n    // Defensive: clear cache if it gets too large\n    if (this.#cache.size > this.#maxSize) {\n      this.#cache.clear();\n      return undefined;\n    }\n\n    return this.#cache.get(key);\n  }\n\n  setItem(key: string, value: TtlInMilliseconds): void {\n    this.#cache.set(key, value);\n  }\n\n  removeItem(key: string): void {\n    this.#cache.delete(key);\n  }\n}\n","/**\n * The `TelemetryCollector` class handles collection of telemetry events from Clerk SDKs. Telemetry is opt-out and can be disabled by setting a CLERK_TELEMETRY_DISABLED environment variable.\n * The `ClerkProvider` also accepts a `telemetry` prop that will be passed to the collector during initialization:.\n *\n * ```jsx\n * <ClerkProvider telemetry={false}>\n *    ...\n * </ClerkProvider>\n * ```\n *\n * For more information, please see the telemetry documentation page: https://clerk.com/docs/telemetry.\n */\nimport { parsePublishableKey } from '../keys';\nimport type {\n  InstanceType,\n  SDKMetadata,\n  TelemetryCollector as TelemetryCollectorInterface,\n  TelemetryEvent,\n  TelemetryEventRaw,\n  TelemetryLogEntry,\n} from '../types';\nimport { isTruthy } from '../underscore';\nimport { InMemoryThrottlerCache, LocalStorageThrottlerCache, TelemetryEventThrottler } from './throttler';\nimport type { TelemetryCollectorOptions } from './types';\n\n/**\n * Local interface for window.Clerk to avoid global type pollution.\n * This is only used within this module and doesn't affect other packages.\n */\ninterface WindowWithClerk extends Window {\n  Clerk?: {\n    constructor?: {\n      sdkMetadata?: SDKMetadata;\n    };\n  };\n}\n\n/**\n * Type guard to check if window.Clerk exists and has the expected structure.\n */\nfunction isWindowClerkWithMetadata(clerk: unknown): clerk is { constructor: { sdkMetadata?: SDKMetadata } } {\n  return (\n    typeof clerk === 'object' && clerk !== null && 'constructor' in clerk && typeof clerk.constructor === 'function'\n  );\n}\n\ntype TelemetryCollectorConfig = Pick<\n  TelemetryCollectorOptions,\n  'samplingRate' | 'disabled' | 'debug' | 'maxBufferSize' | 'perEventSampling'\n> & {\n  endpoint: string;\n};\n\ntype TelemetryMetadata = Required<\n  Pick<TelemetryCollectorOptions, 'clerkVersion' | 'sdk' | 'sdkVersion' | 'publishableKey' | 'secretKey'>\n> & {\n  /**\n   * The instance type, derived from the provided publishableKey.\n   */\n  instanceType: InstanceType;\n};\n\n/**\n * Structure of log data sent to the telemetry endpoint.\n */\ntype TelemetryLogData = {\n  /** Service that generated the log. */\n  sdk: string;\n  /** The version of the SDK where the event originated from. */\n  sdkv: string;\n  /** The version of Clerk where the event originated from. */\n  cv: string;\n  /** Log level (info, warn, error, debug, etc.). */\n  lvl: TelemetryLogEntry['level'];\n  /** Log message. */\n  msg: string;\n  /** Instance ID - optional. */\n  iid?: string;\n  /** Timestamp when log was generated. */\n  ts: string;\n  /** Primary key. */\n  pk: string | null;\n  /** Additional payload for the log. */\n  payload: Record<string, unknown> | null;\n};\n\ntype TelemetryBufferItem = { kind: 'event'; value: TelemetryEvent } | { kind: 'log'; value: TelemetryLogData };\n\n// Accepted log levels for runtime validation\nconst VALID_LOG_LEVELS = new Set<string>(['error', 'warn', 'info', 'debug', 'trace']);\n\nconst DEFAULT_CONFIG: Partial<TelemetryCollectorConfig> = {\n  samplingRate: 1,\n  maxBufferSize: 5,\n  // Production endpoint: https://clerk-telemetry.com\n  // Staging endpoint: https://staging.clerk-telemetry.com\n  // Local: http://localhost:8787\n  endpoint: 'https://clerk-telemetry.com',\n};\n\nexport class TelemetryCollector implements TelemetryCollectorInterface {\n  #config: Required<TelemetryCollectorConfig>;\n  #eventThrottler: TelemetryEventThrottler;\n  #metadata: TelemetryMetadata = {} as TelemetryMetadata;\n  #buffer: TelemetryBufferItem[] = [];\n  #pendingFlush: number | ReturnType<typeof setTimeout> | null = null;\n\n  constructor(options: TelemetryCollectorOptions) {\n    this.#config = {\n      maxBufferSize: options.maxBufferSize ?? DEFAULT_CONFIG.maxBufferSize,\n      samplingRate: options.samplingRate ?? DEFAULT_CONFIG.samplingRate,\n      perEventSampling: options.perEventSampling ?? true,\n      disabled: options.disabled ?? false,\n      debug: options.debug ?? false,\n      endpoint: DEFAULT_CONFIG.endpoint,\n    } as Required<TelemetryCollectorConfig>;\n\n    if (!options.clerkVersion && typeof window === 'undefined') {\n      // N/A in a server environment\n      this.#metadata.clerkVersion = '';\n    } else {\n      this.#metadata.clerkVersion = options.clerkVersion ?? '';\n    }\n\n    // We will try to grab the SDK data lazily when an event is triggered, so it should always be defined once the event is sent.\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    this.#metadata.sdk = options.sdk!;\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    this.#metadata.sdkVersion = options.sdkVersion!;\n\n    this.#metadata.publishableKey = options.publishableKey ?? '';\n\n    const parsedKey = parsePublishableKey(options.publishableKey);\n    if (parsedKey) {\n      this.#metadata.instanceType = parsedKey.instanceType;\n    }\n\n    if (options.secretKey) {\n      // Only send the first 16 characters of the secret key to to avoid sending the full key. We can still query against the partial key.\n      this.#metadata.secretKey = options.secretKey.substring(0, 16);\n    }\n\n    // Use LocalStorage cache in browsers where it's supported, otherwise fall back to in-memory cache\n    const cache = LocalStorageThrottlerCache.isSupported()\n      ? new LocalStorageThrottlerCache()\n      : new InMemoryThrottlerCache();\n    this.#eventThrottler = new TelemetryEventThrottler(cache);\n  }\n\n  get isEnabled(): boolean {\n    if (this.#metadata.instanceType !== 'development') {\n      return false;\n    }\n\n    // In browser or client environments, we most likely pass the disabled option to the collector, but in environments\n    // where environment variables are available we also check for `CLERK_TELEMETRY_DISABLED`.\n    if (\n      this.#config.disabled ||\n      (typeof process !== 'undefined' && process.env && isTruthy(process.env.CLERK_TELEMETRY_DISABLED))\n    ) {\n      return false;\n    }\n\n    // navigator.webdriver is a property generally set by headless browsers that are running in an automated testing environment.\n    // Data from these environments is not meaningful for us and has the potential to produce a large volume of events, so we disable\n    // collection in this case. (ref: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver)\n    if (typeof window !== 'undefined' && !!window?.navigator?.webdriver) {\n      return false;\n    }\n\n    return true;\n  }\n\n  get isDebug(): boolean {\n    return (\n      this.#config.debug ||\n      (typeof process !== 'undefined' && process.env && isTruthy(process.env.CLERK_TELEMETRY_DEBUG))\n    );\n  }\n\n  record(event: TelemetryEventRaw): void {\n    try {\n      const preparedPayload = this.#preparePayload(event.event, event.payload);\n\n      this.#logEvent(preparedPayload.event, preparedPayload);\n\n      if (!this.#shouldRecord(preparedPayload, event.eventSamplingRate)) {\n        return;\n      }\n\n      this.#buffer.push({ kind: 'event', value: preparedPayload });\n\n      this.#scheduleFlush();\n    } catch (error) {\n      console.error('[clerk/telemetry] Error recording telemetry event', error);\n    }\n  }\n\n  /**\n   * Records a telemetry log entry if logging is enabled and not in debug mode.\n   *\n   * @param entry - The telemetry log entry to record.\n   */\n  recordLog(entry: TelemetryLogEntry): void {\n    try {\n      if (!this.#shouldRecordLog(entry)) {\n        return;\n      }\n\n      const levelIsValid = typeof entry?.level === 'string' && VALID_LOG_LEVELS.has(entry.level);\n      const messageIsValid = typeof entry?.message === 'string' && entry.message.trim().length > 0;\n\n      let normalizedTimestamp: Date | null = null;\n      const timestampInput: unknown = (entry as unknown as { timestamp?: unknown })?.timestamp;\n      if (typeof timestampInput === 'number' || typeof timestampInput === 'string') {\n        const candidate = new Date(timestampInput);\n        if (!Number.isNaN(candidate.getTime())) {\n          normalizedTimestamp = candidate;\n        }\n      }\n\n      if (!levelIsValid || !messageIsValid || normalizedTimestamp === null) {\n        if (this.isDebug && typeof console !== 'undefined') {\n          console.warn('[clerk/telemetry] Dropping invalid telemetry log entry', {\n            levelIsValid,\n            messageIsValid,\n            timestampIsValid: normalizedTimestamp !== null,\n          });\n        }\n        return;\n      }\n\n      const sdkMetadata = this.#getSDKMetadata();\n\n      const logData: TelemetryLogData = {\n        sdk: sdkMetadata.name,\n        sdkv: sdkMetadata.version,\n        cv: this.#metadata.clerkVersion ?? '',\n        lvl: entry.level,\n        msg: entry.message,\n        ts: normalizedTimestamp.toISOString(),\n        pk: this.#metadata.publishableKey || null,\n        payload: this.#sanitizeContext(entry.context),\n      };\n\n      this.#buffer.push({ kind: 'log', value: logData });\n\n      this.#scheduleFlush();\n    } catch (error) {\n      console.error('[clerk/telemetry] Error recording telemetry log entry', error);\n    }\n  }\n\n  #shouldRecord(preparedPayload: TelemetryEvent, eventSamplingRate?: number) {\n    return this.isEnabled && !this.isDebug && this.#shouldBeSampled(preparedPayload, eventSamplingRate);\n  }\n\n  #shouldRecordLog(_entry: TelemetryLogEntry): boolean {\n    // Always allow logs from debug logger to be sent. Debug logger itself is already gated elsewhere.\n    return true;\n  }\n\n  #shouldBeSampled(preparedPayload: TelemetryEvent, eventSamplingRate?: number) {\n    const randomSeed = Math.random();\n\n    const toBeSampled =\n      randomSeed <= this.#config.samplingRate &&\n      (this.#config.perEventSampling === false ||\n        typeof eventSamplingRate === 'undefined' ||\n        randomSeed <= eventSamplingRate);\n\n    if (!toBeSampled) {\n      return false;\n    }\n\n    return !this.#eventThrottler.isEventThrottled(preparedPayload);\n  }\n\n  #scheduleFlush(): void {\n    // On the server, we want to flush immediately as we have less guarantees about the lifecycle of the process\n    if (typeof window === 'undefined') {\n      this.#flush();\n      return;\n    }\n    const isBufferFull = this.#buffer.length >= this.#config.maxBufferSize;\n    if (isBufferFull) {\n      // If the buffer is full, flush immediately to make sure we minimize the chance of event loss.\n      // Cancel any pending flushes as we're going to flush immediately\n      if (this.#pendingFlush) {\n        if (typeof cancelIdleCallback !== 'undefined') {\n          cancelIdleCallback(Number(this.#pendingFlush));\n        } else {\n          clearTimeout(Number(this.#pendingFlush));\n        }\n      }\n      this.#flush();\n      return;\n    }\n\n    // If we have a pending flush, do nothing\n    if (this.#pendingFlush) {\n      return;\n    }\n\n    if ('requestIdleCallback' in window) {\n      this.#pendingFlush = requestIdleCallback(() => {\n        this.#flush();\n        this.#pendingFlush = null;\n      });\n    } else {\n      // This is not an ideal solution, but it at least waits until the next tick\n      this.#pendingFlush = setTimeout(() => {\n        this.#flush();\n        this.#pendingFlush = null;\n      }, 0);\n    }\n  }\n\n  #flush(): void {\n    // Capture the current buffer and clear it immediately to avoid closure references\n    const itemsToSend = [...this.#buffer];\n    this.#buffer = [];\n\n    this.#pendingFlush = null;\n\n    if (itemsToSend.length === 0) {\n      return;\n    }\n\n    const eventsToSend = itemsToSend\n      .filter(item => item.kind === 'event')\n      .map(item => (item as { kind: 'event'; value: TelemetryEvent }).value);\n\n    const logsToSend = itemsToSend\n      .filter(item => item.kind === 'log')\n      .map(item => (item as { kind: 'log'; value: TelemetryLogData }).value);\n\n    if (eventsToSend.length > 0) {\n      const eventsUrl = new URL('/v1/event', this.#config.endpoint);\n      fetch(eventsUrl, {\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        keepalive: true,\n        method: 'POST',\n        // TODO: We send an array here with that idea that we can eventually send multiple events.\n        body: JSON.stringify({ events: eventsToSend }),\n      }).catch(() => void 0);\n    }\n\n    if (logsToSend.length > 0) {\n      const logsUrl = new URL('/v1/logs', this.#config.endpoint);\n      fetch(logsUrl, {\n        headers: {\n          'Content-Type': 'application/json',\n        },\n        keepalive: true,\n        method: 'POST',\n        body: JSON.stringify({ logs: logsToSend }),\n      }).catch(() => void 0);\n    }\n  }\n\n  /**\n   * If running in debug mode, log the event and its payload to the console.\n   */\n  #logEvent(event: TelemetryEvent['event'], payload: Record<string, any>) {\n    if (!this.isDebug) {\n      return;\n    }\n\n    if (typeof console.groupCollapsed !== 'undefined') {\n      console.groupCollapsed('[clerk/telemetry]', event);\n      console.log(payload);\n      console.groupEnd();\n    } else {\n      console.log('[clerk/telemetry]', event, payload);\n    }\n  }\n\n  /**\n   * If in browser, attempt to lazily grab the SDK metadata from the Clerk singleton, otherwise fallback to the initially passed in values.\n   *\n   * This is necessary because the sdkMetadata can be set by the host SDK after the TelemetryCollector is instantiated.\n   */\n  #getSDKMetadata() {\n    const sdkMetadata = {\n      name: this.#metadata.sdk,\n      version: this.#metadata.sdkVersion,\n    };\n\n    if (typeof window !== 'undefined') {\n      const windowWithClerk = window as WindowWithClerk;\n\n      if (windowWithClerk.Clerk) {\n        const windowClerk = windowWithClerk.Clerk;\n\n        if (isWindowClerkWithMetadata(windowClerk) && windowClerk.constructor.sdkMetadata) {\n          const { name, version } = windowClerk.constructor.sdkMetadata;\n\n          if (name !== undefined) {\n            sdkMetadata.name = name;\n          }\n          if (version !== undefined) {\n            sdkMetadata.version = version;\n          }\n        }\n      }\n    }\n\n    return sdkMetadata;\n  }\n\n  /**\n   * Append relevant metadata from the Clerk singleton to the event payload.\n   */\n  #preparePayload(event: TelemetryEvent['event'], payload: TelemetryEvent['payload']): TelemetryEvent {\n    const sdkMetadata = this.#getSDKMetadata();\n\n    return {\n      event,\n      cv: this.#metadata.clerkVersion ?? '',\n      it: this.#metadata.instanceType ?? '',\n      sdk: sdkMetadata.name,\n      sdkv: sdkMetadata.version,\n      ...(this.#metadata.publishableKey ? { pk: this.#metadata.publishableKey } : {}),\n      ...(this.#metadata.secretKey ? { sk: this.#metadata.secretKey } : {}),\n      payload,\n    };\n  }\n\n  /**\n   * Best-effort sanitization of the context payload. Returns a plain object with JSON-serializable\n   * values or null when the input is missing or not serializable. Arrays are not accepted.\n   */\n  #sanitizeContext(context: unknown): Record<string, unknown> | null {\n    if (context === null || typeof context === 'undefined') {\n      return null;\n    }\n    if (typeof context !== 'object') {\n      return null;\n    }\n    try {\n      const cleaned = JSON.parse(JSON.stringify(context));\n      if (cleaned && typeof cleaned === 'object' && !Array.isArray(cleaned)) {\n        return cleaned as Record<string, unknown>;\n      }\n      return null;\n    } catch {\n      return null;\n    }\n  }\n}\n","import type { TelemetryEventRaw } from '../../types';\n\nconst EVENT_COMPONENT_MOUNTED = 'COMPONENT_MOUNTED';\nconst EVENT_COMPONENT_OPENED = 'COMPONENT_OPENED';\nconst EVENT_SAMPLING_RATE = 0.1;\n\n/** Increase sampling for high-signal auth components on mount. */\nconst AUTH_COMPONENTS = new Set<string>(['SignIn', 'SignUp']);\n\n/**\n * Returns the per-event sampling rate for component-mounted telemetry events.\n * Uses a higher rate for SignIn/SignUp to improve signal quality.\n *\n *  @internal\n */\nfunction getComponentMountedSamplingRate(component: string): number {\n  return AUTH_COMPONENTS.has(component) ? 1 : EVENT_SAMPLING_RATE;\n}\n\ntype ComponentMountedBase = {\n  component: string;\n};\n\ntype EventPrebuiltComponent = ComponentMountedBase & {\n  appearanceProp: boolean;\n  elements: boolean;\n  variables: boolean;\n  theme: boolean;\n};\n\ntype EventComponentMounted = ComponentMountedBase & TelemetryEventRaw['payload'];\n\n/**\n * Factory for prebuilt component telemetry events.\n *\n * @internal\n */\nfunction createPrebuiltComponentEvent(event: typeof EVENT_COMPONENT_MOUNTED | typeof EVENT_COMPONENT_OPENED) {\n  return function (\n    component: string,\n    props?: Record<string, any>,\n    additionalPayload?: TelemetryEventRaw['payload'],\n  ): TelemetryEventRaw<EventPrebuiltComponent> {\n    return {\n      event,\n      eventSamplingRate:\n        event === EVENT_COMPONENT_MOUNTED ? getComponentMountedSamplingRate(component) : EVENT_SAMPLING_RATE,\n      payload: {\n        component,\n        appearanceProp: Boolean(props?.appearance),\n        theme: Boolean(props?.appearance?.theme),\n        elements: Boolean(props?.appearance?.elements),\n        variables: Boolean(props?.appearance?.variables),\n        ...additionalPayload,\n      },\n    };\n  };\n}\n\n/**\n * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is mounted.\n *\n * @param component - The name of the component.\n * @param props - The props passed to the component. Will be filtered to a known list of props.\n * @param additionalPayload - Additional data to send with the event.\n * @example\n * telemetry.record(eventPrebuiltComponentMounted('SignUp', props));\n */\nexport function eventPrebuiltComponentMounted(\n  component: string,\n  props?: Record<string, any>,\n  additionalPayload?: TelemetryEventRaw['payload'],\n): TelemetryEventRaw<EventPrebuiltComponent> {\n  return createPrebuiltComponentEvent(EVENT_COMPONENT_MOUNTED)(component, props, additionalPayload);\n}\n\n/**\n * Helper function for `telemetry.record()`. Create a consistent event object for when a prebuilt (AIO) component is opened as a modal.\n *\n * @param component - The name of the component.\n * @param props - The props passed to the component. Will be filtered to a known list of props.\n * @param additionalPayload - Additional data to send with the event.\n * @example\n * telemetry.record(eventPrebuiltComponentOpened('GoogleOneTap', props));\n */\nexport function eventPrebuiltComponentOpened(\n  component: string,\n  props?: Record<string, any>,\n  additionalPayload?: TelemetryEventRaw['payload'],\n): TelemetryEventRaw<EventPrebuiltComponent> {\n  return createPrebuiltComponentEvent(EVENT_COMPONENT_OPENED)(component, props, additionalPayload);\n}\n\n/**\n * Helper function for `telemetry.record()`. Create a consistent event object for when a component is mounted. Use `eventPrebuiltComponentMounted` for prebuilt components.\n *\n * **Caution:** Filter the `props` you pass to this function to avoid sending too much data.\n *\n * @param component - The name of the component.\n * @param props - The props passed to the component. Ideally you only pass a handful of props here.\n * @example\n * telemetry.record(eventComponentMounted('SignUp', props));\n */\nexport function eventComponentMounted(\n  component: string,\n  props: TelemetryEventRaw['payload'] = {},\n): TelemetryEventRaw<EventComponentMounted> {\n  return {\n    event: EVENT_COMPONENT_MOUNTED,\n    eventSamplingRate: getComponentMountedSamplingRate(component),\n    payload: {\n      component,\n      ...props,\n    },\n  };\n}\n","import type { TelemetryEventRaw } from '../../types';\n\nconst EVENT_METHOD_CALLED = 'METHOD_CALLED';\nconst EVENT_SAMPLING_RATE = 0.1;\n\ntype EventMethodCalled = {\n  method: string;\n} & Record<string, string | number | boolean>;\n\n/**\n * Fired when a helper method is called from a Clerk SDK.\n */\nexport function eventMethodCalled(\n  method: string,\n  payload?: Record<string, unknown>,\n): TelemetryEventRaw<EventMethodCalled> {\n  return {\n    event: EVENT_METHOD_CALLED,\n    eventSamplingRate: EVENT_SAMPLING_RATE,\n    payload: {\n      method,\n      ...payload,\n    },\n  };\n}\n","import type { TelemetryEventRaw } from '../../types';\n\nconst EVENT_FRAMEWORK_METADATA = 'FRAMEWORK_METADATA';\nconst EVENT_SAMPLING_RATE = 0.1;\n\ntype EventFrameworkMetadata = Record<string, string | number | boolean>;\n\n/**\n * Fired when a helper method is called from a Clerk SDK.\n */\nexport function eventFrameworkMetadata(payload: EventFrameworkMetadata): TelemetryEventRaw<EventFrameworkMetadata> {\n  return {\n    event: EVENT_FRAMEWORK_METADATA,\n    eventSamplingRate: EVENT_SAMPLING_RATE,\n    payload,\n  };\n}\n","import type { TelemetryEventRaw } from '../../types';\n\nexport const EVENT_THEME_USAGE = 'THEME_USAGE';\nexport const EVENT_SAMPLING_RATE = 1;\n\ntype EventThemeUsage = {\n  /**\n   * The name of the theme being used (e.g., \"shadcn\", \"neobrutalism\", etc.).\n   */\n  themeName?: string;\n};\n\n/**\n * Helper function for `telemetry.record()`. Create a consistent event object for tracking theme usage in ClerkProvider.\n *\n * @param appearance - The appearance prop from ClerkProvider.\n * @example\n * telemetry.record(eventThemeUsage(appearance));\n */\nexport function eventThemeUsage(appearance?: any): TelemetryEventRaw<EventThemeUsage> {\n  const payload = analyzeThemeUsage(appearance);\n\n  return {\n    event: EVENT_THEME_USAGE,\n    eventSamplingRate: EVENT_SAMPLING_RATE,\n    payload,\n  };\n}\n\n/**\n * Analyzes the appearance prop to extract theme usage information for telemetry.\n *\n * @internal\n */\nfunction analyzeThemeUsage(appearance?: any): EventThemeUsage {\n  if (!appearance || typeof appearance !== 'object') {\n    return {};\n  }\n\n  const themeProperty = appearance.theme;\n\n  if (!themeProperty) {\n    return {};\n  }\n\n  let themeName: string | undefined;\n\n  if (Array.isArray(themeProperty)) {\n    // Look for the first identifiable theme name in the array\n    for (const theme of themeProperty) {\n      const name = extractThemeName(theme);\n      if (name) {\n        themeName = name;\n        break;\n      }\n    }\n  } else {\n    themeName = extractThemeName(themeProperty);\n  }\n\n  return { themeName };\n}\n\n/**\n * Extracts the theme name from a theme object.\n *\n * @internal\n */\nfunction extractThemeName(theme: any): string | undefined {\n  if (typeof theme === 'string') {\n    return theme;\n  }\n\n  if (typeof theme === 'object' && theme !== null) {\n    // Check for explicit theme name\n    if ('name' in theme && typeof theme.name === 'string') {\n      return theme.name;\n    }\n  }\n\n  return undefined;\n}\n"],"mappings":";;;;AAIA,MAAM,uBAAuB;;;;;AAgB7B,IAAa,0BAAb,MAAqC;CACnC;CACA,YAAY;CAEZ,YAAY,OAAuB;AACjC,QAAKA,QAAS;;CAGhB,iBAAiB,SAAkC;EACjD,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,MAAM,MAAKC,YAAa,QAAQ;EACtC,MAAM,QAAQ,MAAKD,MAAO,QAAQ,IAAI;AAEtC,MAAI,CAAC,OAAO;AACV,SAAKA,MAAO,QAAQ,KAAK,IAAI;AAC7B,UAAO;;AAIT,MADyB,MAAM,QAAQ,MAAKE,UACtB;AACpB,SAAKF,MAAO,QAAQ,KAAK,IAAI;AAC7B,UAAO;;AAGT,SAAO;;;;;;CAOT,aAAa,OAA+B;EAC1C,MAAM,EAAE,IAAI,KAAK,IAAI,KAAK,QAAS,GAAG,SAAS;EAE/C,MAAMG,iBAA4F;GAChG,GAAG;GACH,GAAG;GACJ;AAED,SAAO,KAAK,UACV,OAAO,KAAK;GACV,GAAG;GACH,GAAG;GACJ,CAAC,CACC,MAAM,CACN,KAAI,QAAO,eAAe,KAAK,CACnC;;;;;;AAOL,IAAa,6BAAb,MAAkE;CAChE,cAAc;CAEd,QAAQ,KAA4C;AAClD,SAAO,MAAKC,UAAW,CAAC;;CAG1B,QAAQ,KAAa,OAAgC;AACnD,MAAI;GACF,MAAM,QAAQ,MAAKA,UAAW;AAC9B,SAAM,OAAO;AACb,gBAAa,QAAQ,MAAKC,YAAa,KAAK,UAAU,MAAM,CAAC;WACtDC,KAAc;AAMrB,OAJE,eAAe,iBAEd,IAAI,SAAS,wBAAwB,IAAI,SAAS,iCAEzB,aAAa,SAAS,EAEhD,cAAa,WAAW,MAAKD,WAAY;;;CAK/C,WAAW,KAAmB;AAC5B,MAAI;GACF,MAAM,QAAQ,MAAKD,UAAW;AAC9B,UAAO,MAAM;AACb,gBAAa,QAAQ,MAAKC,YAAa,KAAK,UAAU,MAAM,CAAC;UACvD;;CAKV,YAA+C;AAC7C,MAAI;GACF,MAAM,cAAc,aAAa,QAAQ,MAAKA,WAAY;AAC1D,OAAI,CAAC,YACH,QAAO,EAAE;AAEX,UAAO,KAAK,MAAM,YAAY;UACxB;AACN,UAAO,EAAE;;;CAIb,OAAO,cAAuB;AAC5B,SAAO,OAAO,WAAW,eAAe,CAAC,CAAC,OAAO;;;;;;AAOrD,IAAa,yBAAb,MAA8D;CAC5D,yBAAyC,IAAI,KAAK;CAClD,WAAW;CAEX,QAAQ,KAA4C;AAElD,MAAI,MAAKL,MAAO,OAAO,MAAKO,SAAU;AACpC,SAAKP,MAAO,OAAO;AACnB;;AAGF,SAAO,MAAKA,MAAO,IAAI,IAAI;;CAG7B,QAAQ,KAAa,OAAgC;AACnD,QAAKA,MAAO,IAAI,KAAK,MAAM;;CAG7B,WAAW,KAAmB;AAC5B,QAAKA,MAAO,OAAO,IAAI;;;;;;;;;;;;;;;;;;;;;AC3G3B,SAAS,0BAA0B,OAAyE;AAC1G,QACE,OAAO,UAAU,YAAY,UAAU,QAAQ,iBAAiB,SAAS,OAAO,MAAM,gBAAgB;;AA+C1G,MAAM,mBAAmB,IAAI,IAAY;CAAC;CAAS;CAAQ;CAAQ;CAAS;CAAQ,CAAC;AAErF,MAAMQ,iBAAoD;CACxD,cAAc;CACd,eAAe;CAIf,UAAU;CACX;AAED,IAAa,qBAAb,MAAuE;CACrE;CACA;CACA,YAA+B,EAAE;CACjC,UAAiC,EAAE;CACnC,gBAA+D;CAE/D,YAAY,SAAoC;AAC9C,QAAKC,SAAU;GACb,eAAe,QAAQ,iBAAiB,eAAe;GACvD,cAAc,QAAQ,gBAAgB,eAAe;GACrD,kBAAkB,QAAQ,oBAAoB;GAC9C,UAAU,QAAQ,YAAY;GAC9B,OAAO,QAAQ,SAAS;GACxB,UAAU,eAAe;GAC1B;AAED,MAAI,CAAC,QAAQ,gBAAgB,OAAO,WAAW,YAE7C,OAAKC,SAAU,eAAe;MAE9B,OAAKA,SAAU,eAAe,QAAQ,gBAAgB;AAKxD,QAAKA,SAAU,MAAM,QAAQ;AAE7B,QAAKA,SAAU,aAAa,QAAQ;AAEpC,QAAKA,SAAU,iBAAiB,QAAQ,kBAAkB;EAE1D,MAAM,YAAY,oBAAoB,QAAQ,eAAe;AAC7D,MAAI,UACF,OAAKA,SAAU,eAAe,UAAU;AAG1C,MAAI,QAAQ,UAEV,OAAKA,SAAU,YAAY,QAAQ,UAAU,UAAU,GAAG,GAAG;AAO/D,QAAKC,iBAAkB,IAAI,wBAHb,2BAA2B,aAAa,GAClD,IAAI,4BAA4B,GAChC,IAAI,wBAAwB,CACyB;;CAG3D,IAAI,YAAqB;AACvB,MAAI,MAAKD,SAAU,iBAAiB,cAClC,QAAO;AAKT,MACE,MAAKD,OAAQ,YACZ,OAAO,YAAY,eAAe,QAAQ,OAAO,SAAS,QAAQ,IAAI,yBAAyB,CAEhG,QAAO;AAMT,MAAI,OAAO,WAAW,eAAe,CAAC,CAAC,QAAQ,WAAW,UACxD,QAAO;AAGT,SAAO;;CAGT,IAAI,UAAmB;AACrB,SACE,MAAKA,OAAQ,SACZ,OAAO,YAAY,eAAe,QAAQ,OAAO,SAAS,QAAQ,IAAI,sBAAsB;;CAIjG,OAAO,OAAgC;AACrC,MAAI;GACF,MAAM,kBAAkB,MAAKG,eAAgB,MAAM,OAAO,MAAM,QAAQ;AAExE,SAAKC,SAAU,gBAAgB,OAAO,gBAAgB;AAEtD,OAAI,CAAC,MAAKC,aAAc,iBAAiB,MAAM,kBAAkB,CAC/D;AAGF,SAAKC,OAAQ,KAAK;IAAE,MAAM;IAAS,OAAO;IAAiB,CAAC;AAE5D,SAAKC,eAAgB;WACd,OAAO;AACd,WAAQ,MAAM,qDAAqD,MAAM;;;;;;;;CAS7E,UAAU,OAAgC;AACxC,MAAI;AACF,OAAI,CAAC,MAAKC,gBAAiB,MAAM,CAC/B;GAGF,MAAM,eAAe,OAAO,OAAO,UAAU,YAAY,iBAAiB,IAAI,MAAM,MAAM;GAC1F,MAAM,iBAAiB,OAAO,OAAO,YAAY,YAAY,MAAM,QAAQ,MAAM,CAAC,SAAS;GAE3F,IAAIC,sBAAmC;GACvC,MAAMC,iBAA2B,OAA8C;AAC/E,OAAI,OAAO,mBAAmB,YAAY,OAAO,mBAAmB,UAAU;IAC5E,MAAM,YAAY,IAAI,KAAK,eAAe;AAC1C,QAAI,CAAC,OAAO,MAAM,UAAU,SAAS,CAAC,CACpC,uBAAsB;;AAI1B,OAAI,CAAC,gBAAgB,CAAC,kBAAkB,wBAAwB,MAAM;AACpE,QAAI,KAAK,WAAW,OAAO,YAAY,YACrC,SAAQ,KAAK,0DAA0D;KACrE;KACA;KACA,kBAAkB,wBAAwB;KAC3C,CAAC;AAEJ;;GAGF,MAAM,cAAc,MAAKC,gBAAiB;GAE1C,MAAMC,UAA4B;IAChC,KAAK,YAAY;IACjB,MAAM,YAAY;IAClB,IAAI,MAAKX,SAAU,gBAAgB;IACnC,KAAK,MAAM;IACX,KAAK,MAAM;IACX,IAAI,oBAAoB,aAAa;IACrC,IAAI,MAAKA,SAAU,kBAAkB;IACrC,SAAS,MAAKY,gBAAiB,MAAM,QAAQ;IAC9C;AAED,SAAKP,OAAQ,KAAK;IAAE,MAAM;IAAO,OAAO;IAAS,CAAC;AAElD,SAAKC,eAAgB;WACd,OAAO;AACd,WAAQ,MAAM,yDAAyD,MAAM;;;CAIjF,cAAc,iBAAiC,mBAA4B;AACzE,SAAO,KAAK,aAAa,CAAC,KAAK,WAAW,MAAKO,gBAAiB,iBAAiB,kBAAkB;;CAGrG,iBAAiB,QAAoC;AAEnD,SAAO;;CAGT,iBAAiB,iBAAiC,mBAA4B;EAC5E,MAAM,aAAa,KAAK,QAAQ;AAQhC,MAAI,EALF,cAAc,MAAKd,OAAQ,iBAC1B,MAAKA,OAAQ,qBAAqB,SACjC,OAAO,sBAAsB,eAC7B,cAAc,oBAGhB,QAAO;AAGT,SAAO,CAAC,MAAKE,eAAgB,iBAAiB,gBAAgB;;CAGhE,iBAAuB;AAErB,MAAI,OAAO,WAAW,aAAa;AACjC,SAAKa,OAAQ;AACb;;AAGF,MADqB,MAAKT,OAAQ,UAAU,MAAKN,OAAQ,eACvC;AAGhB,OAAI,MAAKgB,aACP,KAAI,OAAO,uBAAuB,YAChC,oBAAmB,OAAO,MAAKA,aAAc,CAAC;OAE9C,cAAa,OAAO,MAAKA,aAAc,CAAC;AAG5C,SAAKD,OAAQ;AACb;;AAIF,MAAI,MAAKC,aACP;AAGF,MAAI,yBAAyB,OAC3B,OAAKA,eAAgB,0BAA0B;AAC7C,SAAKD,OAAQ;AACb,SAAKC,eAAgB;IACrB;MAGF,OAAKA,eAAgB,iBAAiB;AACpC,SAAKD,OAAQ;AACb,SAAKC,eAAgB;KACpB,EAAE;;CAIT,SAAe;EAEb,MAAM,cAAc,CAAC,GAAG,MAAKV,OAAQ;AACrC,QAAKA,SAAU,EAAE;AAEjB,QAAKU,eAAgB;AAErB,MAAI,YAAY,WAAW,EACzB;EAGF,MAAM,eAAe,YAClB,QAAO,SAAQ,KAAK,SAAS,QAAQ,CACrC,KAAI,SAAS,KAAkD,MAAM;EAExE,MAAM,aAAa,YAChB,QAAO,SAAQ,KAAK,SAAS,MAAM,CACnC,KAAI,SAAS,KAAkD,MAAM;AAExE,MAAI,aAAa,SAAS,GAAG;GAC3B,MAAM,YAAY,IAAI,IAAI,aAAa,MAAKhB,OAAQ,SAAS;AAC7D,SAAM,WAAW;IACf,SAAS,EACP,gBAAgB,oBACjB;IACD,WAAW;IACX,QAAQ;IAER,MAAM,KAAK,UAAU,EAAE,QAAQ,cAAc,CAAC;IAC/C,CAAC,CAAC,YAAY,KAAK,EAAE;;AAGxB,MAAI,WAAW,SAAS,GAAG;GACzB,MAAM,UAAU,IAAI,IAAI,YAAY,MAAKA,OAAQ,SAAS;AAC1D,SAAM,SAAS;IACb,SAAS,EACP,gBAAgB,oBACjB;IACD,WAAW;IACX,QAAQ;IACR,MAAM,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;IAC3C,CAAC,CAAC,YAAY,KAAK,EAAE;;;;;;CAO1B,UAAU,OAAgC,SAA8B;AACtE,MAAI,CAAC,KAAK,QACR;AAGF,MAAI,OAAO,QAAQ,mBAAmB,aAAa;AACjD,WAAQ,eAAe,qBAAqB,MAAM;AAClD,WAAQ,IAAI,QAAQ;AACpB,WAAQ,UAAU;QAElB,SAAQ,IAAI,qBAAqB,OAAO,QAAQ;;;;;;;CASpD,kBAAkB;EAChB,MAAM,cAAc;GAClB,MAAM,MAAKC,SAAU;GACrB,SAAS,MAAKA,SAAU;GACzB;AAED,MAAI,OAAO,WAAW,aAAa;GACjC,MAAM,kBAAkB;AAExB,OAAI,gBAAgB,OAAO;IACzB,MAAM,cAAc,gBAAgB;AAEpC,QAAI,0BAA0B,YAAY,IAAI,YAAY,YAAY,aAAa;KACjF,MAAM,EAAE,MAAM,YAAY,YAAY,YAAY;AAElD,SAAI,SAAS,OACX,aAAY,OAAO;AAErB,SAAI,YAAY,OACd,aAAY,UAAU;;;;AAM9B,SAAO;;;;;CAMT,gBAAgB,OAAgC,SAAoD;EAClG,MAAM,cAAc,MAAKU,gBAAiB;AAE1C,SAAO;GACL;GACA,IAAI,MAAKV,SAAU,gBAAgB;GACnC,IAAI,MAAKA,SAAU,gBAAgB;GACnC,KAAK,YAAY;GACjB,MAAM,YAAY;GAClB,GAAI,MAAKA,SAAU,iBAAiB,EAAE,IAAI,MAAKA,SAAU,gBAAgB,GAAG,EAAE;GAC9E,GAAI,MAAKA,SAAU,YAAY,EAAE,IAAI,MAAKA,SAAU,WAAW,GAAG,EAAE;GACpE;GACD;;;;;;CAOH,iBAAiB,SAAkD;AACjE,MAAI,YAAY,QAAQ,OAAO,YAAY,YACzC,QAAO;AAET,MAAI,OAAO,YAAY,SACrB,QAAO;AAET,MAAI;GACF,MAAM,UAAU,KAAK,MAAM,KAAK,UAAU,QAAQ,CAAC;AACnD,OAAI,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,QAAQ,CACnE,QAAO;AAET,UAAO;UACD;AACN,UAAO;;;;;;;AC/bb,MAAM,0BAA0B;AAChC,MAAM,yBAAyB;AAC/B,MAAMgB,wBAAsB;;AAG5B,MAAM,kBAAkB,IAAI,IAAY,CAAC,UAAU,SAAS,CAAC;;;;;;;AAQ7D,SAAS,gCAAgC,WAA2B;AAClE,QAAO,gBAAgB,IAAI,UAAU,GAAG,IAAIA;;;;;;;AAqB9C,SAAS,6BAA6B,OAAuE;AAC3G,QAAO,SACL,WACA,OACA,mBAC2C;AAC3C,SAAO;GACL;GACA,mBACE,UAAU,0BAA0B,gCAAgC,UAAU,GAAGA;GACnF,SAAS;IACP;IACA,gBAAgB,QAAQ,OAAO,WAAW;IAC1C,OAAO,QAAQ,OAAO,YAAY,MAAM;IACxC,UAAU,QAAQ,OAAO,YAAY,SAAS;IAC9C,WAAW,QAAQ,OAAO,YAAY,UAAU;IAChD,GAAG;IACJ;GACF;;;;;;;;;;;;AAaL,SAAgB,8BACd,WACA,OACA,mBAC2C;AAC3C,QAAO,6BAA6B,wBAAwB,CAAC,WAAW,OAAO,kBAAkB;;;;;;;;;;;AAYnG,SAAgB,6BACd,WACA,OACA,mBAC2C;AAC3C,QAAO,6BAA6B,uBAAuB,CAAC,WAAW,OAAO,kBAAkB;;;;;;;;;;;;AAalG,SAAgB,sBACd,WACA,QAAsC,EAAE,EACE;AAC1C,QAAO;EACL,OAAO;EACP,mBAAmB,gCAAgC,UAAU;EAC7D,SAAS;GACP;GACA,GAAG;GACJ;EACF;;;;;AChHH,MAAM,sBAAsB;AAC5B,MAAMC,wBAAsB;;;;AAS5B,SAAgB,kBACd,QACA,SACsC;AACtC,QAAO;EACL,OAAO;EACP,mBAAmBA;EACnB,SAAS;GACP;GACA,GAAG;GACJ;EACF;;;;;ACrBH,MAAM,2BAA2B;AACjC,MAAMC,wBAAsB;;;;AAO5B,SAAgB,uBAAuB,SAA4E;AACjH,QAAO;EACL,OAAO;EACP,mBAAmBA;EACnB;EACD;;;;;ACbH,MAAa,oBAAoB;AACjC,MAAa,sBAAsB;;;;;;;;AAgBnC,SAAgB,gBAAgB,YAAsD;AAGpF,QAAO;EACL,OAAO;EACP,mBAAmB;EACnB,SALc,kBAAkB,WAAW;EAM5C;;;;;;;AAQH,SAAS,kBAAkB,YAAmC;AAC5D,KAAI,CAAC,cAAc,OAAO,eAAe,SACvC,QAAO,EAAE;CAGX,MAAM,gBAAgB,WAAW;AAEjC,KAAI,CAAC,cACH,QAAO,EAAE;CAGX,IAAIC;AAEJ,KAAI,MAAM,QAAQ,cAAc,CAE9B,MAAK,MAAM,SAAS,eAAe;EACjC,MAAM,OAAO,iBAAiB,MAAM;AACpC,MAAI,MAAM;AACR,eAAY;AACZ;;;KAIJ,aAAY,iBAAiB,cAAc;AAG7C,QAAO,EAAE,WAAW;;;;;;;AAQtB,SAAS,iBAAiB,OAAgC;AACxD,KAAI,OAAO,UAAU,SACnB,QAAO;AAGT,KAAI,OAAO,UAAU,YAAY,UAAU,MAEzC;MAAI,UAAU,SAAS,OAAO,MAAM,SAAS,SAC3C,QAAO,MAAM"}