@clerk/shared 4.8.4-snapshot.v20260423043146 → 4.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/apiUrlFromPublishableKey.d.mts +1 -1
- package/dist/runtime/apiUrlFromPublishableKey.d.ts +1 -1
- package/dist/runtime/apiUrlFromPublishableKey.js +1 -1
- package/dist/runtime/apiUrlFromPublishableKey.mjs +1 -1
- package/dist/runtime/globs.d.mts.map +1 -1
- package/dist/runtime/globs.d.ts.map +1 -1
- package/dist/runtime/index-B4_BYgBX.d.mts.map +1 -1
- package/dist/runtime/internal/clerk-js/completeSignUpFlow.js +3 -3
- package/dist/runtime/internal/clerk-js/completeSignUpFlow.mjs +3 -3
- package/dist/runtime/internal/clerk-js/queryParams.js +3 -3
- package/dist/runtime/internal/clerk-js/queryParams.mjs +3 -3
- package/dist/runtime/internal/clerk-js/queryStateParams.js +3 -3
- package/dist/runtime/internal/clerk-js/queryStateParams.mjs +3 -3
- package/dist/runtime/internal/clerk-js/redirectUrls.js +2 -2
- package/dist/runtime/internal/clerk-js/redirectUrls.mjs +2 -2
- package/dist/runtime/internal/clerk-js/sessionTasks.js +4 -4
- package/dist/runtime/internal/clerk-js/sessionTasks.mjs +4 -4
- package/dist/runtime/internal/clerk-js/url.js +2 -2
- package/dist/runtime/internal/clerk-js/url.mjs +2 -2
- package/dist/runtime/{keys-DuxzP8MU.mjs → keys-BeVKH43u.mjs} +32 -2
- package/dist/runtime/keys-BeVKH43u.mjs.map +1 -0
- package/dist/runtime/{keys-BI9hmfja.js → keys-D5ahg2Gn.js} +37 -1
- package/dist/runtime/keys-D5ahg2Gn.js.map +1 -0
- package/dist/runtime/keys.d.mts +26 -1
- package/dist/runtime/keys.d.mts.map +1 -1
- package/dist/runtime/keys.d.ts +26 -1
- package/dist/runtime/keys.d.ts.map +1 -1
- package/dist/runtime/keys.js +3 -2
- package/dist/runtime/keys.mjs +2 -2
- package/dist/runtime/loadClerkJsScript.js +3 -3
- package/dist/runtime/loadClerkJsScript.js.map +1 -1
- package/dist/runtime/loadClerkJsScript.mjs +3 -3
- package/dist/runtime/loadClerkJsScript.mjs.map +1 -1
- package/dist/runtime/{netlifyCacheHandler-Dkdkho_6.mjs → netlifyCacheHandler-Cpx2hZ9E.mjs} +2 -2
- package/dist/runtime/{netlifyCacheHandler-Dkdkho_6.mjs.map → netlifyCacheHandler-Cpx2hZ9E.mjs.map} +1 -1
- package/dist/runtime/{netlifyCacheHandler-DFm5qdPh.js → netlifyCacheHandler-DMlEakyq.js} +2 -2
- package/dist/runtime/{netlifyCacheHandler-DFm5qdPh.js.map → netlifyCacheHandler-DMlEakyq.js.map} +1 -1
- package/dist/runtime/netlifyCacheHandler.js +2 -2
- package/dist/runtime/netlifyCacheHandler.mjs +2 -2
- package/dist/runtime/{queryParams-Dlt0oVDg.mjs → queryParams-Bad5kF87.mjs} +2 -2
- package/dist/runtime/{queryParams-Dlt0oVDg.mjs.map → queryParams-Bad5kF87.mjs.map} +1 -1
- package/dist/runtime/{queryParams-DSUymAGT.js → queryParams-DFhrd86C.js} +2 -2
- package/dist/runtime/{queryParams-DSUymAGT.js.map → queryParams-DFhrd86C.js.map} +1 -1
- package/dist/runtime/react/index.d.mts +1 -1
- package/dist/runtime/react/index.d.ts +1 -1
- package/dist/runtime/react/index.js +3 -3
- package/dist/runtime/react/index.js.map +1 -1
- package/dist/runtime/react/index.mjs +3 -3
- package/dist/runtime/react/index.mjs.map +1 -1
- package/dist/runtime/router.d.mts.map +1 -1
- package/dist/runtime/{telemetry-DE2JFEBf.mjs → telemetry-DJrefnDc.mjs} +2 -2
- package/dist/runtime/{telemetry-DE2JFEBf.mjs.map → telemetry-DJrefnDc.mjs.map} +1 -1
- package/dist/runtime/{telemetry--P0a0tSk.js → telemetry-DMGwYVSd.js} +2 -2
- package/dist/runtime/{telemetry--P0a0tSk.js.map → telemetry-DMGwYVSd.js.map} +1 -1
- package/dist/runtime/telemetry.js +2 -2
- package/dist/runtime/telemetry.mjs +2 -2
- package/dist/runtime/{url-CoXV4i87.js → url-Cw4Wpvh3.js} +2 -2
- package/dist/runtime/{url-CoXV4i87.js.map → url-Cw4Wpvh3.js.map} +1 -1
- package/dist/runtime/{url-DaPDWryr.mjs → url-cNLJYbcB.mjs} +2 -2
- package/dist/runtime/{url-DaPDWryr.mjs.map → url-cNLJYbcB.mjs.map} +1 -1
- package/dist/runtime/{versionSelector-DSmto5Fc.js → versionSelector-C1hK82gB.js} +2 -2
- package/dist/runtime/{versionSelector-DSmto5Fc.js.map → versionSelector-C1hK82gB.js.map} +1 -1
- package/dist/runtime/{versionSelector-Ey3EuPi-.mjs → versionSelector-CNF9SLY3.mjs} +2 -2
- package/dist/runtime/{versionSelector-Ey3EuPi-.mjs.map → versionSelector-CNF9SLY3.mjs.map} +1 -1
- package/dist/runtime/versionSelector.js +1 -1
- package/dist/runtime/versionSelector.mjs +1 -1
- package/package.json +1 -1
- package/dist/runtime/keys-BI9hmfja.js.map +0 -1
- package/dist/runtime/keys-DuxzP8MU.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.mts","names":[],"sources":["../../src/router/router.ts","../../src/router/react.tsx"],"sourcesContent":[],"mappings":";;;;;;;;AAQY,KAAA,WAAA,GAAW;EASa,8CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,MAAA;EASnB;;;EAkBF,QAAA,EAAA,MAAA;EAIH;;;EAqBI,KAAA,EAAA,CAAA,aAAiB,EAAA,MAAA,EAAA,GApDG,WAoDM;;;;EC7D7B,KAAA,EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,
|
|
1
|
+
{"version":3,"file":"router.d.mts","names":[],"sources":["../../src/router/router.ts","../../src/router/react.tsx"],"sourcesContent":[],"mappings":";;;;;;;;AAQY,KAAA,WAAA,GAAW;EASa,8CAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAAA,MAAA;EASnB;;;EAkBF,QAAA,EAAA,MAAA;EAIH;;;EAqBI,KAAA,EAAA,CAAA,aAAiB,EAAA,MAAA,EAAA,GApDG,WAoDM;;;;EC7D7B,KAAA,EAAA,CAAA,IAAA,CAAA,EAAA,MAAA,EAAA,KAAsB,CAA8C,EAAA,OAA9C,EAAA,GAAA,OAAA;EACtB;AAKb;AAeA;EAagB,SAAM,IAAA,EDhBL,WCgBK;EACpB;;;EAIU,SAAM,IAAA,EAAA,MAAA;EAEP;;;EAQN,IAAA,EDrBG,eCqBO,CAAA,MAAA,CAAA;EAKC;;;EAAwB,OAAA,EDtB7B,eCsB6B,CAAA,SAAA,CAAA;EAAS;;;EAA0C,WAAA,EDlB5E,eCkB4E,CAAA,aAAA,CAAA;;;;YDd/E;;;;gBAII;;;;;;;;;iBAiBA,iBAAA,SAA0B,qCAA0C;;;AA7DxE,cCAC,sBDAU,ECAY,KAAA,CAAA,ODAZ,CCAY,eDAZ,GAAA,IAAA,CAAA;AASa,cCRvB,kBDQuB,ECRL,KAAA,CAAA,ODQK,CCRL,WDQK,GAAA,IAAA,CAAA;;;;AA2BrB,iBC9BC,kBAAA,CAAA,CD8BD,EC9BmB,eD8BnB;;;;AAyBC,iBCxCA,cAAA,CAAA,CDwC0B,ECxCZ,WDwCY;;;;AC7D7B,iBAkCG,MAAA,CAlCiE;EAAA,QAAA;EAA9C,QAAA;EAAA;AAkCnC,CAlCmC,EAAA;EACtB,QAAA,EAsCD,KAAA,CAAM,SAtCuD;EAKzD,QAAA,CAAA,EAAA,MAAA;EAeA,MAAA,CAAA,EAoBL,eApBmB;AAa9B,CAAA,CAAA,EAQC,KAAA,CAAA,GAAA,CAAA,OARqB;KAejB,UAAA,GAdH;EACA,IAAA,CAAA,EAAA,MAAA;EACA,KAAA,CAAA,EAAA,OAAA;CAEU;;;;AAUP,iBAKW,KAAA,CALD;EAAA,IAAA;EAAA,QAAA;EAAA;CAAA,EAKkC,UALlC,GAAA;EAKC,QAAK,EAAqD,KAAA,CAAM,SAA3D;CAAG,CAAA,EAAmE,KAAA,CAAA,SAAnE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as parsePublishableKey } from "./keys-
|
|
1
|
+
import { u as parsePublishableKey } from "./keys-BeVKH43u.mjs";
|
|
2
2
|
import { o as isTruthy } from "./underscore-ClYSgvuy.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/telemetry/throttler.ts
|
|
@@ -517,4 +517,4 @@ function extractThemeName(theme) {
|
|
|
517
517
|
|
|
518
518
|
//#endregion
|
|
519
519
|
export { eventMethodCalled as a, eventPrebuiltComponentOpened as c, eventFrameworkMetadata as i, TelemetryCollector as l, EVENT_THEME_USAGE as n, eventComponentMounted as o, eventThemeUsage as r, eventPrebuiltComponentMounted as s, EVENT_SAMPLING_RATE as t };
|
|
520
|
-
//# sourceMappingURL=telemetry-
|
|
520
|
+
//# sourceMappingURL=telemetry-DJrefnDc.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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"}
|
|
1
|
+
{"version":3,"file":"telemetry-DJrefnDc.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":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_keys = require('./keys-
|
|
1
|
+
const require_keys = require('./keys-D5ahg2Gn.js');
|
|
2
2
|
const require_underscore = require('./underscore-BX6Ucmg5.js');
|
|
3
3
|
|
|
4
4
|
//#region src/telemetry/throttler.ts
|
|
@@ -570,4 +570,4 @@ Object.defineProperty(exports, 'eventThemeUsage', {
|
|
|
570
570
|
return eventThemeUsage;
|
|
571
571
|
}
|
|
572
572
|
});
|
|
573
|
-
//# sourceMappingURL=telemetry
|
|
573
|
+
//# sourceMappingURL=telemetry-DMGwYVSd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry--P0a0tSk.js","names":["#cache","#generateKey","#cacheTtl","sanitizedEvent: Omit<TelemetryEvent, 'sk' | 'pk' | 'payload'> & TelemetryEvent['payload']","#getCache","#storageKey","err: unknown","#maxSize","DEFAULT_CONFIG: Partial<TelemetryCollectorConfig>","#config","#metadata","parsePublishableKey","#eventThrottler","isTruthy","#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,YAAYC,iCAAoB,QAAQ,eAAe;AAC7D,MAAI,UACF,OAAKD,SAAU,eAAe,UAAU;AAG1C,MAAI,QAAQ,UAEV,OAAKA,SAAU,YAAY,QAAQ,UAAU,UAAU,GAAG,GAAG;AAO/D,QAAKE,iBAAkB,IAAI,wBAHb,2BAA2B,aAAa,GAClD,IAAI,4BAA4B,GAChC,IAAI,wBAAwB,CACyB;;CAG3D,IAAI,YAAqB;AACvB,MAAI,MAAKF,SAAU,iBAAiB,cAClC,QAAO;AAKT,MACE,MAAKD,OAAQ,YACZ,OAAO,YAAY,eAAe,QAAQ,OAAOI,4BAAS,QAAQ,IAAI,yBAAyB,CAEhG,QAAO;AAMT,MAAI,OAAO,WAAW,eAAe,CAAC,CAAC,QAAQ,WAAW,UACxD,QAAO;AAGT,SAAO;;CAGT,IAAI,UAAmB;AACrB,SACE,MAAKJ,OAAQ,SACZ,OAAO,YAAY,eAAe,QAAQ,OAAOI,4BAAS,QAAQ,IAAI,sBAAsB;;CAIjG,OAAO,OAAgC;AACrC,MAAI;GACF,MAAM,kBAAkB,MAAKC,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,MAAKb,SAAU,gBAAgB;IACnC,KAAK,MAAM;IACX,KAAK,MAAM;IACX,IAAI,oBAAoB,aAAa;IACrC,IAAI,MAAKA,SAAU,kBAAkB;IACrC,SAAS,MAAKc,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,MAAKhB,OAAQ,iBAC1B,MAAKA,OAAQ,qBAAqB,SACjC,OAAO,sBAAsB,eAC7B,cAAc,oBAGhB,QAAO;AAGT,SAAO,CAAC,MAAKG,eAAgB,iBAAiB,gBAAgB;;CAGhE,iBAAuB;AAErB,MAAI,OAAO,WAAW,aAAa;AACjC,SAAKc,OAAQ;AACb;;AAGF,MADqB,MAAKT,OAAQ,UAAU,MAAKR,OAAQ,eACvC;AAGhB,OAAI,MAAKkB,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,MAAKlB,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,MAAKY,gBAAiB;AAE1C,SAAO;GACL;GACA,IAAI,MAAKZ,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,MAAMkB,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"}
|
|
1
|
+
{"version":3,"file":"telemetry-DMGwYVSd.js","names":["#cache","#generateKey","#cacheTtl","sanitizedEvent: Omit<TelemetryEvent, 'sk' | 'pk' | 'payload'> & TelemetryEvent['payload']","#getCache","#storageKey","err: unknown","#maxSize","DEFAULT_CONFIG: Partial<TelemetryCollectorConfig>","#config","#metadata","parsePublishableKey","#eventThrottler","isTruthy","#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":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
require('./constants-WYhx_umW.js');
|
|
2
2
|
require('./isomorphicAtob-Hkpnx2p8.js');
|
|
3
3
|
require('./isomorphicBtoa-_pSA92Q9.js');
|
|
4
|
-
require('./keys-
|
|
4
|
+
require('./keys-D5ahg2Gn.js');
|
|
5
5
|
require('./underscore-BX6Ucmg5.js');
|
|
6
|
-
const require_telemetry = require('./telemetry
|
|
6
|
+
const require_telemetry = require('./telemetry-DMGwYVSd.js');
|
|
7
7
|
|
|
8
8
|
exports.EVENT_SAMPLING_RATE = require_telemetry.EVENT_SAMPLING_RATE;
|
|
9
9
|
exports.EVENT_THEME_USAGE = require_telemetry.EVENT_THEME_USAGE;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./constants-Bta24VLk.mjs";
|
|
2
2
|
import "./isomorphicAtob-CoF80qYz.mjs";
|
|
3
3
|
import "./isomorphicBtoa-DWmLcIHi.mjs";
|
|
4
|
-
import "./keys-
|
|
4
|
+
import "./keys-BeVKH43u.mjs";
|
|
5
5
|
import "./underscore-ClYSgvuy.mjs";
|
|
6
|
-
import { a as eventMethodCalled, c as eventPrebuiltComponentOpened, i as eventFrameworkMetadata, l as TelemetryCollector, n as EVENT_THEME_USAGE, o as eventComponentMounted, r as eventThemeUsage, s as eventPrebuiltComponentMounted, t as EVENT_SAMPLING_RATE } from "./telemetry-
|
|
6
|
+
import { a as eventMethodCalled, c as eventPrebuiltComponentOpened, i as eventFrameworkMetadata, l as TelemetryCollector, n as EVENT_THEME_USAGE, o as eventComponentMounted, r as eventThemeUsage, s as eventPrebuiltComponentMounted, t as EVENT_SAMPLING_RATE } from "./telemetry-DJrefnDc.mjs";
|
|
7
7
|
|
|
8
8
|
export { EVENT_SAMPLING_RATE, EVENT_THEME_USAGE, TelemetryCollector, eventComponentMounted, eventFrameworkMetadata, eventMethodCalled, eventPrebuiltComponentMounted, eventPrebuiltComponentOpened, eventThemeUsage };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_keys = require('./keys-
|
|
1
|
+
const require_keys = require('./keys-D5ahg2Gn.js');
|
|
2
2
|
const require_globs = require('./globs-D0Kpu4g1.js');
|
|
3
3
|
const require_url = require('./url-sAcxbiir.js');
|
|
4
4
|
const require_logger = require('./logger-BOte4sQb.js');
|
|
@@ -404,4 +404,4 @@ Object.defineProperty(exports, 'trimTrailingSlash', {
|
|
|
404
404
|
return trimTrailingSlash;
|
|
405
405
|
}
|
|
406
406
|
});
|
|
407
|
-
//# sourceMappingURL=url-
|
|
407
|
+
//# sourceMappingURL=url-Cw4Wpvh3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-CoXV4i87.js","names":["createDevOrStagingUrlCache","isLegacyDevAccountPortalOrigin","isCurrentDevAccountPortalOrigin","camelToSnake","joinPaths","getQueryParams","frontendApiRedirectPathsWithUserInput: string[]","frontendApiRedirectPathsNoUserInput: string[]","globs","origins: string[]"],"sources":["../../src/internal/clerk-js/url.ts"],"sourcesContent":["import { globs } from '../../globs';\nimport { createDevOrStagingUrlCache } from '../../keys';\nimport { logger } from '../../logger';\nimport type { SignUpResource } from '../../types';\nimport { camelToSnake } from '../../underscore';\nimport { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '../../url';\nimport { joinPaths } from './path';\nimport { getQueryParams } from './querystring';\n\ndeclare global {\n export interface Window {\n tldts: {\n getDomain(hostname: string, { allowPrivateDomains }: { allowPrivateDomains: boolean }): string;\n };\n }\n}\n\n// This is used as a dummy base when we need to invoke \"new URL()\" but we don't care about the URL origin.\nconst DUMMY_URL_BASE = 'http://clerk-dummy';\n\nconst BANNED_URI_PROTOCOLS = ['javascript:'] as const;\n\n// Protocols that are dangerous specifically for href attributes in links\nconst BANNED_HREF_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'blob:'] as const;\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\nexport { isDevOrStagingUrl };\nconst accountPortalCache = new Map<string, boolean>();\n\nexport function isDevAccountPortalOrigin(hostname: string = window.location.hostname): boolean {\n if (!hostname) {\n return false;\n }\n\n let res = accountPortalCache.get(hostname);\n\n if (res === undefined) {\n res = isLegacyDevAccountPortalOrigin(hostname) || isCurrentDevAccountPortalOrigin(hostname);\n accountPortalCache.set(hostname, res);\n }\n\n return res;\n}\n\nexport function getETLDPlusOneFromFrontendApi(frontendApi: string): string {\n return frontendApi.replace('clerk.', '');\n}\n\ninterface BuildURLParams extends Partial<URL> {\n base?: string;\n hashPath?: string;\n hashSearch?: string;\n hashSearchParams?: URLSearchParams | Record<string, string> | Array<URLSearchParams | Record<string, string>>;\n}\n\ninterface BuildURLOptions<T> {\n skipOrigin?: boolean;\n stringify?: T;\n}\n\n/**\n *\n * buildURL(params: URLParams, options: BuildURLOptions): string\n *\n * Builds a URL safely by using the native URL() constructor. It can\n * also build a secondary path and search URL that lives inside the hash\n * of the main URL. For example:\n *\n * https://foo.com/bar?qux=42#/hash-bar?hash-qux=42\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param params\n * @param options\n * @returns Returns the URL href\n */\nexport function buildURL<B extends boolean>(\n params: BuildURLParams,\n options?: BuildURLOptions<B>,\n): B extends true ? string : URL;\n\nexport function buildURL(params: BuildURLParams, options: BuildURLOptions<boolean> = {}): URL | string {\n const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest } = params;\n\n let fallbackBase = '';\n // This check is necessary for React native environments where window is undefined.\n // TODO: Refactor all window and document usages in clerk-js and import them from\n // a single file that will be mocked easily in React native environments.\n if (typeof window !== 'undefined' && !!window.location) {\n fallbackBase = window.location.href;\n } else {\n fallbackBase = 'http://react-native-fake-base-url';\n }\n\n const url = new URL(base || '', fallbackBase);\n\n // Properly copy URLSearchParams\n if (searchParams instanceof URLSearchParams) {\n searchParams.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n url.searchParams.set(camelToSnake(key), value);\n }\n });\n }\n\n Object.assign(url, rest);\n\n // Treat that hash part of the main URL as if it's another URL with a pathname and a search.\n // Another nested hash inside the top level hash (e.g. #my-hash#my-second-hash) is currently\n // not supported as there is no use case for it yet.\n if (hashPath || hashSearch || hashSearchParams) {\n // Parse the hash to a URL object\n const dummyUrlForHash = new URL(DUMMY_URL_BASE + url.hash.substring(1));\n\n // Join the current hash path and with the provided one\n dummyUrlForHash.pathname = joinPaths(dummyUrlForHash.pathname, hashPath || '');\n\n // Merge search params from hashSearch string\n const searchParamsFromHashSearchString = getQueryParams(hashSearch || '');\n for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {\n dummyUrlForHash.searchParams.append(key, val);\n }\n\n // Merge search params from the hashSearchParams object\n if (hashSearchParams) {\n const paramsArr = Array.isArray(hashSearchParams) ? hashSearchParams : [hashSearchParams];\n for (const _params of paramsArr) {\n if (!(_params instanceof URLSearchParams) && typeof _params !== 'object') {\n continue;\n }\n const params = new URLSearchParams(_params);\n params.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n dummyUrlForHash.searchParams.set(camelToSnake(key), value);\n }\n });\n }\n }\n\n // Keep just the pathname and the search\n const newHash = dummyUrlForHash.href.replace(DUMMY_URL_BASE, '');\n\n // if the hash is `/`, it means that nothing new was added to the hash\n // so we can skip assigning it to the hash of the main url\n if (newHash !== '/') {\n // Assign them to the hash of the main url\n url.hash = newHash;\n }\n }\n\n const { stringify, skipOrigin } = options;\n if (stringify) {\n return skipOrigin ? url.href.replace(url.origin, '') : url.href;\n }\n return url;\n}\n\nexport function toURL(url: string | URL): URL {\n return new URL(url.toString(), window.location.origin);\n}\n\n/**\n *\n * stripOrigin(url: URL | string): string\n *\n * Strips the origin part of a URL and preserves path, search and hash is applicable\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param url\n * @returns Returns the URL href without the origin\n */\nexport function stripOrigin(url: URL | string): string {\n // In non-browser environments `window.location.origin` might not be available\n // if not polyfilled, so we can't construct a URL object with the `url` string\n // note: in that case, we can't easily strip the origin, so we return the original string\n if (typeof window.location === 'undefined' && typeof url === 'string') {\n return url;\n }\n\n url = toURL(url);\n return url.href.replace(url.origin, '');\n}\n\n/**\n * trimTrailingSlash(path: string): string\n *\n * Strips the trailing slashes from a string\n *\n * @returns Returns the string without trailing slashes\n *\n * @param path\n */\nexport const trimTrailingSlash = (path: string): string => {\n return (path || '').replace(/\\/+$/, '');\n};\n\n/**\n * trimLeadingSlash(path: string): string\n *\n * Strips the leading slashes from a string\n *\n * @returns Returns the string without leading slashes\n *\n * @param path\n */\nexport const trimLeadingSlash = (path: string): string => {\n return (path || '').replace(/^\\/+/, '');\n};\n\nexport const hasExternalAccountSignUpError = (signUp: SignUpResource): boolean => {\n const { externalAccount } = signUp.verifications;\n return !!externalAccount.error;\n};\n\nexport function getSearchParameterFromHash({\n hash = window.location.hash,\n paramName,\n}: {\n hash?: string;\n paramName: string;\n}) {\n const h = hash.startsWith('#') ? hash.substring(1) : hash;\n const dummyUrlForHash = new URL(h, DUMMY_URL_BASE);\n return dummyUrlForHash.searchParams.get(paramName);\n}\n\nexport function isValidUrl(val: string | URL | undefined | null): boolean {\n if (!val) {\n return false;\n }\n\n try {\n new URL(val as string);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function relativeToAbsoluteUrl(url: string, origin: string | URL): URL {\n try {\n return new URL(url);\n } catch {\n return new URL(url, origin);\n }\n}\n\n// Regular expression to detect disallowed patterns\nconst disallowedPatterns = [\n /\\0/, // Null bytes\n /^\\/\\//, // Protocol-relative\n // eslint-disable-next-line no-control-regex\n /[\\x00-\\x1F]/, // Control characters\n];\n\n/**\n * Check for potentially problematic URLs that could have been crafted to intentionally bypass the origin check. Note that the URLs passed to this\n * function are assumed to be from an \"allowed origin\", so we are not executing origin-specific checks here.\n */\nexport function isProblematicUrl(url: URL): boolean {\n if (hasBannedProtocol(url)) {\n return true;\n }\n // Check against disallowed patterns\n for (const pattern of disallowedPatterns) {\n if (pattern.test(url.pathname)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isDataUri(val?: string): val is string {\n if (!val || !isValidUrl(val)) {\n return false;\n }\n\n return new URL(val).protocol === 'data:';\n}\n\n/**\n * Checks if a URL uses javascript: protocol.\n * This prevents some XSS attacks through javascript: URLs.\n *\n * IMPORTANT: This does not check for `data:` or other protocols which\n * are dangerous if used for links or setting the window location.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedProtocol(val: string | URL) {\n if (!isValidUrl(val)) {\n return false;\n }\n const protocol = new URL(val).protocol;\n return BANNED_URI_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Checks if a URL contains a banned protocol for href attributes in links.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedHrefProtocol(val: string | URL): boolean {\n if (!isValidUrl(val)) {\n return false;\n }\n const protocol = new URL(val).protocol;\n return BANNED_HREF_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Sanitizes an href value by checking for dangerous protocols.\n * Returns null if the href contains a dangerous protocol, otherwise returns the original href.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param href - The href value to sanitize\n * @returns The sanitized href or null if dangerous\n */\nexport function sanitizeHref(href: string | undefined | null): string | null {\n if (!href || href.trim() === '') {\n return null;\n }\n\n // For relative URLs (starting with / or # or ?), allow them through\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n\n // For relative URLs without leading slash, allow them through\n if (!href.includes(':')) {\n return href;\n }\n\n // Check if it's a valid URL with a dangerous protocol\n try {\n const url = new URL(href);\n if (hasBannedHrefProtocol(url)) {\n return null;\n }\n return href;\n } catch {\n // If URL parsing fails, it's likely a relative URL or malformed\n // Allow relative URLs through, but be cautious with malformed ones\n return href;\n }\n}\n\nexport const hasUrlInFragment = (_url: URL | string) => {\n return new URL(_url, DUMMY_URL_BASE).hash.startsWith('#/');\n};\n\n/**\n * Creates a new URL by merging a fragment-based URL, if found.\n * The result URL has the original and the fragment pathnames appended\n * and also includes all search params from both places.\n *\n * @example\n * ```ts\n * mergeFragmentIntoUrl('https://accounts.clerk.com/sign-in?user_param=hello#/verify/factor-one?redirect_url=/protected')\n * // Returns: 'https://accounts.clerk.com/sign-in/verify/factor-one?user_param=hello&redirect_url=/protected'\n * ```\n */\nexport const mergeFragmentIntoUrl = (_url: string | URL): URL => {\n const url = new URL(_url);\n\n if (!hasUrlInFragment(url)) {\n return url;\n }\n\n const fragmentUrl = new URL(url.hash.replace('#/', '/'), url.href);\n const mergedPathname = [url.pathname, fragmentUrl.pathname]\n .map(s => s.split('/'))\n .flat()\n .filter(Boolean)\n .join('/');\n\n const mergedUrl = new URL(mergedPathname, url.origin);\n\n url.searchParams.forEach((val, key) => {\n mergedUrl.searchParams.set(key, val);\n });\n\n fragmentUrl.searchParams.forEach((val, key) => {\n mergedUrl.searchParams.set(key, val);\n });\n\n return mergedUrl;\n};\n\nexport const pathFromFullPath = (fullPath: string) => {\n return fullPath.replace(/CLERK-ROUTER\\/(.*?)\\//, '');\n};\n\nconst frontendApiRedirectPathsWithUserInput: string[] = [\n '/oauth/authorize', // OAuth2 identify provider flow\n];\n\nconst frontendApiRedirectPathsNoUserInput: string[] = [\n '/v1/verify', // magic links\n '/v1/tickets/accept', // ticket flow\n '/oauth/authorize-with-immediate-redirect', // OAuth 2 identity provider\n '/oauth/end_session', // OIDC logout\n];\n\nexport function isRedirectForFAPIInitiatedFlow(frontendApi: string, redirectUrl: string): boolean {\n const url = new URL(redirectUrl, DUMMY_URL_BASE);\n const path = url.pathname;\n\n const isValidFrontendRedirectPath =\n frontendApiRedirectPathsWithUserInput.includes(path) || frontendApiRedirectPathsNoUserInput.includes(path);\n return frontendApi === url.host && isValidFrontendRedirectPath;\n}\n\nexport function requiresUserInput(redirectUrl: string): boolean {\n const url = new URL(redirectUrl, DUMMY_URL_BASE);\n return frontendApiRedirectPathsWithUserInput.includes(url.pathname);\n}\n\nexport const isAllowedRedirect =\n (allowedRedirectOrigins: Array<string | RegExp> | undefined, currentOrigin: string) => (_url: URL | string) => {\n let url = _url;\n if (typeof url === 'string') {\n url = relativeToAbsoluteUrl(url, currentOrigin);\n }\n\n if (!allowedRedirectOrigins) {\n return true;\n }\n\n const isSameOrigin = currentOrigin === url.origin;\n\n const isAllowed =\n !isProblematicUrl(url) &&\n (isSameOrigin ||\n allowedRedirectOrigins\n .map(origin => (typeof origin === 'string' ? globs.toRegexp(trimTrailingSlash(origin)) : origin))\n .some(origin => origin.test(trimTrailingSlash(url.origin))));\n\n if (!isAllowed) {\n logger.warnOnce(\n `Clerk: Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`,\n );\n }\n return isAllowed;\n };\n\nexport function createAllowedRedirectOrigins(\n allowedRedirectOrigins: Array<string | RegExp> | undefined,\n frontendApi: string,\n instanceType?: string,\n): (string | RegExp)[] | undefined {\n if (Array.isArray(allowedRedirectOrigins) && !!allowedRedirectOrigins.length) {\n return allowedRedirectOrigins;\n }\n\n const origins: string[] = [];\n if (typeof window !== 'undefined' && !!window.location) {\n origins.push(window.location.origin);\n }\n\n origins.push(`https://${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n origins.push(`https://*.${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n\n if (instanceType === 'development') {\n origins.push(`https://${frontendApi}`);\n }\n\n return origins;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"url-Cw4Wpvh3.js","names":["createDevOrStagingUrlCache","isLegacyDevAccountPortalOrigin","isCurrentDevAccountPortalOrigin","camelToSnake","joinPaths","getQueryParams","frontendApiRedirectPathsWithUserInput: string[]","frontendApiRedirectPathsNoUserInput: string[]","globs","origins: string[]"],"sources":["../../src/internal/clerk-js/url.ts"],"sourcesContent":["import { globs } from '../../globs';\nimport { createDevOrStagingUrlCache } from '../../keys';\nimport { logger } from '../../logger';\nimport type { SignUpResource } from '../../types';\nimport { camelToSnake } from '../../underscore';\nimport { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '../../url';\nimport { joinPaths } from './path';\nimport { getQueryParams } from './querystring';\n\ndeclare global {\n export interface Window {\n tldts: {\n getDomain(hostname: string, { allowPrivateDomains }: { allowPrivateDomains: boolean }): string;\n };\n }\n}\n\n// This is used as a dummy base when we need to invoke \"new URL()\" but we don't care about the URL origin.\nconst DUMMY_URL_BASE = 'http://clerk-dummy';\n\nconst BANNED_URI_PROTOCOLS = ['javascript:'] as const;\n\n// Protocols that are dangerous specifically for href attributes in links\nconst BANNED_HREF_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'blob:'] as const;\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\nexport { isDevOrStagingUrl };\nconst accountPortalCache = new Map<string, boolean>();\n\nexport function isDevAccountPortalOrigin(hostname: string = window.location.hostname): boolean {\n if (!hostname) {\n return false;\n }\n\n let res = accountPortalCache.get(hostname);\n\n if (res === undefined) {\n res = isLegacyDevAccountPortalOrigin(hostname) || isCurrentDevAccountPortalOrigin(hostname);\n accountPortalCache.set(hostname, res);\n }\n\n return res;\n}\n\nexport function getETLDPlusOneFromFrontendApi(frontendApi: string): string {\n return frontendApi.replace('clerk.', '');\n}\n\ninterface BuildURLParams extends Partial<URL> {\n base?: string;\n hashPath?: string;\n hashSearch?: string;\n hashSearchParams?: URLSearchParams | Record<string, string> | Array<URLSearchParams | Record<string, string>>;\n}\n\ninterface BuildURLOptions<T> {\n skipOrigin?: boolean;\n stringify?: T;\n}\n\n/**\n *\n * buildURL(params: URLParams, options: BuildURLOptions): string\n *\n * Builds a URL safely by using the native URL() constructor. It can\n * also build a secondary path and search URL that lives inside the hash\n * of the main URL. For example:\n *\n * https://foo.com/bar?qux=42#/hash-bar?hash-qux=42\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param params\n * @param options\n * @returns Returns the URL href\n */\nexport function buildURL<B extends boolean>(\n params: BuildURLParams,\n options?: BuildURLOptions<B>,\n): B extends true ? string : URL;\n\nexport function buildURL(params: BuildURLParams, options: BuildURLOptions<boolean> = {}): URL | string {\n const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest } = params;\n\n let fallbackBase = '';\n // This check is necessary for React native environments where window is undefined.\n // TODO: Refactor all window and document usages in clerk-js and import them from\n // a single file that will be mocked easily in React native environments.\n if (typeof window !== 'undefined' && !!window.location) {\n fallbackBase = window.location.href;\n } else {\n fallbackBase = 'http://react-native-fake-base-url';\n }\n\n const url = new URL(base || '', fallbackBase);\n\n // Properly copy URLSearchParams\n if (searchParams instanceof URLSearchParams) {\n searchParams.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n url.searchParams.set(camelToSnake(key), value);\n }\n });\n }\n\n Object.assign(url, rest);\n\n // Treat that hash part of the main URL as if it's another URL with a pathname and a search.\n // Another nested hash inside the top level hash (e.g. #my-hash#my-second-hash) is currently\n // not supported as there is no use case for it yet.\n if (hashPath || hashSearch || hashSearchParams) {\n // Parse the hash to a URL object\n const dummyUrlForHash = new URL(DUMMY_URL_BASE + url.hash.substring(1));\n\n // Join the current hash path and with the provided one\n dummyUrlForHash.pathname = joinPaths(dummyUrlForHash.pathname, hashPath || '');\n\n // Merge search params from hashSearch string\n const searchParamsFromHashSearchString = getQueryParams(hashSearch || '');\n for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {\n dummyUrlForHash.searchParams.append(key, val);\n }\n\n // Merge search params from the hashSearchParams object\n if (hashSearchParams) {\n const paramsArr = Array.isArray(hashSearchParams) ? hashSearchParams : [hashSearchParams];\n for (const _params of paramsArr) {\n if (!(_params instanceof URLSearchParams) && typeof _params !== 'object') {\n continue;\n }\n const params = new URLSearchParams(_params);\n params.forEach((value, key) => {\n if (value !== null && value !== undefined) {\n dummyUrlForHash.searchParams.set(camelToSnake(key), value);\n }\n });\n }\n }\n\n // Keep just the pathname and the search\n const newHash = dummyUrlForHash.href.replace(DUMMY_URL_BASE, '');\n\n // if the hash is `/`, it means that nothing new was added to the hash\n // so we can skip assigning it to the hash of the main url\n if (newHash !== '/') {\n // Assign them to the hash of the main url\n url.hash = newHash;\n }\n }\n\n const { stringify, skipOrigin } = options;\n if (stringify) {\n return skipOrigin ? url.href.replace(url.origin, '') : url.href;\n }\n return url;\n}\n\nexport function toURL(url: string | URL): URL {\n return new URL(url.toString(), window.location.origin);\n}\n\n/**\n *\n * stripOrigin(url: URL | string): string\n *\n * Strips the origin part of a URL and preserves path, search and hash is applicable\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param url\n * @returns Returns the URL href without the origin\n */\nexport function stripOrigin(url: URL | string): string {\n // In non-browser environments `window.location.origin` might not be available\n // if not polyfilled, so we can't construct a URL object with the `url` string\n // note: in that case, we can't easily strip the origin, so we return the original string\n if (typeof window.location === 'undefined' && typeof url === 'string') {\n return url;\n }\n\n url = toURL(url);\n return url.href.replace(url.origin, '');\n}\n\n/**\n * trimTrailingSlash(path: string): string\n *\n * Strips the trailing slashes from a string\n *\n * @returns Returns the string without trailing slashes\n *\n * @param path\n */\nexport const trimTrailingSlash = (path: string): string => {\n return (path || '').replace(/\\/+$/, '');\n};\n\n/**\n * trimLeadingSlash(path: string): string\n *\n * Strips the leading slashes from a string\n *\n * @returns Returns the string without leading slashes\n *\n * @param path\n */\nexport const trimLeadingSlash = (path: string): string => {\n return (path || '').replace(/^\\/+/, '');\n};\n\nexport const hasExternalAccountSignUpError = (signUp: SignUpResource): boolean => {\n const { externalAccount } = signUp.verifications;\n return !!externalAccount.error;\n};\n\nexport function getSearchParameterFromHash({\n hash = window.location.hash,\n paramName,\n}: {\n hash?: string;\n paramName: string;\n}) {\n const h = hash.startsWith('#') ? hash.substring(1) : hash;\n const dummyUrlForHash = new URL(h, DUMMY_URL_BASE);\n return dummyUrlForHash.searchParams.get(paramName);\n}\n\nexport function isValidUrl(val: string | URL | undefined | null): boolean {\n if (!val) {\n return false;\n }\n\n try {\n new URL(val as string);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function relativeToAbsoluteUrl(url: string, origin: string | URL): URL {\n try {\n return new URL(url);\n } catch {\n return new URL(url, origin);\n }\n}\n\n// Regular expression to detect disallowed patterns\nconst disallowedPatterns = [\n /\\0/, // Null bytes\n /^\\/\\//, // Protocol-relative\n // eslint-disable-next-line no-control-regex\n /[\\x00-\\x1F]/, // Control characters\n];\n\n/**\n * Check for potentially problematic URLs that could have been crafted to intentionally bypass the origin check. Note that the URLs passed to this\n * function are assumed to be from an \"allowed origin\", so we are not executing origin-specific checks here.\n */\nexport function isProblematicUrl(url: URL): boolean {\n if (hasBannedProtocol(url)) {\n return true;\n }\n // Check against disallowed patterns\n for (const pattern of disallowedPatterns) {\n if (pattern.test(url.pathname)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function isDataUri(val?: string): val is string {\n if (!val || !isValidUrl(val)) {\n return false;\n }\n\n return new URL(val).protocol === 'data:';\n}\n\n/**\n * Checks if a URL uses javascript: protocol.\n * This prevents some XSS attacks through javascript: URLs.\n *\n * IMPORTANT: This does not check for `data:` or other protocols which\n * are dangerous if used for links or setting the window location.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedProtocol(val: string | URL) {\n if (!isValidUrl(val)) {\n return false;\n }\n const protocol = new URL(val).protocol;\n return BANNED_URI_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Checks if a URL contains a banned protocol for href attributes in links.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedHrefProtocol(val: string | URL): boolean {\n if (!isValidUrl(val)) {\n return false;\n }\n const protocol = new URL(val).protocol;\n return BANNED_HREF_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Sanitizes an href value by checking for dangerous protocols.\n * Returns null if the href contains a dangerous protocol, otherwise returns the original href.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param href - The href value to sanitize\n * @returns The sanitized href or null if dangerous\n */\nexport function sanitizeHref(href: string | undefined | null): string | null {\n if (!href || href.trim() === '') {\n return null;\n }\n\n // For relative URLs (starting with / or # or ?), allow them through\n if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n return href;\n }\n\n // For relative URLs without leading slash, allow them through\n if (!href.includes(':')) {\n return href;\n }\n\n // Check if it's a valid URL with a dangerous protocol\n try {\n const url = new URL(href);\n if (hasBannedHrefProtocol(url)) {\n return null;\n }\n return href;\n } catch {\n // If URL parsing fails, it's likely a relative URL or malformed\n // Allow relative URLs through, but be cautious with malformed ones\n return href;\n }\n}\n\nexport const hasUrlInFragment = (_url: URL | string) => {\n return new URL(_url, DUMMY_URL_BASE).hash.startsWith('#/');\n};\n\n/**\n * Creates a new URL by merging a fragment-based URL, if found.\n * The result URL has the original and the fragment pathnames appended\n * and also includes all search params from both places.\n *\n * @example\n * ```ts\n * mergeFragmentIntoUrl('https://accounts.clerk.com/sign-in?user_param=hello#/verify/factor-one?redirect_url=/protected')\n * // Returns: 'https://accounts.clerk.com/sign-in/verify/factor-one?user_param=hello&redirect_url=/protected'\n * ```\n */\nexport const mergeFragmentIntoUrl = (_url: string | URL): URL => {\n const url = new URL(_url);\n\n if (!hasUrlInFragment(url)) {\n return url;\n }\n\n const fragmentUrl = new URL(url.hash.replace('#/', '/'), url.href);\n const mergedPathname = [url.pathname, fragmentUrl.pathname]\n .map(s => s.split('/'))\n .flat()\n .filter(Boolean)\n .join('/');\n\n const mergedUrl = new URL(mergedPathname, url.origin);\n\n url.searchParams.forEach((val, key) => {\n mergedUrl.searchParams.set(key, val);\n });\n\n fragmentUrl.searchParams.forEach((val, key) => {\n mergedUrl.searchParams.set(key, val);\n });\n\n return mergedUrl;\n};\n\nexport const pathFromFullPath = (fullPath: string) => {\n return fullPath.replace(/CLERK-ROUTER\\/(.*?)\\//, '');\n};\n\nconst frontendApiRedirectPathsWithUserInput: string[] = [\n '/oauth/authorize', // OAuth2 identify provider flow\n];\n\nconst frontendApiRedirectPathsNoUserInput: string[] = [\n '/v1/verify', // magic links\n '/v1/tickets/accept', // ticket flow\n '/oauth/authorize-with-immediate-redirect', // OAuth 2 identity provider\n '/oauth/end_session', // OIDC logout\n];\n\nexport function isRedirectForFAPIInitiatedFlow(frontendApi: string, redirectUrl: string): boolean {\n const url = new URL(redirectUrl, DUMMY_URL_BASE);\n const path = url.pathname;\n\n const isValidFrontendRedirectPath =\n frontendApiRedirectPathsWithUserInput.includes(path) || frontendApiRedirectPathsNoUserInput.includes(path);\n return frontendApi === url.host && isValidFrontendRedirectPath;\n}\n\nexport function requiresUserInput(redirectUrl: string): boolean {\n const url = new URL(redirectUrl, DUMMY_URL_BASE);\n return frontendApiRedirectPathsWithUserInput.includes(url.pathname);\n}\n\nexport const isAllowedRedirect =\n (allowedRedirectOrigins: Array<string | RegExp> | undefined, currentOrigin: string) => (_url: URL | string) => {\n let url = _url;\n if (typeof url === 'string') {\n url = relativeToAbsoluteUrl(url, currentOrigin);\n }\n\n if (!allowedRedirectOrigins) {\n return true;\n }\n\n const isSameOrigin = currentOrigin === url.origin;\n\n const isAllowed =\n !isProblematicUrl(url) &&\n (isSameOrigin ||\n allowedRedirectOrigins\n .map(origin => (typeof origin === 'string' ? globs.toRegexp(trimTrailingSlash(origin)) : origin))\n .some(origin => origin.test(trimTrailingSlash(url.origin))));\n\n if (!isAllowed) {\n logger.warnOnce(\n `Clerk: Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`,\n );\n }\n return isAllowed;\n };\n\nexport function createAllowedRedirectOrigins(\n allowedRedirectOrigins: Array<string | RegExp> | undefined,\n frontendApi: string,\n instanceType?: string,\n): (string | RegExp)[] | undefined {\n if (Array.isArray(allowedRedirectOrigins) && !!allowedRedirectOrigins.length) {\n return allowedRedirectOrigins;\n }\n\n const origins: string[] = [];\n if (typeof window !== 'undefined' && !!window.location) {\n origins.push(window.location.origin);\n }\n\n origins.push(`https://${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n origins.push(`https://*.${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n\n if (instanceType === 'development') {\n origins.push(`https://${frontendApi}`);\n }\n\n return origins;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as createDevOrStagingUrlCache } from "./keys-
|
|
1
|
+
import { n as createDevOrStagingUrlCache } from "./keys-BeVKH43u.mjs";
|
|
2
2
|
import { t as globs } from "./globs-u_gXJPLt.mjs";
|
|
3
3
|
import { c as isCurrentDevAccountPortalOrigin, l as isLegacyDevAccountPortalOrigin } from "./url-C6gPMFx5.mjs";
|
|
4
4
|
import { t as logger } from "./logger-DISzhF9M.mjs";
|
|
@@ -261,4 +261,4 @@ function createAllowedRedirectOrigins(allowedRedirectOrigins, frontendApi, insta
|
|
|
261
261
|
|
|
262
262
|
//#endregion
|
|
263
263
|
export { trimLeadingSlash as C, toURL as S, pathFromFullPath as _, hasBannedHrefProtocol as a, sanitizeHref as b, hasUrlInFragment as c, isDevAccountPortalOrigin as d, isDevOrStagingUrl as f, mergeFragmentIntoUrl as g, isValidUrl as h, getSearchParameterFromHash as i, isAllowedRedirect as l, isRedirectForFAPIInitiatedFlow as m, createAllowedRedirectOrigins as n, hasBannedProtocol as o, isProblematicUrl as p, getETLDPlusOneFromFrontendApi as r, hasExternalAccountSignUpError as s, buildURL as t, isDataUri as u, relativeToAbsoluteUrl as v, trimTrailingSlash as w, stripOrigin as x, requiresUserInput as y };
|
|
264
|
-
//# sourceMappingURL=url-
|
|
264
|
+
//# sourceMappingURL=url-cNLJYbcB.mjs.map
|