From 10b0d071a706934e4fa0985f96f0d291f32a5552 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Tue, 12 Aug 2025 13:43:36 -0400 Subject: [PATCH 01/13] feat(clerk-js,themes,shared): Add theme-usage telemetry --- .../src/contexts/ClerkContextProvider.tsx | 9 + packages/shared/src/telemetry.ts | 1 + packages/shared/src/telemetry/events/index.ts | 1 + .../src/telemetry/events/theme-usage.ts | 26 +++ .../utils/__tests__/analyzeThemeUsage.test.ts | 157 ++++++++++++++++++ .../src/telemetry/utils/analyzeThemeUsage.ts | 56 +++++++ packages/shared/src/telemetry/utils/index.ts | 1 + packages/themes/src/createTheme.ts | 8 + packages/themes/src/themes/shadcn.ts | 1 + 9 files changed, 260 insertions(+) create mode 100644 packages/shared/src/telemetry/events/theme-usage.ts create mode 100644 packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts create mode 100644 packages/shared/src/telemetry/utils/analyzeThemeUsage.ts create mode 100644 packages/shared/src/telemetry/utils/index.ts diff --git a/packages/react/src/contexts/ClerkContextProvider.tsx b/packages/react/src/contexts/ClerkContextProvider.tsx index f38f9f785f5..3e29523c702 100644 --- a/packages/react/src/contexts/ClerkContextProvider.tsx +++ b/packages/react/src/contexts/ClerkContextProvider.tsx @@ -6,6 +6,7 @@ import { SessionContext, UserContext, } from '@clerk/shared/react'; +import { analyzeThemeUsage, eventThemeUsage } from '@clerk/shared/telemetry'; import type { ClientResource, InitialState, Resources } from '@clerk/types'; import React from 'react'; @@ -119,6 +120,14 @@ const useLoadedIsomorphicClerk = (options: IsomorphicClerkOptions) => { void isomorphicClerkRef.current.__unstable__updateProps({ appearance: options.appearance }); }, [options.appearance]); + // Record theme usage telemetry when appearance changes + React.useEffect(() => { + if (options.appearance && isomorphicClerkRef.current.telemetry) { + const themeAnalysis = analyzeThemeUsage(options.appearance); + isomorphicClerkRef.current.telemetry.record(eventThemeUsage(themeAnalysis)); + } + }, [options.appearance]); + React.useEffect(() => { void isomorphicClerkRef.current.__unstable__updateProps({ options }); }, [options.localization]); diff --git a/packages/shared/src/telemetry.ts b/packages/shared/src/telemetry.ts index 3f80deefed7..922383e41c7 100644 --- a/packages/shared/src/telemetry.ts +++ b/packages/shared/src/telemetry.ts @@ -2,3 +2,4 @@ export { TelemetryCollector } from './telemetry/collector'; export type { TelemetryCollectorOptions } from './telemetry/types'; export * from './telemetry/events'; +export * from './telemetry/utils'; diff --git a/packages/shared/src/telemetry/events/index.ts b/packages/shared/src/telemetry/events/index.ts index e9ad6ca4ceb..84b7c4eb5de 100644 --- a/packages/shared/src/telemetry/events/index.ts +++ b/packages/shared/src/telemetry/events/index.ts @@ -1,3 +1,4 @@ export * from './component-mounted'; export * from './method-called'; export * from './framework-metadata'; +export * from './theme-usage'; diff --git a/packages/shared/src/telemetry/events/theme-usage.ts b/packages/shared/src/telemetry/events/theme-usage.ts new file mode 100644 index 00000000000..49cf98b4561 --- /dev/null +++ b/packages/shared/src/telemetry/events/theme-usage.ts @@ -0,0 +1,26 @@ +import type { TelemetryEventRaw } from '@clerk/types'; + +const EVENT_THEME_USAGE = 'THEME_USAGE'; +const EVENT_SAMPLING_RATE = 0.1; + +type EventThemeUsage = { + /** + * The name of the theme being used (e.g., "shadcn", "neobrutalism", etc.). + */ + themeName?: string; +}; + +/** + * Helper function for `telemetry.record()`. Create a consistent event object for tracking theme usage in ClerkProvider. + * + * @param payload - Theme usage data to track. + * @example + * telemetry.record(eventThemeUsage({ themeName: 'shadcn' })); + */ +export function eventThemeUsage(payload: EventThemeUsage): TelemetryEventRaw { + return { + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, + payload, + }; +} diff --git a/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts b/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts new file mode 100644 index 00000000000..7696dfac906 --- /dev/null +++ b/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts @@ -0,0 +1,157 @@ +import type { Appearance } from '@clerk/types'; + +import { analyzeThemeUsage } from '../analyzeThemeUsage'; + +describe('analyzeThemeUsage', () => { + it('returns empty object for undefined appearance', () => { + const result = analyzeThemeUsage(undefined); + expect(result).toEqual({}); + }); + + it('returns empty object for empty appearance object', () => { + const result = analyzeThemeUsage({}); + expect(result).toEqual({}); + }); + + it('returns empty object when no theme is provided', () => { + const appearance: Appearance = { + variables: { colorPrimary: '#ff0000' }, + elements: { button: 'custom-class' }, + }; + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({}); + }); + + it('identifies shadcn theme correctly from explicit theme name', () => { + const appearance: Appearance = { + theme: { + __type: 'prebuilt_appearance', + __themeName: 'shadcn', + variables: { + colorBackground: 'var(--card)', + colorPrimary: 'var(--primary)', + }, + elements: { + input: 'bg-transparent dark:bg-input/30', + }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'shadcn' }); + }); + + it('identifies shadcn theme correctly from baseTheme with explicit name', () => { + const appearance: Appearance = { + baseTheme: { + __type: 'prebuilt_appearance', + __themeName: 'shadcn', + variables: { + colorBackground: 'var(--card)', + colorPrimary: 'var(--primary)', + }, + elements: { + input: 'bg-transparent dark:bg-input/30', + }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'shadcn' }); + }); + + it('prioritizes theme over baseTheme when both are present', () => { + const appearance: Appearance = { + theme: 'simple' as any, + baseTheme: { + __type: 'prebuilt_appearance', + variables: { + colorBackground: 'var(--card)', + colorPrimary: 'var(--primary)', + }, + elements: { + input: 'bg-transparent dark:bg-input/30', + }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'simple' }); + }); + + it('handles string themes', () => { + const appearance: Appearance = { + theme: 'clerk' as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'clerk' }); + }); + + it('finds first identifiable theme in array', () => { + const appearance: Appearance = { + theme: [ + { customProp: 'value' }, // Custom theme, no identifiable name + { + __type: 'prebuilt_appearance', + __themeName: 'shadcn', + variables: { + colorBackground: 'var(--card)', + colorPrimary: 'var(--primary)', + }, + elements: { + input: 'bg-transparent dark:bg-input/30', + }, + }, + ] as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'shadcn' }); + }); + + it('returns undefined theme name for unidentifiable themes', () => { + const appearance: Appearance = { + theme: { + __type: 'prebuilt_appearance', + variables: { colorPrimary: '#custom' }, + elements: { button: 'custom-style' }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: undefined }); + }); + + it('returns undefined for themes without explicit names', () => { + const appearance: Appearance = { + theme: { + __type: 'prebuilt_appearance', + // No __themeName property - should return undefined + variables: { + colorBackground: 'var(--card)', + colorPrimary: 'var(--primary)', + }, + elements: { + input: 'bg-transparent dark:bg-input/30', + }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: undefined }); + }); + + it('handles custom theme names', () => { + const appearance: Appearance = { + theme: { + __type: 'prebuilt_appearance', + __themeName: 'my-custom-theme', + variables: { colorPrimary: '#purple' }, + } as any, + }; + + const result = analyzeThemeUsage(appearance); + expect(result).toEqual({ themeName: 'my-custom-theme' }); + }); +}); diff --git a/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts b/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts new file mode 100644 index 00000000000..ea6671c0073 --- /dev/null +++ b/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts @@ -0,0 +1,56 @@ +import type { Appearance, BaseTheme } from '@clerk/types'; + +type ThemeUsageAnalysis = { + themeName?: string; +}; + +/** + * Analyzes the appearance prop to extract theme usage information for telemetry. + */ +export function analyzeThemeUsage(appearance?: Appearance): ThemeUsageAnalysis { + if (!appearance || typeof appearance !== 'object') { + return {}; + } + + // Prioritize the new theme property over deprecated baseTheme + const themeProperty = appearance.theme || appearance.baseTheme; + + if (!themeProperty) { + return {}; + } + + let themeName: string | undefined; + + if (Array.isArray(themeProperty)) { + // Look for the first identifiable theme name in the array + for (const theme of themeProperty) { + const name = extractThemeName(theme); + if (name) { + themeName = name; + break; + } + } + } else { + themeName = extractThemeName(themeProperty); + } + + return { themeName }; +} + +/** + * Extracts the theme name from a theme object. + */ +function extractThemeName(theme: BaseTheme): string | undefined { + if (typeof theme === 'string') { + return theme; + } + + if (typeof theme === 'object' && theme !== null) { + // Check for explicit theme name + if ('__themeName' in theme && typeof theme.__themeName === 'string') { + return theme.__themeName; + } + } + + return undefined; +} diff --git a/packages/shared/src/telemetry/utils/index.ts b/packages/shared/src/telemetry/utils/index.ts new file mode 100644 index 00000000000..5d7a20c4f81 --- /dev/null +++ b/packages/shared/src/telemetry/utils/index.ts @@ -0,0 +1 @@ +export * from './analyzeThemeUsage'; diff --git a/packages/themes/src/createTheme.ts b/packages/themes/src/createTheme.ts index 2c5e86f844e..02f060841e1 100644 --- a/packages/themes/src/createTheme.ts +++ b/packages/themes/src/createTheme.ts @@ -5,6 +5,12 @@ import type { Appearance, BaseTheme, DeepPartial, Elements, Theme } from '@clerk import type { InternalTheme } from '../../clerk-js/src/ui/foundations'; interface CreateClerkThemeParams extends DeepPartial { + /** + * Optional name for the theme, used for telemetry and debugging. + * @example 'shadcn', 'neobrutalism', 'custom-dark' + */ + name?: string; + /** * {@link Theme.elements} */ @@ -16,5 +22,7 @@ export const experimental_createTheme = (appearance: Appearance Date: Tue, 12 Aug 2025 14:16:15 -0400 Subject: [PATCH 02/13] add to clerk --- packages/clerk-js/src/core/clerk.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 539b50e961e..ab68b18830b 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -8,8 +8,10 @@ import { logger } from '@clerk/shared/logger'; import { CLERK_NETLIFY_CACHE_BUST_PARAM } from '@clerk/shared/netlifyCacheHandler'; import { isHttpOrHttps, isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy'; import { + analyzeThemeUsage, eventPrebuiltComponentMounted, eventPrebuiltComponentOpened, + eventThemeUsage, TelemetryCollector, } from '@clerk/shared/telemetry'; import { addClerkPrefix, isAbsoluteUrl, stripScheme } from '@clerk/shared/url'; @@ -443,6 +445,12 @@ export class Clerk implements ClerkInterface { publishableKey: this.publishableKey, ...this.#options.telemetry, }); + + // Record theme usage telemetry when appearance is provided + if (this.#options.appearance) { + const themeAnalysis = analyzeThemeUsage(this.#options.appearance); + this.telemetry.record(eventThemeUsage(themeAnalysis)); + } } try { From a3416ad8b6682ce85ef38066eb798e3dc9a1f92f Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Tue, 12 Aug 2025 14:23:56 -0400 Subject: [PATCH 03/13] refactor --- packages/clerk-js/src/core/clerk.ts | 4 +- .../src/contexts/ClerkContextProvider.tsx | 5 +- packages/shared/src/telemetry.ts | 1 - .../events/__tests__/theme-usage.test.ts | 127 ++++++++++++++ .../src/telemetry/events/theme-usage.ts | 65 +++++++- .../utils/__tests__/analyzeThemeUsage.test.ts | 157 ------------------ .../src/telemetry/utils/analyzeThemeUsage.ts | 56 ------- packages/shared/src/telemetry/utils/index.ts | 1 - packages/themes/src/themes/dark.ts | 1 + packages/themes/src/themes/neobrutalism.ts | 1 + packages/themes/src/themes/shadesOfPurple.ts | 1 + packages/themes/src/themes/simple.ts | 1 + 12 files changed, 195 insertions(+), 225 deletions(-) create mode 100644 packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts delete mode 100644 packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts delete mode 100644 packages/shared/src/telemetry/utils/analyzeThemeUsage.ts delete mode 100644 packages/shared/src/telemetry/utils/index.ts diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index ab68b18830b..d3e09dfc168 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -8,7 +8,6 @@ import { logger } from '@clerk/shared/logger'; import { CLERK_NETLIFY_CACHE_BUST_PARAM } from '@clerk/shared/netlifyCacheHandler'; import { isHttpOrHttps, isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy'; import { - analyzeThemeUsage, eventPrebuiltComponentMounted, eventPrebuiltComponentOpened, eventThemeUsage, @@ -448,8 +447,7 @@ export class Clerk implements ClerkInterface { // Record theme usage telemetry when appearance is provided if (this.#options.appearance) { - const themeAnalysis = analyzeThemeUsage(this.#options.appearance); - this.telemetry.record(eventThemeUsage(themeAnalysis)); + this.telemetry.record(eventThemeUsage(this.#options.appearance)); } } diff --git a/packages/react/src/contexts/ClerkContextProvider.tsx b/packages/react/src/contexts/ClerkContextProvider.tsx index 3e29523c702..87540bebfab 100644 --- a/packages/react/src/contexts/ClerkContextProvider.tsx +++ b/packages/react/src/contexts/ClerkContextProvider.tsx @@ -6,7 +6,7 @@ import { SessionContext, UserContext, } from '@clerk/shared/react'; -import { analyzeThemeUsage, eventThemeUsage } from '@clerk/shared/telemetry'; +import { eventThemeUsage } from '@clerk/shared/telemetry'; import type { ClientResource, InitialState, Resources } from '@clerk/types'; import React from 'react'; @@ -123,8 +123,7 @@ const useLoadedIsomorphicClerk = (options: IsomorphicClerkOptions) => { // Record theme usage telemetry when appearance changes React.useEffect(() => { if (options.appearance && isomorphicClerkRef.current.telemetry) { - const themeAnalysis = analyzeThemeUsage(options.appearance); - isomorphicClerkRef.current.telemetry.record(eventThemeUsage(themeAnalysis)); + isomorphicClerkRef.current.telemetry.record(eventThemeUsage(options.appearance)); } }, [options.appearance]); diff --git a/packages/shared/src/telemetry.ts b/packages/shared/src/telemetry.ts index 922383e41c7..3f80deefed7 100644 --- a/packages/shared/src/telemetry.ts +++ b/packages/shared/src/telemetry.ts @@ -2,4 +2,3 @@ export { TelemetryCollector } from './telemetry/collector'; export type { TelemetryCollectorOptions } from './telemetry/types'; export * from './telemetry/events'; -export * from './telemetry/utils'; diff --git a/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts new file mode 100644 index 00000000000..4c7791c8acf --- /dev/null +++ b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts @@ -0,0 +1,127 @@ +import { eventThemeUsage } from '../theme-usage'; + +describe('eventThemeUsage', () => { + it('should create telemetry event with shadcn theme name', () => { + const appearance = { + theme: { + __type: 'prebuilt_appearance' as const, + __themeName: 'shadcn', + variables: { colorPrimary: 'var(--primary)' }, + }, + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: 'shadcn' }, + }); + }); + + it('should handle string themes', () => { + const appearance = { + theme: 'clerk' as any, // String themes are valid at runtime + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: 'clerk' }, + }); + }); + + it('should handle array of themes', () => { + const appearance = { + theme: [ + 'clerk' as any, // String themes are valid at runtime + { + __type: 'prebuilt_appearance' as const, + __themeName: 'shadcn', + }, + ] as any, + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: 'clerk' }, + }); + }); + + it('should handle themes without explicit names', () => { + const appearance = { + theme: { + __type: 'prebuilt_appearance' as const, + variables: { colorPrimary: 'blue' }, + }, + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: undefined }, + }); + }); + + it('should prioritize theme over deprecated baseTheme', () => { + const appearance = { + theme: 'clerk' as any, // String themes are valid at runtime + baseTheme: { + __type: 'prebuilt_appearance' as const, + __themeName: 'shadcn', + }, + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: 'clerk' }, + }); + }); + + it('should use baseTheme when theme is not provided', () => { + const appearance = { + baseTheme: { + __type: 'prebuilt_appearance' as const, + __themeName: 'shadcn', + }, + }; + + const result = eventThemeUsage(appearance); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: { themeName: 'shadcn' }, + }); + }); + + it('should handle undefined appearance', () => { + const result = eventThemeUsage(); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: {}, + }); + }); + + it('should handle null appearance', () => { + const result = eventThemeUsage(null as any); + + expect(result).toEqual({ + event: 'THEME_USAGE', + eventSamplingRate: 0.1, + payload: {}, + }); + }); +}); diff --git a/packages/shared/src/telemetry/events/theme-usage.ts b/packages/shared/src/telemetry/events/theme-usage.ts index 49cf98b4561..a3f97809fb0 100644 --- a/packages/shared/src/telemetry/events/theme-usage.ts +++ b/packages/shared/src/telemetry/events/theme-usage.ts @@ -1,4 +1,4 @@ -import type { TelemetryEventRaw } from '@clerk/types'; +import type { Appearance, BaseTheme, TelemetryEventRaw } from '@clerk/types'; const EVENT_THEME_USAGE = 'THEME_USAGE'; const EVENT_SAMPLING_RATE = 0.1; @@ -13,14 +13,71 @@ type EventThemeUsage = { /** * Helper function for `telemetry.record()`. Create a consistent event object for tracking theme usage in ClerkProvider. * - * @param payload - Theme usage data to track. + * @param appearance - The appearance prop from ClerkProvider. * @example - * telemetry.record(eventThemeUsage({ themeName: 'shadcn' })); + * telemetry.record(eventThemeUsage(appearance)); */ -export function eventThemeUsage(payload: EventThemeUsage): TelemetryEventRaw { +export function eventThemeUsage(appearance?: Appearance): TelemetryEventRaw { + const payload = analyzeThemeUsage(appearance); + return { event: EVENT_THEME_USAGE, eventSamplingRate: EVENT_SAMPLING_RATE, payload, }; } + +/** + * Analyzes the appearance prop to extract theme usage information for telemetry. + * + * @internal + */ +function analyzeThemeUsage(appearance?: Appearance): EventThemeUsage { + if (!appearance || typeof appearance !== 'object') { + return {}; + } + + // Prioritize the new theme property over deprecated baseTheme + const themeProperty = appearance.theme || appearance.baseTheme; + + if (!themeProperty) { + return {}; + } + + let themeName: string | undefined; + + if (Array.isArray(themeProperty)) { + // Look for the first identifiable theme name in the array + for (const theme of themeProperty) { + const name = extractThemeName(theme); + if (name) { + themeName = name; + break; + } + } + } else { + themeName = extractThemeName(themeProperty); + } + + return { themeName }; +} + +/** + * Extracts the theme name from a theme object. + * + * @internal + */ +function extractThemeName(theme: BaseTheme): string | undefined { + if (typeof theme === 'string') { + return theme; + } + + if (typeof theme === 'object' && theme !== null) { + // Check for explicit theme name + if ('__themeName' in theme && typeof theme.__themeName === 'string') { + return theme.__themeName; + } + } + + return undefined; +} diff --git a/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts b/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts deleted file mode 100644 index 7696dfac906..00000000000 --- a/packages/shared/src/telemetry/utils/__tests__/analyzeThemeUsage.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -import type { Appearance } from '@clerk/types'; - -import { analyzeThemeUsage } from '../analyzeThemeUsage'; - -describe('analyzeThemeUsage', () => { - it('returns empty object for undefined appearance', () => { - const result = analyzeThemeUsage(undefined); - expect(result).toEqual({}); - }); - - it('returns empty object for empty appearance object', () => { - const result = analyzeThemeUsage({}); - expect(result).toEqual({}); - }); - - it('returns empty object when no theme is provided', () => { - const appearance: Appearance = { - variables: { colorPrimary: '#ff0000' }, - elements: { button: 'custom-class' }, - }; - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({}); - }); - - it('identifies shadcn theme correctly from explicit theme name', () => { - const appearance: Appearance = { - theme: { - __type: 'prebuilt_appearance', - __themeName: 'shadcn', - variables: { - colorBackground: 'var(--card)', - colorPrimary: 'var(--primary)', - }, - elements: { - input: 'bg-transparent dark:bg-input/30', - }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'shadcn' }); - }); - - it('identifies shadcn theme correctly from baseTheme with explicit name', () => { - const appearance: Appearance = { - baseTheme: { - __type: 'prebuilt_appearance', - __themeName: 'shadcn', - variables: { - colorBackground: 'var(--card)', - colorPrimary: 'var(--primary)', - }, - elements: { - input: 'bg-transparent dark:bg-input/30', - }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'shadcn' }); - }); - - it('prioritizes theme over baseTheme when both are present', () => { - const appearance: Appearance = { - theme: 'simple' as any, - baseTheme: { - __type: 'prebuilt_appearance', - variables: { - colorBackground: 'var(--card)', - colorPrimary: 'var(--primary)', - }, - elements: { - input: 'bg-transparent dark:bg-input/30', - }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'simple' }); - }); - - it('handles string themes', () => { - const appearance: Appearance = { - theme: 'clerk' as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'clerk' }); - }); - - it('finds first identifiable theme in array', () => { - const appearance: Appearance = { - theme: [ - { customProp: 'value' }, // Custom theme, no identifiable name - { - __type: 'prebuilt_appearance', - __themeName: 'shadcn', - variables: { - colorBackground: 'var(--card)', - colorPrimary: 'var(--primary)', - }, - elements: { - input: 'bg-transparent dark:bg-input/30', - }, - }, - ] as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'shadcn' }); - }); - - it('returns undefined theme name for unidentifiable themes', () => { - const appearance: Appearance = { - theme: { - __type: 'prebuilt_appearance', - variables: { colorPrimary: '#custom' }, - elements: { button: 'custom-style' }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: undefined }); - }); - - it('returns undefined for themes without explicit names', () => { - const appearance: Appearance = { - theme: { - __type: 'prebuilt_appearance', - // No __themeName property - should return undefined - variables: { - colorBackground: 'var(--card)', - colorPrimary: 'var(--primary)', - }, - elements: { - input: 'bg-transparent dark:bg-input/30', - }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: undefined }); - }); - - it('handles custom theme names', () => { - const appearance: Appearance = { - theme: { - __type: 'prebuilt_appearance', - __themeName: 'my-custom-theme', - variables: { colorPrimary: '#purple' }, - } as any, - }; - - const result = analyzeThemeUsage(appearance); - expect(result).toEqual({ themeName: 'my-custom-theme' }); - }); -}); diff --git a/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts b/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts deleted file mode 100644 index ea6671c0073..00000000000 --- a/packages/shared/src/telemetry/utils/analyzeThemeUsage.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { Appearance, BaseTheme } from '@clerk/types'; - -type ThemeUsageAnalysis = { - themeName?: string; -}; - -/** - * Analyzes the appearance prop to extract theme usage information for telemetry. - */ -export function analyzeThemeUsage(appearance?: Appearance): ThemeUsageAnalysis { - if (!appearance || typeof appearance !== 'object') { - return {}; - } - - // Prioritize the new theme property over deprecated baseTheme - const themeProperty = appearance.theme || appearance.baseTheme; - - if (!themeProperty) { - return {}; - } - - let themeName: string | undefined; - - if (Array.isArray(themeProperty)) { - // Look for the first identifiable theme name in the array - for (const theme of themeProperty) { - const name = extractThemeName(theme); - if (name) { - themeName = name; - break; - } - } - } else { - themeName = extractThemeName(themeProperty); - } - - return { themeName }; -} - -/** - * Extracts the theme name from a theme object. - */ -function extractThemeName(theme: BaseTheme): string | undefined { - if (typeof theme === 'string') { - return theme; - } - - if (typeof theme === 'object' && theme !== null) { - // Check for explicit theme name - if ('__themeName' in theme && typeof theme.__themeName === 'string') { - return theme.__themeName; - } - } - - return undefined; -} diff --git a/packages/shared/src/telemetry/utils/index.ts b/packages/shared/src/telemetry/utils/index.ts deleted file mode 100644 index 5d7a20c4f81..00000000000 --- a/packages/shared/src/telemetry/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './analyzeThemeUsage'; diff --git a/packages/themes/src/themes/dark.ts b/packages/themes/src/themes/dark.ts index 3e560d7f0dc..3a9e4530695 100644 --- a/packages/themes/src/themes/dark.ts +++ b/packages/themes/src/themes/dark.ts @@ -1,6 +1,7 @@ import { experimental_createTheme } from '../createTheme'; export const dark = experimental_createTheme({ + name: 'dark', variables: { colorBackground: '#212126', colorNeutral: 'white', diff --git a/packages/themes/src/themes/neobrutalism.ts b/packages/themes/src/themes/neobrutalism.ts index d992eeb68d7..3d49f81aa5b 100644 --- a/packages/themes/src/themes/neobrutalism.ts +++ b/packages/themes/src/themes/neobrutalism.ts @@ -20,6 +20,7 @@ const shadowStyle = { }; export const neobrutalism = experimental_createTheme({ + name: 'neobrutalism', //@ts-expect-error not public api simpleStyles: true, variables: { diff --git a/packages/themes/src/themes/shadesOfPurple.ts b/packages/themes/src/themes/shadesOfPurple.ts index f99f111d306..a80392ed149 100644 --- a/packages/themes/src/themes/shadesOfPurple.ts +++ b/packages/themes/src/themes/shadesOfPurple.ts @@ -2,6 +2,7 @@ import { experimental_createTheme } from '../createTheme'; import { dark } from './dark'; export const shadesOfPurple = experimental_createTheme({ + name: 'shadesOfPurple', baseTheme: dark, variables: { colorBackground: '#3f3c77', diff --git a/packages/themes/src/themes/simple.ts b/packages/themes/src/themes/simple.ts index a985a3ae484..228dfb752e3 100644 --- a/packages/themes/src/themes/simple.ts +++ b/packages/themes/src/themes/simple.ts @@ -1,6 +1,7 @@ import { experimental_createTheme } from '../createTheme'; export const experimental__simple = experimental_createTheme({ + name: 'simple', //@ts-expect-error not public api simpleStyles: true, }); From 6733b47e2ce77202976beb74d2683c657f730d39 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Wed, 13 Aug 2025 15:16:48 -0400 Subject: [PATCH 04/13] just use name --- .../src/telemetry/events/__tests__/theme-usage.test.ts | 8 ++++---- packages/shared/src/telemetry/events/theme-usage.ts | 4 ++-- packages/themes/src/createTheme.ts | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts index 4c7791c8acf..d5557a89ce6 100644 --- a/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts +++ b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts @@ -5,7 +5,7 @@ describe('eventThemeUsage', () => { const appearance = { theme: { __type: 'prebuilt_appearance' as const, - __themeName: 'shadcn', + name: 'shadcn', variables: { colorPrimary: 'var(--primary)' }, }, }; @@ -39,7 +39,7 @@ describe('eventThemeUsage', () => { 'clerk' as any, // String themes are valid at runtime { __type: 'prebuilt_appearance' as const, - __themeName: 'shadcn', + name: 'shadcn', }, ] as any, }; @@ -75,7 +75,7 @@ describe('eventThemeUsage', () => { theme: 'clerk' as any, // String themes are valid at runtime baseTheme: { __type: 'prebuilt_appearance' as const, - __themeName: 'shadcn', + name: 'shadcn', }, }; @@ -92,7 +92,7 @@ describe('eventThemeUsage', () => { const appearance = { baseTheme: { __type: 'prebuilt_appearance' as const, - __themeName: 'shadcn', + name: 'shadcn', }, }; diff --git a/packages/shared/src/telemetry/events/theme-usage.ts b/packages/shared/src/telemetry/events/theme-usage.ts index a3f97809fb0..5ee5e0e56f5 100644 --- a/packages/shared/src/telemetry/events/theme-usage.ts +++ b/packages/shared/src/telemetry/events/theme-usage.ts @@ -74,8 +74,8 @@ function extractThemeName(theme: BaseTheme): string | undefined { if (typeof theme === 'object' && theme !== null) { // Check for explicit theme name - if ('__themeName' in theme && typeof theme.__themeName === 'string') { - return theme.__themeName; + if ('name' in theme && typeof theme.name === 'string') { + return theme.name; } } diff --git a/packages/themes/src/createTheme.ts b/packages/themes/src/createTheme.ts index 02f060841e1..ea43ce03a89 100644 --- a/packages/themes/src/createTheme.ts +++ b/packages/themes/src/createTheme.ts @@ -22,7 +22,5 @@ export const experimental_createTheme = (appearance: Appearance Date: Wed, 13 Aug 2025 16:20:47 -0400 Subject: [PATCH 05/13] Update bundlewatch.config.json --- packages/clerk-js/bundlewatch.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index 00856735535..160a1e44387 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -1,6 +1,6 @@ { "files": [ - { "path": "./dist/clerk.js", "maxSize": "622.25KB" }, + { "path": "./dist/clerk.js", "maxSize": "622.37KB" }, { "path": "./dist/clerk.browser.js", "maxSize": "76KB" }, { "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" }, { "path": "./dist/clerk.headless*.js", "maxSize": "58KB" }, From 1655a7663aa46a8dda957493f00bdd0f259ce244 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Wed, 27 Aug 2025 09:54:35 -0400 Subject: [PATCH 06/13] Update packages/shared/src/telemetry/events/theme-usage.ts Co-authored-by: Mike Wickett --- packages/shared/src/telemetry/events/theme-usage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/telemetry/events/theme-usage.ts b/packages/shared/src/telemetry/events/theme-usage.ts index 5ee5e0e56f5..c2d7acbf767 100644 --- a/packages/shared/src/telemetry/events/theme-usage.ts +++ b/packages/shared/src/telemetry/events/theme-usage.ts @@ -1,7 +1,7 @@ import type { Appearance, BaseTheme, TelemetryEventRaw } from '@clerk/types'; const EVENT_THEME_USAGE = 'THEME_USAGE'; -const EVENT_SAMPLING_RATE = 0.1; +const EVENT_SAMPLING_RATE = 1; type EventThemeUsage = { /** From 6adad532e64695769bfec56cb57cf6ce3c5ab756 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Wed, 27 Aug 2025 10:28:19 -0400 Subject: [PATCH 07/13] use consts --- .../events/__tests__/theme-usage.test.ts | 34 +++++++++---------- .../src/telemetry/events/theme-usage.ts | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts index d5557a89ce6..a5165b29298 100644 --- a/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts +++ b/packages/shared/src/telemetry/events/__tests__/theme-usage.test.ts @@ -1,4 +1,4 @@ -import { eventThemeUsage } from '../theme-usage'; +import { EVENT_SAMPLING_RATE, EVENT_THEME_USAGE, eventThemeUsage } from '../theme-usage'; describe('eventThemeUsage', () => { it('should create telemetry event with shadcn theme name', () => { @@ -13,8 +13,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: 'shadcn' }, }); }); @@ -27,8 +27,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: 'clerk' }, }); }); @@ -47,8 +47,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: 'clerk' }, }); }); @@ -64,8 +64,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: undefined }, }); }); @@ -82,8 +82,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: 'clerk' }, }); }); @@ -99,8 +99,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(appearance); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: { themeName: 'shadcn' }, }); }); @@ -109,8 +109,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: {}, }); }); @@ -119,8 +119,8 @@ describe('eventThemeUsage', () => { const result = eventThemeUsage(null as any); expect(result).toEqual({ - event: 'THEME_USAGE', - eventSamplingRate: 0.1, + event: EVENT_THEME_USAGE, + eventSamplingRate: EVENT_SAMPLING_RATE, payload: {}, }); }); diff --git a/packages/shared/src/telemetry/events/theme-usage.ts b/packages/shared/src/telemetry/events/theme-usage.ts index c2d7acbf767..0848bb81ced 100644 --- a/packages/shared/src/telemetry/events/theme-usage.ts +++ b/packages/shared/src/telemetry/events/theme-usage.ts @@ -1,7 +1,7 @@ import type { Appearance, BaseTheme, TelemetryEventRaw } from '@clerk/types'; -const EVENT_THEME_USAGE = 'THEME_USAGE'; -const EVENT_SAMPLING_RATE = 1; +export const EVENT_THEME_USAGE = 'THEME_USAGE'; +export const EVENT_SAMPLING_RATE = 1; type EventThemeUsage = { /** From 5478a6692d4f0c9c475246f02eacaebe725d587f Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Wed, 27 Aug 2025 11:20:06 -0400 Subject: [PATCH 08/13] add changeset --- .changeset/orange-tips-turn.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/orange-tips-turn.md diff --git a/.changeset/orange-tips-turn.md b/.changeset/orange-tips-turn.md new file mode 100644 index 00000000000..0b92910a53a --- /dev/null +++ b/.changeset/orange-tips-turn.md @@ -0,0 +1,8 @@ +--- +'@clerk/clerk-js': patch +'@clerk/shared': patch +'@clerk/themes': patch +'@clerk/clerk-react': patch +--- + +Add theme-usage telemetry From 6eac2d6f58c155233872b6bc867de07c003ce0ec Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Wed, 27 Aug 2025 11:28:41 -0400 Subject: [PATCH 09/13] dedupe --- pnpm-lock.yaml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 637e158a697..dec30dbb0fd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3414,82 +3414,66 @@ packages: '@miniflare/cache@2.14.4': resolution: {integrity: sha512-ayzdjhcj+4mjydbNK7ZGDpIXNliDbQY4GPcY2KrYw0v1OSUdj5kZUkygD09fqoGRfAks0d91VelkyRsAXX8FQA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/core@2.14.4': resolution: {integrity: sha512-FMmZcC1f54YpF4pDWPtdQPIO8NXfgUxCoR9uyrhxKJdZu7M6n8QKopPVNuaxR40jcsdxb7yKoQoFWnHfzJD9GQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/d1@2.14.4': resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/durable-objects@2.14.4': resolution: {integrity: sha512-+JrmHP6gHHrjxV8S3axVw5lGHLgqmAGdcO/1HJUPswAyJEd3Ah2YnKhpo+bNmV4RKJCtEq9A2hbtVjBTD2YzwA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/html-rewriter@2.14.4': resolution: {integrity: sha512-GB/vZn7oLbnhw+815SGF+HU5EZqSxbhIa3mu2L5MzZ2q5VOD5NHC833qG8c2GzDPhIaZ99ITY+ZJmbR4d+4aNQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/kv@2.14.4': resolution: {integrity: sha512-QlERH0Z+klwLg0xw+/gm2yC34Nnr/I0GcQ+ASYqXeIXBwjqOtMBa3YVQnocaD+BPy/6TUtSpOAShHsEj76R2uw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/queues@2.14.4': resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/r2@2.14.4': resolution: {integrity: sha512-4ctiZWh7Ty7LB3brUjmbRiGMqwyDZgABYaczDtUidblo2DxX4JZPnJ/ZAyxMPNJif32kOJhcg6arC2hEthR9Sw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/runner-vm@2.14.4': resolution: {integrity: sha512-Nog0bB9SVhPbZAkTWfO4lpLAUsBXKEjlb4y+y66FJw77mPlmPlVdpjElCvmf8T3VN/pqh83kvELGM+/fucMf4g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared-test-environment@2.14.4': resolution: {integrity: sha512-FdU2/8wEd00vIu+MfofLiHcfZWz+uCbE2VTL85KpyYfBsNGAbgRtzFMpOXdoXLqQfRu6MBiRwWpb2FbMrBzi7g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared@2.14.4': resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/sites@2.14.4': resolution: {integrity: sha512-O5npWopi+fw9W9Ki0gy99nuBbgDva/iXy8PDC4dAXDB/pz45nISDqldabk0rL2t4W2+lY6LXKzdOw+qJO1GQTA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-file@2.14.4': resolution: {integrity: sha512-JxcmX0hXf4cB0cC9+s6ZsgYCq+rpyUKRPCGzaFwymWWplrO3EjPVxKCcMxG44jsdgsII6EZihYUN2J14wwCT7A==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-memory@2.14.4': resolution: {integrity: sha512-9jB5BqNkMZ3SFjbPFeiVkLi1BuSahMhc/W1Y9H0W89qFDrrD+z7EgRgDtHTG1ZRyi9gIlNtt9qhkO1B6W2qb2A==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/watcher@2.14.4': resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/web-sockets@2.14.4': resolution: {integrity: sha512-stTxvLdJ2IcGOs76AnvGYAzGvx8JvQPRxC5DW0P5zdAAnhL33noqb5LKdPt3P37BKp9FzBKZHuihQI9oVqwm0g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@modelcontextprotocol/sdk@1.7.0': resolution: {integrity: sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==} @@ -14437,7 +14421,6 @@ packages: vitest-environment-miniflare@2.14.4: resolution: {integrity: sha512-DzwQWdY42sVYR6aUndw9FdCtl/i0oh3NkbkQpw+xq5aYQw5eiJn5kwnKaKQEWaoBe8Cso71X2i1EJGvi1jZ2xw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 peerDependencies: vitest: '>=0.23.0' From 2a5782a26a72c067a5cf532e74d46272fd010d1b Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 5 Sep 2025 09:53:22 -0400 Subject: [PATCH 10/13] remove useEffect usage --- packages/react/src/contexts/ClerkContextProvider.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/react/src/contexts/ClerkContextProvider.tsx b/packages/react/src/contexts/ClerkContextProvider.tsx index 87540bebfab..f38f9f785f5 100644 --- a/packages/react/src/contexts/ClerkContextProvider.tsx +++ b/packages/react/src/contexts/ClerkContextProvider.tsx @@ -6,7 +6,6 @@ import { SessionContext, UserContext, } from '@clerk/shared/react'; -import { eventThemeUsage } from '@clerk/shared/telemetry'; import type { ClientResource, InitialState, Resources } from '@clerk/types'; import React from 'react'; @@ -120,13 +119,6 @@ const useLoadedIsomorphicClerk = (options: IsomorphicClerkOptions) => { void isomorphicClerkRef.current.__unstable__updateProps({ appearance: options.appearance }); }, [options.appearance]); - // Record theme usage telemetry when appearance changes - React.useEffect(() => { - if (options.appearance && isomorphicClerkRef.current.telemetry) { - isomorphicClerkRef.current.telemetry.record(eventThemeUsage(options.appearance)); - } - }, [options.appearance]); - React.useEffect(() => { void isomorphicClerkRef.current.__unstable__updateProps({ options }); }, [options.localization]); From df24963576df486a55bf10d8a07299bc7c576323 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 5 Sep 2025 10:03:52 -0400 Subject: [PATCH 11/13] Update .changeset/orange-tips-turn.md --- .changeset/orange-tips-turn.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/orange-tips-turn.md b/.changeset/orange-tips-turn.md index 0b92910a53a..eb2aaacce73 100644 --- a/.changeset/orange-tips-turn.md +++ b/.changeset/orange-tips-turn.md @@ -2,7 +2,6 @@ '@clerk/clerk-js': patch '@clerk/shared': patch '@clerk/themes': patch -'@clerk/clerk-react': patch --- Add theme-usage telemetry From 2b11e9eb965effde7a088ebd1a32c416fb980bc5 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 5 Sep 2025 10:09:40 -0400 Subject: [PATCH 12/13] Update bundlewatch.config.json --- packages/clerk-js/bundlewatch.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index 6406f0f9367..825838ea31e 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -1,7 +1,7 @@ { "files": [ { "path": "./dist/clerk.js", "maxSize": "818KB" }, - { "path": "./dist/clerk.browser.js", "maxSize": "78KB" }, + { "path": "./dist/clerk.browser.js", "maxSize": "78.2KB" }, { "path": "./dist/clerk.legacy.browser.js", "maxSize": "120KB" }, { "path": "./dist/clerk.headless*.js", "maxSize": "61KB" }, { "path": "./dist/ui-common*.js", "maxSize": "117.1KB" }, From 8c6cfc2cf7307b6f0b243c413b30c169e7039a11 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Tue, 9 Sep 2025 16:36:08 -0400 Subject: [PATCH 13/13] Update bundlewatch.config.json --- packages/clerk-js/bundlewatch.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index d03cb80801d..8a263109115 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -2,7 +2,7 @@ "files": [ { "path": "./dist/clerk.js", "maxSize": "819KB" }, { "path": "./dist/clerk.browser.js", "maxSize": "78.2KB" }, - { "path": "./dist/clerk.legacy.browser.js", "maxSize": "120KB" }, + { "path": "./dist/clerk.legacy.browser.js", "maxSize": "120.2KB" }, { "path": "./dist/clerk.headless*.js", "maxSize": "61KB" }, { "path": "./dist/ui-common*.js", "maxSize": "117.1KB" }, { "path": "./dist/ui-common*.legacy.*.js", "maxSize": "120KB" },