diff --git a/.changeset/internal-clerk-js-ui-props.md b/.changeset/internal-clerk-js-ui-props.md
new file mode 100644
index 00000000000..9bbc67a3dcc
--- /dev/null
+++ b/.changeset/internal-clerk-js-ui-props.md
@@ -0,0 +1,11 @@
+---
+'@clerk/shared': minor
+'@clerk/nextjs': minor
+'@clerk/astro': minor
+'@clerk/react-router': minor
+'@clerk/tanstack-react-start': minor
+'@clerk/express': minor
+'@clerk/nuxt': minor
+---
+
+Remove `clerkJSUrl`, `clerkJSVersion`, `clerkUIUrl`, and `clerkUIVersion` props and replace with `__internal_clerkJSUrl`, `__internal_clerkJSVersion`, `__internal_clerkUIUrl`, and `__internal_clerkUIVersion` internal-only options. Use `@clerk/upgrade` to migrate.
diff --git a/.changeset/remove-clerk-ui-version.md b/.changeset/remove-clerk-ui-version.md
new file mode 100644
index 00000000000..3404d56cb95
--- /dev/null
+++ b/.changeset/remove-clerk-ui-version.md
@@ -0,0 +1,11 @@
+---
+'@clerk/shared': minor
+'@clerk/nextjs': minor
+'@clerk/astro': minor
+'@clerk/react-router': minor
+'@clerk/tanstack-react-start': minor
+'@clerk/express': minor
+'@clerk/nuxt': minor
+---
+
+Remove `clerkUIVersion` and `clerkJSVersion` props across all SDKs. Use `@clerk/upgrade` to migrate to the new `__internal_` prefixed props if needed.
diff --git a/integration/templates/custom-flows-react-vite/src/main.tsx b/integration/templates/custom-flows-react-vite/src/main.tsx
index 225a3ddd20f..33b3d38e758 100644
--- a/integration/templates/custom-flows-react-vite/src/main.tsx
+++ b/integration/templates/custom-flows-react-vite/src/main.tsx
@@ -14,8 +14,8 @@ createRoot(document.getElementById('root')!).render(
router.push(to)}
routerReplace={to => router.replace(to)}
- clerkJSUrl={process.env.EXPO_PUBLIC_CLERK_JS_URL}
- clerkUIUrl={process.env.EXPO_PUBLIC_CLERK_UI_URL}
+ __internal_clerkJSUrl={process.env.EXPO_PUBLIC_CLERK_JS_URL}
+ __internal_clerkUIUrl={process.env.EXPO_PUBLIC_CLERK_UI_URL}
appearance={{
options: {
showOptionalFields: true,
diff --git a/integration/templates/react-cra/src/index.tsx b/integration/templates/react-cra/src/index.tsx
index 81039d51a20..a9d172c24f1 100644
--- a/integration/templates/react-cra/src/index.tsx
+++ b/integration/templates/react-cra/src/index.tsx
@@ -9,8 +9,8 @@ root.render(
{
const navigate = useNavigate();
return (
navigate(to)}
routerReplace={(to: string) => navigate(to, { replace: true })}
appearance={{
diff --git a/integration/templates/tanstack-react-start/src/routes/__root.tsx b/integration/templates/tanstack-react-start/src/routes/__root.tsx
index b9adc012c75..cdd38e131cd 100644
--- a/integration/templates/tanstack-react-start/src/routes/__root.tsx
+++ b/integration/templates/tanstack-react-start/src/routes/__root.tsx
@@ -28,8 +28,8 @@ function RootDocument({ children }: { children: React.ReactNode }) {
()
const { proxyUrl, isSatellite, domain, signInUrl, signUpUrl, enableEnvSchema = true } = params || {};
// These are not provided when the "bundled" integration is used
- const clerkJSUrl = (params as any)?.clerkJSUrl as string | undefined;
- const clerkJSVersion = (params as any)?.clerkJSVersion as string | undefined;
- const clerkUIVersion = (params as any)?.clerkUIVersion as string | undefined;
+ const clerkJSUrl = (params as any)?.__internal_clerkJSUrl as string | undefined;
+ const clerkJSVersion = (params as any)?.__internal_clerkJSVersion as string | undefined;
+ const clerkUIUrl = (params as any)?.__internal_clerkUIUrl as string | undefined;
+ const clerkUIVersion = (params as any)?.__internal_clerkUIVersion as string | undefined;
const prefetchUI = (params as any)?.prefetchUI as boolean | undefined;
const hasUI = !!(params as any)?.ui;
@@ -60,6 +61,7 @@ function createIntegration()
...buildEnvVarFromOption(domain, 'PUBLIC_CLERK_DOMAIN'),
...buildEnvVarFromOption(clerkJSUrl, 'PUBLIC_CLERK_JS_URL'),
...buildEnvVarFromOption(clerkJSVersion, 'PUBLIC_CLERK_JS_VERSION'),
+ ...buildEnvVarFromOption(clerkUIUrl, 'PUBLIC_CLERK_UI_URL'),
...buildEnvVarFromOption(clerkUIVersion, 'PUBLIC_CLERK_UI_VERSION'),
...buildEnvVarFromOption(
prefetchUI === false || hasUI ? 'false' : undefined,
diff --git a/packages/astro/src/internal/__tests__/create-clerk-instance.test.ts b/packages/astro/src/internal/__tests__/create-clerk-instance.test.ts
index e9f62f67a99..8811a9427d0 100644
--- a/packages/astro/src/internal/__tests__/create-clerk-instance.test.ts
+++ b/packages/astro/src/internal/__tests__/create-clerk-instance.test.ts
@@ -42,7 +42,7 @@ describe('getClerkUIEntryChunk', () => {
(window as any).Clerk = undefined;
});
- it('preserves clerkUIUrl from options', async () => {
+ it('preserves __internal_clerkUIUrl from options', async () => {
mockLoadClerkUIScript.mockImplementation(async () => {
(window as any).__internal_ClerkUICtor = mockClerkUICtor;
return null;
@@ -59,18 +59,18 @@ describe('getClerkUIEntryChunk', () => {
// Dynamically import to get fresh module with mocks
const { createClerkInstance } = await import('../create-clerk-instance');
- // Call createClerkInstance with clerkUIUrl
+ // Call createClerkInstance with __internal_clerkUIUrl
await createClerkInstance({
publishableKey: 'pk_test_xxx',
- clerkUIUrl: 'https://custom.selfhosted.example.com/ui.js',
+ __internal_clerkUIUrl: 'https://custom.selfhosted.example.com/ui.js',
});
expect(mockLoadClerkUIScript).toHaveBeenCalled();
const loadClerkUIScriptCall = mockLoadClerkUIScript.mock.calls[0]?.[0] as Record;
- expect(loadClerkUIScriptCall?.clerkUIUrl).toBe('https://custom.selfhosted.example.com/ui.js');
+ expect(loadClerkUIScriptCall?.__internal_clerkUIUrl).toBe('https://custom.selfhosted.example.com/ui.js');
});
- it('does not set clerkUIUrl when not provided', async () => {
+ it('does not set __internal_clerkUIUrl when not provided', async () => {
mockLoadClerkUIScript.mockImplementation(async () => {
(window as any).__internal_ClerkUICtor = mockClerkUICtor;
return null;
@@ -92,6 +92,6 @@ describe('getClerkUIEntryChunk', () => {
expect(mockLoadClerkUIScript).toHaveBeenCalled();
const loadClerkUIScriptCall = mockLoadClerkUIScript.mock.calls[0]?.[0] as Record;
- expect(loadClerkUIScriptCall?.clerkUIUrl).toBeUndefined();
+ expect(loadClerkUIScriptCall?.__internal_clerkUIUrl).toBeUndefined();
});
});
diff --git a/packages/astro/src/internal/merge-env-vars-with-params.ts b/packages/astro/src/internal/merge-env-vars-with-params.ts
index 39dbfd9820b..65128c255bd 100644
--- a/packages/astro/src/internal/merge-env-vars-with-params.ts
+++ b/packages/astro/src/internal/merge-env-vars-with-params.ts
@@ -1,3 +1,4 @@
+import type { InternalClerkScriptProps } from '@clerk/shared/types';
import { isTruthy } from '@clerk/shared/underscore';
import type { AstroClerkIntegrationParams, InternalRuntimeOptions } from '../types';
@@ -25,7 +26,9 @@ function mergePrefetchUIConfig(paramPrefetchUI: AstroClerkIntegrationParams['pre
/**
* @internal
*/
-const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & InternalRuntimeOptions) => {
+const mergeEnvVarsWithParams = (
+ params?: AstroClerkIntegrationParams & InternalRuntimeOptions & InternalClerkScriptProps,
+) => {
const {
signInUrl: paramSignIn,
signUpUrl: paramSignUp,
@@ -34,10 +37,10 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & InternalR
domain: paramDomain,
publishableKey: paramPublishableKey,
telemetry: paramTelemetry,
- clerkJSUrl: paramClerkJSUrl,
- clerkJSVersion: paramClerkJSVersion,
- clerkUIUrl: paramClerkUIUrl,
- clerkUIVersion: paramClerkUIVersion,
+ __internal_clerkJSUrl: paramClerkJSUrl,
+ __internal_clerkJSVersion: paramClerkJSVersion,
+ __internal_clerkUIUrl: paramClerkUIUrl,
+ __internal_clerkUIVersion: paramClerkUIVersion,
prefetchUI: paramPrefetchUI,
...rest
} = params || {};
@@ -53,10 +56,10 @@ const mergeEnvVarsWithParams = (params?: AstroClerkIntegrationParams & InternalR
// In keyless mode, use server-injected publishableKey from params
publishableKey:
paramPublishableKey || internalOptions?.publishableKey || import.meta.env.PUBLIC_CLERK_PUBLISHABLE_KEY || '',
- clerkJSUrl: paramClerkJSUrl || import.meta.env.PUBLIC_CLERK_JS_URL,
- clerkJSVersion: paramClerkJSVersion || import.meta.env.PUBLIC_CLERK_JS_VERSION,
- clerkUIUrl: paramClerkUIUrl || import.meta.env.PUBLIC_CLERK_UI_URL,
- clerkUIVersion: paramClerkUIVersion || import.meta.env.PUBLIC_CLERK_UI_VERSION,
+ __internal_clerkJSUrl: paramClerkJSUrl || import.meta.env.PUBLIC_CLERK_JS_URL,
+ __internal_clerkJSVersion: paramClerkJSVersion || import.meta.env.PUBLIC_CLERK_JS_VERSION,
+ __internal_clerkUIUrl: paramClerkUIUrl || import.meta.env.PUBLIC_CLERK_UI_URL,
+ __internal_clerkUIVersion: paramClerkUIVersion || import.meta.env.PUBLIC_CLERK_UI_VERSION,
prefetchUI: mergePrefetchUIConfig(paramPrefetchUI),
telemetry: paramTelemetry || {
disabled: isTruthy(import.meta.env.PUBLIC_CLERK_TELEMETRY_DISABLED),
diff --git a/packages/astro/src/server/build-clerk-hotload-script.ts b/packages/astro/src/server/build-clerk-hotload-script.ts
index 5510759b387..c97be95cd4e 100644
--- a/packages/astro/src/server/build-clerk-hotload-script.ts
+++ b/packages/astro/src/server/build-clerk-hotload-script.ts
@@ -13,8 +13,8 @@ function buildClerkHotloadScript(locals: APIContext['locals']) {
const domain = env.domain!;
const clerkJsScriptSrc = clerkJSScriptUrl({
- clerkJSUrl: env.clerkJsUrl,
- clerkJSVersion: env.clerkJsVersion,
+ __internal_clerkJSUrl: env.clerkJsUrl,
+ __internal_clerkJSVersion: env.clerkJsVersion,
domain,
proxyUrl,
publishableKey,
@@ -35,8 +35,8 @@ function buildClerkHotloadScript(locals: APIContext['locals']) {
}
const clerkUIScriptSrc = clerkUIScriptUrl({
- clerkUIUrl: env.clerkUIUrl,
- clerkUIVersion: env.clerkUIVersion,
+ __internal_clerkUIUrl: env.clerkUIUrl,
+ __internal_clerkUIVersion: env.clerkUIVersion,
domain,
proxyUrl,
publishableKey,
diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts
index 8e65d322c27..2248d5ce1f3 100644
--- a/packages/astro/src/types.ts
+++ b/packages/astro/src/types.ts
@@ -2,6 +2,7 @@ import type {
Clerk,
ClerkOptions,
ClientResource,
+ InternalClerkScriptProps,
MultiDomainAndOrProxyPrimitives,
ProtectParams,
ShowProps,
@@ -29,16 +30,6 @@ type AstroClerkIntegrationParams = Without<
> &
MultiDomainAndOrProxyPrimitives & {
appearance?: Appearance;
- clerkJSUrl?: string;
- clerkJSVersion?: string;
- /**
- * The URL that `@clerk/ui` should be hot-loaded from.
- */
- clerkUIUrl?: string;
- /**
- * The npm version for `@clerk/ui`.
- */
- clerkUIVersion?: string;
/**
* Controls prefetching of the `@clerk/ui` script.
* - `false` - Skip prefetching the UI (for custom UIs using Control Components)
@@ -47,9 +38,10 @@ type AstroClerkIntegrationParams = Without<
prefetchUI?: boolean;
};
-type AstroClerkCreateInstanceParams = AstroClerkIntegrationParams & {
- publishableKey: string;
-};
+type AstroClerkCreateInstanceParams = AstroClerkIntegrationParams &
+ InternalClerkScriptProps & {
+ publishableKey: string;
+ };
/**
* @internal
diff --git a/packages/chrome-extension/src/react/ClerkProvider.tsx b/packages/chrome-extension/src/react/ClerkProvider.tsx
index db601b22452..15ec1895cfa 100644
--- a/packages/chrome-extension/src/react/ClerkProvider.tsx
+++ b/packages/chrome-extension/src/react/ClerkProvider.tsx
@@ -1,6 +1,6 @@
import type { Clerk } from '@clerk/clerk-js/no-rhc';
import type { ClerkProviderProps as ClerkReactProviderProps } from '@clerk/react';
-import { ClerkProvider as ClerkReactProvider } from '@clerk/react';
+import { InternalClerkProvider as ClerkReactProvider } from '@clerk/react/internal';
import { ui } from '@clerk/ui';
import React from 'react';
diff --git a/packages/expo/src/provider/ClerkProvider.tsx b/packages/expo/src/provider/ClerkProvider.tsx
index 6c81616a1fc..d76e3fa541c 100644
--- a/packages/expo/src/provider/ClerkProvider.tsx
+++ b/packages/expo/src/provider/ClerkProvider.tsx
@@ -1,7 +1,7 @@
import '../polyfills';
-import { ClerkProvider as ClerkReactProvider } from '@clerk/react';
-import type { Ui } from '@clerk/react/internal';
+import type { ClerkProviderProps as ReactClerkProviderProps } from '@clerk/react';
+import { InternalClerkProvider as ClerkReactProvider, type Ui } from '@clerk/react/internal';
import * as WebBrowser from 'expo-web-browser';
import type { TokenCache } from '../cache/types';
@@ -9,10 +9,7 @@ import { isNative, isWeb } from '../utils/runtime';
import { getClerkInstance } from './singleton';
import type { BuildClerkOptions } from './singleton/types';
-export type ClerkProviderProps = Omit<
- React.ComponentProps>,
- 'publishableKey'
-> & {
+export type ClerkProviderProps = Omit, 'publishableKey'> & {
/**
* Your Clerk publishable key, available in the Clerk Dashboard.
* This is required for React Native / Expo apps. Environment variables inside node_modules
diff --git a/packages/express/src/utils.ts b/packages/express/src/utils.ts
index 73a343842df..bd138ed3dbe 100644
--- a/packages/express/src/utils.ts
+++ b/packages/express/src/utils.ts
@@ -11,10 +11,10 @@ export const requestHasAuthObject = (req: ExpressRequest): req is ExpressRequest
export const loadClientEnv = () => {
return {
publishableKey: process.env.CLERK_PUBLISHABLE_KEY || '',
- clerkJSUrl: process.env.CLERK_JS || process.env.CLERK_JS_URL || '',
- clerkJSVersion: process.env.CLERK_JS_VERSION || '',
- clerkUIUrl: process.env.CLERK_UI_URL || '',
- clerkUIVersion: process.env.CLERK_UI_VERSION || '',
+ __internal_clerkJSUrl: process.env.CLERK_JS || process.env.CLERK_JS_URL || '',
+ __internal_clerkJSVersion: process.env.CLERK_JS_VERSION || '',
+ __internal_clerkUIUrl: process.env.CLERK_UI_URL || '',
+ __internal_clerkUIVersion: process.env.CLERK_UI_VERSION || '',
prefetchUI: process.env.CLERK_PREFETCH_UI === 'false' ? false : undefined,
};
};
diff --git a/packages/nextjs/src/app-router/client/ClerkProvider.tsx b/packages/nextjs/src/app-router/client/ClerkProvider.tsx
index 77dc12d7cac..109e1a38c87 100644
--- a/packages/nextjs/src/app-router/client/ClerkProvider.tsx
+++ b/packages/nextjs/src/app-router/client/ClerkProvider.tsx
@@ -1,6 +1,5 @@
'use client';
-import { ClerkProvider as ReactClerkProvider } from '@clerk/react';
-import type { Ui } from '@clerk/react/internal';
+import { InternalClerkProvider as ReactClerkProvider, type Ui } from '@clerk/react/internal';
import { InitialStateProvider } from '@clerk/shared/react';
import dynamic from 'next/dynamic';
import { useRouter } from 'next/navigation';
diff --git a/packages/nextjs/src/app-router/client/ClerkScripts.tsx b/packages/nextjs/src/app-router/client/ClerkScripts.tsx
index bed102c7c08..66017626683 100644
--- a/packages/nextjs/src/app-router/client/ClerkScripts.tsx
+++ b/packages/nextjs/src/app-router/client/ClerkScripts.tsx
@@ -5,7 +5,15 @@ import { useClerkNextOptions } from '../../client-boundary/NextOptionsContext';
import { ClerkScriptTags } from '../../utils/clerk-script-tags';
export function ClerkScripts() {
- const { publishableKey, clerkJSUrl, clerkJSVersion, clerkUIUrl, nonce, prefetchUI } = useClerkNextOptions();
+ const {
+ publishableKey,
+ __internal_clerkJSUrl,
+ __internal_clerkJSVersion,
+ __internal_clerkUIUrl,
+ __internal_clerkUIVersion,
+ nonce,
+ prefetchUI,
+ } = useClerkNextOptions();
const { domain, proxyUrl } = useClerk();
if (!publishableKey) {
@@ -15,9 +23,10 @@ export function ClerkScripts() {
return (
(
{
type DynamicClerkScriptsProps = {
publishableKey: string;
- clerkJSUrl?: string;
- clerkJSVersion?: string;
- clerkUIUrl?: string;
+ __internal_clerkJSUrl?: string;
+ __internal_clerkJSVersion?: string;
+ __internal_clerkUIUrl?: string;
+ __internal_clerkUIVersion?: string;
domain?: string;
proxyUrl?: string;
prefetchUI?: boolean;
@@ -37,7 +38,16 @@ type DynamicClerkScriptsProps = {
* nonce fetching from the rest of the page, allowing static rendering/PPR to work.
*/
export async function DynamicClerkScripts(props: DynamicClerkScriptsProps) {
- const { publishableKey, clerkJSUrl, clerkJSVersion, clerkUIUrl, domain, proxyUrl, prefetchUI } = props;
+ const {
+ publishableKey,
+ __internal_clerkJSUrl,
+ __internal_clerkJSVersion,
+ __internal_clerkUIUrl,
+ __internal_clerkUIVersion,
+ domain,
+ proxyUrl,
+ prefetchUI,
+ } = props;
if (!publishableKey) {
return null;
@@ -48,9 +58,10 @@ export async function DynamicClerkScripts(props: DynamicClerkScriptsProps) {
return (
>;
+type ClerkNextContextValue = Partial & InternalClerkScriptProps>;
const ClerkNextOptionsCtx = React.createContext<{ value: ClerkNextContextValue } | undefined>(undefined);
ClerkNextOptionsCtx.displayName = 'ClerkNextOptionsCtx';
diff --git a/packages/nextjs/src/pages/ClerkProvider.tsx b/packages/nextjs/src/pages/ClerkProvider.tsx
index 5bc6c3b76f8..6d47886a470 100644
--- a/packages/nextjs/src/pages/ClerkProvider.tsx
+++ b/packages/nextjs/src/pages/ClerkProvider.tsx
@@ -1,7 +1,9 @@
-import { ClerkProvider as ReactClerkProvider } from '@clerk/react';
-import type { Ui } from '@clerk/react/internal';
-// Override Clerk React error thrower to show that errors come from @clerk/nextjs
-import { setClerkJSLoadingErrorPackageName, setErrorThrowerOptions } from '@clerk/react/internal';
+import {
+ InternalClerkProvider as ReactClerkProvider,
+ setClerkJSLoadingErrorPackageName,
+ setErrorThrowerOptions,
+ type Ui,
+} from '@clerk/react/internal';
import { useRouter } from 'next/router';
import React from 'react';
diff --git a/packages/nextjs/src/pages/ClerkScripts.tsx b/packages/nextjs/src/pages/ClerkScripts.tsx
index 508100da3bd..a9f7e89ebb2 100644
--- a/packages/nextjs/src/pages/ClerkScripts.tsx
+++ b/packages/nextjs/src/pages/ClerkScripts.tsx
@@ -23,8 +23,16 @@ function ClerkScript(props: { scriptUrl: string; attributes: Record {
});
});
- describe('clerkUIUrl', () => {
- const defaultProps = { children: '' };
-
- it('accepts string URL for custom UI location', () => {
- expectTypeOf({ ...defaultProps, clerkUIUrl: 'https://custom.com/ui.js' }).toMatchTypeOf();
- });
-
- it('accepts undefined', () => {
- expectTypeOf({ ...defaultProps, clerkUIUrl: undefined }).toMatchTypeOf();
+ describe('internal script props', () => {
+ it('does not expose internal script props', () => {
+ expectTypeOf().not.toHaveProperty('__internal_clerkUIUrl');
+ expectTypeOf().not.toHaveProperty('__internal_clerkJSUrl');
+ expectTypeOf().not.toHaveProperty('__internal_clerkUIVersion');
+ expectTypeOf().not.toHaveProperty('__internal_clerkJSVersion');
});
});
diff --git a/packages/nextjs/src/server/constants.ts b/packages/nextjs/src/server/constants.ts
index 4bbc3b74fa5..b98542bdc27 100644
--- a/packages/nextjs/src/server/constants.ts
+++ b/packages/nextjs/src/server/constants.ts
@@ -3,8 +3,8 @@ import { isTruthy } from '@clerk/shared/underscore';
export const CLERK_JS_VERSION = process.env.NEXT_PUBLIC_CLERK_JS_VERSION || '';
export const CLERK_JS_URL = process.env.NEXT_PUBLIC_CLERK_JS_URL || '';
-export const CLERK_UI_VERSION = process.env.NEXT_PUBLIC_CLERK_UI_VERSION || '';
export const CLERK_UI_URL = process.env.NEXT_PUBLIC_CLERK_UI_URL || '';
+export const CLERK_UI_VERSION = process.env.NEXT_PUBLIC_CLERK_UI_VERSION || '';
export const API_VERSION = process.env.CLERK_API_VERSION || 'v1';
export const SECRET_KEY = process.env.CLERK_SECRET_KEY || '';
export const MACHINE_SECRET_KEY = process.env.CLERK_MACHINE_SECRET_KEY || '';
diff --git a/packages/nextjs/src/utils/clerk-script-tags.tsx b/packages/nextjs/src/utils/clerk-script-tags.tsx
index 588d852e349..b7d67c73cd4 100644
--- a/packages/nextjs/src/utils/clerk-script-tags.tsx
+++ b/packages/nextjs/src/utils/clerk-script-tags.tsx
@@ -3,9 +3,10 @@ import React from 'react';
type ClerkScriptTagsProps = {
publishableKey: string;
- clerkJSUrl?: string;
- clerkJSVersion?: string;
- clerkUIUrl?: string;
+ __internal_clerkJSUrl?: string;
+ __internal_clerkJSVersion?: string;
+ __internal_clerkUIUrl?: string;
+ __internal_clerkUIVersion?: string;
nonce?: string;
domain?: string;
proxyUrl?: string;
@@ -18,13 +19,24 @@ type ClerkScriptTagsProps = {
* No hooks or client-only imports — safe for both server and client components.
*/
export function ClerkScriptTags(props: ClerkScriptTagsProps) {
- const { publishableKey, clerkJSUrl, clerkJSVersion, clerkUIUrl, nonce, domain, proxyUrl, prefetchUI } = props;
+ const {
+ publishableKey,
+ __internal_clerkJSUrl,
+ __internal_clerkJSVersion,
+ __internal_clerkUIUrl,
+ __internal_clerkUIVersion,
+ nonce,
+ domain,
+ proxyUrl,
+ prefetchUI,
+ } = props;
const opts = {
publishableKey,
- clerkJSUrl,
- clerkJSVersion,
- clerkUIUrl,
+ __internal_clerkJSUrl,
+ __internal_clerkJSVersion,
+ __internal_clerkUIUrl,
+ __internal_clerkUIVersion,
nonce,
domain,
proxyUrl,
diff --git a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts
index e59be2f5715..afb09022061 100644
--- a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts
+++ b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts
@@ -1,3 +1,4 @@
+import type { InternalClerkScriptProps } from '@clerk/react/internal';
import { isTruthy } from '@clerk/shared/underscore';
import { SDK_METADATA } from '../server/constants';
@@ -18,14 +19,16 @@ function getPrefetchUIFromEnvAndProps(propsPrefetchUI: NextClerkProviderProps['p
}
// @ts-ignore - https://github.com/microsoft/TypeScript/issues/47663
-export const mergeNextClerkPropsWithEnv = (props: Omit): any => {
+export const mergeNextClerkPropsWithEnv = (
+ props: Omit & InternalClerkScriptProps,
+): any => {
return {
...props,
publishableKey: props.publishableKey || process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY || '',
- clerkJSUrl: props.clerkJSUrl || process.env.NEXT_PUBLIC_CLERK_JS_URL,
- clerkJSVersion: props.clerkJSVersion || process.env.NEXT_PUBLIC_CLERK_JS_VERSION,
- clerkUIUrl: props.clerkUIUrl || process.env.NEXT_PUBLIC_CLERK_UI_URL,
- clerkUIVersion: props.clerkUIVersion || process.env.NEXT_PUBLIC_CLERK_UI_VERSION,
+ __internal_clerkJSUrl: props.__internal_clerkJSUrl || process.env.NEXT_PUBLIC_CLERK_JS_URL,
+ __internal_clerkJSVersion: props.__internal_clerkJSVersion || process.env.NEXT_PUBLIC_CLERK_JS_VERSION,
+ __internal_clerkUIUrl: props.__internal_clerkUIUrl || process.env.NEXT_PUBLIC_CLERK_UI_URL,
+ __internal_clerkUIVersion: props.__internal_clerkUIVersion || process.env.NEXT_PUBLIC_CLERK_UI_VERSION,
prefetchUI: getPrefetchUIFromEnvAndProps(props.prefetchUI),
proxyUrl: props.proxyUrl || process.env.NEXT_PUBLIC_CLERK_PROXY_URL || '',
domain: props.domain || process.env.NEXT_PUBLIC_CLERK_DOMAIN || '',
diff --git a/packages/nuxt/src/global.d.ts b/packages/nuxt/src/global.d.ts
index 84eec72d191..6fd1ecef727 100644
--- a/packages/nuxt/src/global.d.ts
+++ b/packages/nuxt/src/global.d.ts
@@ -16,7 +16,7 @@ declare module 'nuxt/schema' {
};
}
interface PublicRuntimeConfig {
- clerk: Omit & {
+ clerk: PluginOptions & {
/**
* The URL that `@clerk/clerk-js` should be hot-loaded from.
* Supports NUXT_PUBLIC_CLERK_JS_URL env var.
@@ -27,6 +27,14 @@ declare module 'nuxt/schema' {
* Supports NUXT_PUBLIC_CLERK_UI_URL env var.
*/
uiUrl?: string;
+ /**
+ * The npm version for `@clerk/clerk-js`.
+ */
+ clerkJSVersion?: string;
+ /**
+ * The npm version for `@clerk/ui`.
+ */
+ clerkUIVersion?: string;
};
}
}
diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts
index c4ee151a95a..49f2505e3ee 100644
--- a/packages/nuxt/src/module.ts
+++ b/packages/nuxt/src/module.ts
@@ -1,4 +1,4 @@
-import type { Without } from '@clerk/shared/types';
+import type { InternalClerkScriptProps, Without } from '@clerk/shared/types';
import type { PluginOptions } from '@clerk/vue';
import {
addComponent,
@@ -12,30 +12,28 @@ import {
updateRuntimeConfig,
} from '@nuxt/kit';
-export type ModuleOptions = Without<
- PluginOptions,
- 'routerPush' | 'routerReplace' | 'publishableKey' | 'initialState'
-> & {
- publishableKey?: string;
- /**
- * Skip the automatic server middleware registration. When enabled, you'll need to
- * register the middleware manually in your application.
- *
- * @default false
- *
- * @example
- *
- * ```ts
- * // server/middleware/clerk.ts
- * import { clerkMiddleware } from '@clerk/nuxt/server'
- *
- * export default clerkMiddleware((event) => {
- * console.log('auth', event.context.auth())
- * })
- * ```
- */
- skipServerMiddleware?: boolean;
-};
+export type ModuleOptions = Without &
+ InternalClerkScriptProps & {
+ publishableKey?: string;
+ /**
+ * Skip the automatic server middleware registration. When enabled, you'll need to
+ * register the middleware manually in your application.
+ *
+ * @default false
+ *
+ * @example
+ *
+ * ```ts
+ * // server/middleware/clerk.ts
+ * import { clerkMiddleware } from '@clerk/nuxt/server'
+ *
+ * export default clerkMiddleware((event) => {
+ * console.log('auth', event.context.auth())
+ * })
+ * ```
+ */
+ skipServerMiddleware?: boolean;
+ };
export default defineNuxtModule({
meta: {
@@ -64,12 +62,12 @@ export default defineNuxtModule({
signUpForceRedirectUrl: options.signUpForceRedirectUrl,
signUpUrl: options.signUpUrl,
domain: options.domain,
- // Using jsUrl/uiUrl instead of clerkJSUrl/clerkUIUrl to support
+ // Using jsUrl/uiUrl instead of __internal_clerkJSUrl/__internal_clerkUIUrl to support
// NUXT_PUBLIC_CLERK_JS_URL and NUXT_PUBLIC_CLERK_UI_URL env vars.
- jsUrl: options.clerkJSUrl,
- uiUrl: options.clerkUIUrl,
- clerkJSVersion: options.clerkJSVersion,
- clerkUIVersion: options.clerkUIVersion,
+ jsUrl: options.__internal_clerkJSUrl,
+ uiUrl: options.__internal_clerkUIUrl,
+ clerkJSVersion: options.__internal_clerkJSVersion,
+ clerkUIVersion: options.__internal_clerkUIVersion,
// prefetchUI config: can be false or undefined
prefetchUI: options.prefetchUI,
isSatellite: options.isSatellite,
diff --git a/packages/nuxt/src/runtime/plugin.ts b/packages/nuxt/src/runtime/plugin.ts
index 03fdeb75d25..650358ef02c 100644
--- a/packages/nuxt/src/runtime/plugin.ts
+++ b/packages/nuxt/src/runtime/plugin.ts
@@ -21,9 +21,11 @@ export default defineNuxtPlugin(nuxtApp => {
nuxtApp.vueApp.use(clerkPlugin as any, {
...clerkConfig,
- // Map jsUrl/uiUrl to clerkJSUrl/clerkUIUrl as expected by the Vue plugin
- clerkJSUrl: clerkConfig.jsUrl,
- clerkUIUrl: clerkConfig.uiUrl,
+ // Map jsUrl/uiUrl to __internal_clerkJSUrl/__internal_clerkUIUrl as expected by the Vue plugin
+ __internal_clerkJSUrl: clerkConfig.jsUrl,
+ __internal_clerkUIUrl: clerkConfig.uiUrl,
+ __internal_clerkJSVersion: clerkConfig.clerkJSVersion,
+ __internal_clerkUIVersion: clerkConfig.clerkUIVersion,
sdkMetadata: {
name: PACKAGE_NAME,
version: PACKAGE_VERSION,
diff --git a/packages/react-router/src/client/ReactRouterClerkProvider.tsx b/packages/react-router/src/client/ReactRouterClerkProvider.tsx
index ce2d7857719..5abefcbb341 100644
--- a/packages/react-router/src/client/ReactRouterClerkProvider.tsx
+++ b/packages/react-router/src/client/ReactRouterClerkProvider.tsx
@@ -1,5 +1,4 @@
-import { ClerkProvider as ReactClerkProvider } from '@clerk/react';
-import type { Ui } from '@clerk/react/internal';
+import { InternalClerkProvider as ReactClerkProvider, type Ui } from '@clerk/react/internal';
import React from 'react';
import {
@@ -93,10 +92,10 @@ function ClerkProviderBase({ children, ...rest }: ClerkProv
signUpForceRedirectUrl: __signUpForceRedirectUrl,
signInFallbackRedirectUrl: __signInFallbackRedirectUrl,
signUpFallbackRedirectUrl: __signUpFallbackRedirectUrl,
- clerkJSUrl: __clerkJSUrl,
- clerkJSVersion: __clerkJSVersion,
- clerkUIUrl: __clerkUIUrl,
- clerkUIVersion: __clerkUIVersion,
+ __internal_clerkJSUrl: __clerkJSUrl,
+ __internal_clerkJSVersion: __clerkJSVersion,
+ __internal_clerkUIUrl: __clerkUIUrl,
+ __internal_clerkUIVersion: __clerkUIVersion,
prefetchUI: __prefetchUI,
telemetry: {
disabled: __telemetryDisabled,
diff --git a/packages/react-router/src/client/__tests__/ClerkProvider.test.tsx b/packages/react-router/src/client/__tests__/ClerkProvider.test.tsx
index 6164770edb3..1677e93a22a 100644
--- a/packages/react-router/src/client/__tests__/ClerkProvider.test.tsx
+++ b/packages/react-router/src/client/__tests__/ClerkProvider.test.tsx
@@ -4,10 +4,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const mockClerkProvider = vi.fn(({ children }: { children: React.ReactNode }) => {children}
);
-vi.mock('@clerk/react', () => ({
- ClerkProvider: (props: any) => mockClerkProvider(props),
+vi.mock('@clerk/react/internal', () => ({
+ InternalClerkProvider: (props: any) => mockClerkProvider(props),
}));
+vi.mock('@clerk/react', () => ({}));
+
vi.mock('react-router', () => ({
useNavigate: () => vi.fn(),
useLocation: () => ({ pathname: '/' }),
@@ -17,11 +19,11 @@ vi.mock('react-router', () => ({
vi.mock('../../utils/assert', () => ({
assertPublishableKeyInSpaMode: vi.fn(),
assertValidClerkState: vi.fn(),
- isSpaMode: () => true,
+ isSpaMode: () => false,
warnForSsr: vi.fn(),
}));
-describe('ClerkProvider clerkUIUrl prop', () => {
+describe('ClerkProvider __internal_clerkUIUrl via clerkState', () => {
beforeEach(() => {
vi.clearAllMocks();
});
@@ -30,26 +32,32 @@ describe('ClerkProvider clerkUIUrl prop', () => {
vi.clearAllMocks();
});
- it('passes clerkUIUrl prop to the underlying ClerkProvider', async () => {
+ it('passes __internal_clerkUIUrl from clerkState to the underlying ClerkProvider', async () => {
const { ClerkProvider } = await import('../ReactRouterClerkProvider');
+ const clerkState = {
+ __type: 'clerkState' as const,
+ __internal_clerk_state: {
+ __clerk_ssr_state: undefined,
+ __publishableKey: 'pk_test_xxx',
+ __clerkUIUrl: 'https://custom.clerk.ui/ui.js',
+ },
+ };
+
render(
-
+
Test
,
);
expect(mockClerkProvider).toHaveBeenCalledWith(
expect.objectContaining({
- clerkUIUrl: 'https://custom.clerk.ui/ui.js',
+ __internal_clerkUIUrl: 'https://custom.clerk.ui/ui.js',
}),
);
});
- it('passes clerkUIUrl as undefined when not provided', async () => {
+ it('passes __internal_clerkUIUrl as undefined when not in clerkState', async () => {
const { ClerkProvider } = await import('../ReactRouterClerkProvider');
render(
@@ -60,30 +68,36 @@ describe('ClerkProvider clerkUIUrl prop', () => {
expect(mockClerkProvider).toHaveBeenCalledWith(
expect.objectContaining({
- clerkUIUrl: undefined,
+ __internal_clerkUIUrl: undefined,
}),
);
});
- it('passes clerkUIUrl alongside other props', async () => {
+ it('passes __internal_clerkUIUrl alongside other props from clerkState', async () => {
const { ClerkProvider } = await import('../ReactRouterClerkProvider');
+ const clerkState = {
+ __type: 'clerkState' as const,
+ __internal_clerk_state: {
+ __clerk_ssr_state: undefined,
+ __publishableKey: 'pk_test_xxx',
+ __clerkUIUrl: 'https://custom.clerk.ui/ui.js',
+ __clerkJSUrl: 'https://custom.clerk.js/clerk.js',
+ __signInUrl: '/sign-in',
+ __signUpUrl: '/sign-up',
+ },
+ };
+
render(
-
+
Test
,
);
expect(mockClerkProvider).toHaveBeenCalledWith(
expect.objectContaining({
- clerkUIUrl: 'https://custom.clerk.ui/ui.js',
- clerkJSUrl: 'https://custom.clerk.js/clerk.js',
+ __internal_clerkUIUrl: 'https://custom.clerk.ui/ui.js',
+ __internal_clerkJSUrl: 'https://custom.clerk.js/clerk.js',
signInUrl: '/sign-in',
signUpUrl: '/sign-up',
}),
diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts
index 4f35a1a000f..ff4db48fe49 100644
--- a/packages/react/src/internal.ts
+++ b/packages/react/src/internal.ts
@@ -1,3 +1,10 @@
+import type { InternalClerkScriptProps } from '@clerk/shared/types';
+import type { Ui } from '@clerk/ui/internal';
+import type React from 'react';
+
+import { ClerkProvider } from './contexts/ClerkProvider';
+import type { ClerkProviderProps } from './types';
+
export { setErrorThrowerOptions } from './errors/errorThrower';
export { MultisessionAppSupport } from './components/controlComponents';
export { useRoutingProps } from './hooks/useRoutingProps';
@@ -17,3 +24,13 @@ export {
} from '@clerk/shared/loadClerkJsScript';
export type { Ui } from '@clerk/ui/internal';
+
+export type { InternalClerkScriptProps } from '@clerk/shared/types';
+
+/**
+ * A wider-typed version of ClerkProvider that accepts internal script props.
+ * Framework SDKs should use this instead of the public ClerkProvider.
+ */
+export const InternalClerkProvider = ClerkProvider as unknown as ((
+ props: ClerkProviderProps & InternalClerkScriptProps,
+) => React.JSX.Element) & { displayName: string };
diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts
index 99c15fbb0f9..9c38a97c989 100644
--- a/packages/react/src/types.ts
+++ b/packages/react/src/types.ts
@@ -1,6 +1,7 @@
import type {
Clerk,
InitialState,
+ InternalClerkScriptProps,
IsomorphicClerkOptions,
LoadedClerk,
RedirectUrlProp,
@@ -36,7 +37,10 @@ declare global {
/**
* @interface
*/
-export type ClerkProviderProps = Omit & {
+export type ClerkProviderProps = Omit<
+ IsomorphicClerkOptions,
+ 'appearance' | keyof InternalClerkScriptProps
+> & {
children: React.ReactNode;
/**
* Provide an initial state of the Clerk client during server-side rendering. You don't need to set this value yourself unless you're [developing an SDK](https://clerk.com/docs/guides/development/sdk-development/overview).
diff --git a/packages/shared/src/__tests__/loadClerkJsScript.spec.ts b/packages/shared/src/__tests__/loadClerkJsScript.spec.ts
index 4cc384e7893..69eeedf576e 100644
--- a/packages/shared/src/__tests__/loadClerkJsScript.spec.ts
+++ b/packages/shared/src/__tests__/loadClerkJsScript.spec.ts
@@ -147,9 +147,9 @@ describe('clerkJsScriptUrl()', () => {
const mockDevPublishableKey = 'pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk';
const mockProdPublishableKey = 'pk_live_ZXhhbXBsZS5jbGVyay5jb20k'; // example.clerk.com
- test('returns clerkJSUrl when provided', () => {
+ test('returns __internal_clerkJSUrl when provided', () => {
const customUrl = 'https://custom.clerk.com/clerk.js';
- const result = clerkJsScriptUrl({ clerkJSUrl: customUrl, publishableKey: mockDevPublishableKey });
+ const result = clerkJsScriptUrl({ __internal_clerkJSUrl: customUrl, publishableKey: mockDevPublishableKey });
expect(result).toBe(customUrl);
});
@@ -165,8 +165,8 @@ describe('clerkJsScriptUrl()', () => {
expect(result).toBe(`https://example.clerk.com/npm/@clerk/clerk-js@${jsPackageMajorVersion}/dist/clerk.browser.js`);
});
- test('uses provided clerkJSVersion', () => {
- const result = clerkJsScriptUrl({ publishableKey: mockDevPublishableKey, clerkJSVersion: '6' });
+ test('uses provided __internal_clerkJSVersion', () => {
+ const result = clerkJsScriptUrl({ publishableKey: mockDevPublishableKey, __internal_clerkJSVersion: '6' });
expect(result).toContain('/npm/@clerk/clerk-js@6/');
});
});
@@ -386,9 +386,9 @@ describe('clerkUIScriptUrl()', () => {
const mockDevPublishableKey = 'pk_test_Zm9vLWJhci0xMy5jbGVyay5hY2NvdW50cy5kZXYk';
const mockProdPublishableKey = 'pk_live_ZXhhbXBsZS5jbGVyay5jb20k'; // example.clerk.com
- test('returns clerkUIUrl when provided', () => {
+ test('returns __internal_clerkUIUrl when provided', () => {
const customUrl = 'https://custom.clerk.com/ui.js';
- const result = clerkUIScriptUrl({ clerkUIUrl: customUrl, publishableKey: mockDevPublishableKey });
+ const result = clerkUIScriptUrl({ __internal_clerkUIUrl: customUrl, publishableKey: mockDevPublishableKey });
expect(result).toBe(customUrl);
});
@@ -404,11 +404,6 @@ describe('clerkUIScriptUrl()', () => {
expect(result).toBe(`https://example.clerk.com/npm/@clerk/ui@${uiPackageMajorVersion}/dist/ui.browser.js`);
});
- test('uses provided clerkUIVersion', () => {
- const result = clerkUIScriptUrl({ publishableKey: mockDevPublishableKey, clerkUIVersion: '1' });
- expect(result).toContain('/npm/@clerk/ui@1/');
- });
-
test('uses latest as default version when not specified', () => {
const result = clerkUIScriptUrl({ publishableKey: mockDevPublishableKey });
// When no version is specified, versionSelector should return the major version
diff --git a/packages/shared/src/loadClerkJsScript.ts b/packages/shared/src/loadClerkJsScript.ts
index 5c14b538bee..96171f5c648 100644
--- a/packages/shared/src/loadClerkJsScript.ts
+++ b/packages/shared/src/loadClerkJsScript.ts
@@ -12,8 +12,10 @@ const errorThrower = buildErrorThrower({ packageName: '@clerk/shared' });
export type LoadClerkJSScriptOptions = {
publishableKey: string;
- clerkJSUrl?: string;
- clerkJSVersion?: string;
+ /** @internal */
+ __internal_clerkJSUrl?: string;
+ /** @internal */
+ __internal_clerkJSVersion?: string;
sdkMetadata?: SDKMetadata;
proxyUrl?: string;
domain?: string;
@@ -33,8 +35,10 @@ export type LoadClerkJsScriptOptions = LoadClerkJSScriptOptions;
export type LoadClerkUIScriptOptions = {
publishableKey: string;
- clerkUIUrl?: string;
- clerkUIVersion?: string;
+ /** @internal */
+ __internal_clerkUIUrl?: string;
+ /** @internal */
+ __internal_clerkUIVersion?: string;
proxyUrl?: string;
domain?: string;
nonce?: string;
@@ -220,26 +224,26 @@ export const loadClerkUIScript = async (opts?: LoadClerkUIScriptOptions): Promis
};
export const clerkJSScriptUrl = (opts: LoadClerkJSScriptOptions) => {
- const { clerkJSUrl, clerkJSVersion, proxyUrl, domain, publishableKey } = opts;
+ const { __internal_clerkJSUrl, __internal_clerkJSVersion, proxyUrl, domain, publishableKey } = opts;
- if (clerkJSUrl) {
- return clerkJSUrl;
+ if (__internal_clerkJSUrl) {
+ return __internal_clerkJSUrl;
}
const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });
- const version = versionSelector(clerkJSVersion);
+ const version = versionSelector(__internal_clerkJSVersion);
return `https://${scriptHost}/npm/@clerk/clerk-js@${version}/dist/clerk.browser.js`;
};
export const clerkUIScriptUrl = (opts: LoadClerkUIScriptOptions) => {
- const { clerkUIUrl, clerkUIVersion, proxyUrl, domain, publishableKey } = opts;
+ const { __internal_clerkUIUrl, __internal_clerkUIVersion, proxyUrl, domain, publishableKey } = opts;
- if (clerkUIUrl) {
- return clerkUIUrl;
+ if (__internal_clerkUIUrl) {
+ return __internal_clerkUIUrl;
}
const scriptHost = buildScriptHost({ publishableKey, proxyUrl, domain });
- const version = versionSelector(clerkUIVersion, UI_PACKAGE_VERSION);
+ const version = versionSelector(__internal_clerkUIVersion, UI_PACKAGE_VERSION);
return `https://${scriptHost}/npm/@clerk/ui@${version}/dist/ui.browser.js`;
};
diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts
index 6f0182ab318..dfede252d9a 100644
--- a/packages/shared/src/types/clerk.ts
+++ b/packages/shared/src/types/clerk.ts
@@ -2487,24 +2487,39 @@ export type ClerkProp =
| undefined
| null;
+/**
+ * Internal props used by framework SDKs to configure script URLs and versions.
+ * These are omitted from consumer-facing types like ClerkProviderProps.
+ */
+export type InternalClerkScriptProps = {
+ __internal_clerkJSUrl?: string;
+ __internal_clerkJSVersion?: string;
+ __internal_clerkUIUrl?: string;
+ __internal_clerkUIVersion?: string;
+};
+
export type IsomorphicClerkOptions = Without & {
Clerk?: ClerkProp;
/**
* The URL that `@clerk/clerk-js` should be hot-loaded from.
+ * @internal
*/
- clerkJSUrl?: string;
+ __internal_clerkJSUrl?: string;
/**
* The npm version for `@clerk/clerk-js`.
+ * @internal
*/
- clerkJSVersion?: string;
+ __internal_clerkJSVersion?: string;
/**
* The URL that `@clerk/ui` should be hot-loaded from.
+ * @internal
*/
- clerkUIUrl?: string;
+ __internal_clerkUIUrl?: string;
/**
* The npm version for `@clerk/ui`.
+ * @internal
*/
- clerkUIVersion?: string;
+ __internal_clerkUIVersion?: string;
/**
* The Clerk Publishable Key for your instance. This can be found on the [API keys](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard.
*/
diff --git a/packages/tanstack-react-start/src/client/ClerkProvider.tsx b/packages/tanstack-react-start/src/client/ClerkProvider.tsx
index 8247efbac29..23977e0a999 100644
--- a/packages/tanstack-react-start/src/client/ClerkProvider.tsx
+++ b/packages/tanstack-react-start/src/client/ClerkProvider.tsx
@@ -1,5 +1,4 @@
-import { ClerkProvider as ReactClerkProvider } from '@clerk/react';
-import type { Ui } from '@clerk/react/internal';
+import { InternalClerkProvider as ReactClerkProvider, type Ui } from '@clerk/react/internal';
import { ScriptOnce } from '@tanstack/react-router';
import { getGlobalStartContext } from '@tanstack/react-start';
import { useEffect } from 'react';
diff --git a/packages/tanstack-react-start/src/client/utils.ts b/packages/tanstack-react-start/src/client/utils.ts
index f89d19d7ce0..e97c338885f 100644
--- a/packages/tanstack-react-start/src/client/utils.ts
+++ b/packages/tanstack-react-start/src/client/utils.ts
@@ -1,3 +1,5 @@
+import type { InternalClerkScriptProps } from '@clerk/shared/types';
+
import { getPublicEnvVariables } from '../utils/env';
import type { TanstackStartClerkProviderProps } from './types';
@@ -5,11 +7,12 @@ type TanStackProviderAndInitialProps = Omit {
+): TanStackProviderAndInitialProps &
+ InternalClerkScriptProps & {
+ clerkSsrState: any;
+ __keylessClaimUrl?: string;
+ __keylessApiKeysUrl?: string;
+ } => {
const {
__clerk_ssr_state,
__publishableKey,
@@ -41,10 +44,10 @@ export const pickFromClerkInitState = (
isSatellite: !!__isSatellite,
signInUrl: __signInUrl,
signUpUrl: __signUpUrl,
- clerkJSUrl: __clerkJSUrl,
- clerkJSVersion: __clerkJSVersion,
- clerkUIUrl: __clerkUIUrl,
- clerkUIVersion: __clerkUIVersion,
+ __internal_clerkJSUrl: __clerkJSUrl,
+ __internal_clerkJSVersion: __clerkJSVersion,
+ __internal_clerkUIUrl: __clerkUIUrl,
+ __internal_clerkUIVersion: __clerkUIVersion,
prefetchUI: __prefetchUI,
telemetry: {
disabled: __telemetryDisabled,
@@ -68,10 +71,10 @@ export const mergeWithPublicEnvs = (restInitState: any) => {
isSatellite: restInitState.isSatellite || envVars.isSatellite,
signInUrl: restInitState.signInUrl || envVars.signInUrl,
signUpUrl: restInitState.signUpUrl || envVars.signUpUrl,
- clerkJSUrl: restInitState.clerkJSUrl || envVars.clerkJsUrl,
- clerkJSVersion: restInitState.clerkJSVersion || envVars.clerkJsVersion,
- clerkUIUrl: restInitState.clerkUIUrl || envVars.clerkUIUrl,
- clerkUIVersion: restInitState.clerkUIVersion || envVars.clerkUIVersion,
+ __internal_clerkJSUrl: restInitState.__internal_clerkJSUrl || envVars.clerkJsUrl,
+ __internal_clerkJSVersion: restInitState.__internal_clerkJSVersion || envVars.clerkJsVersion,
+ __internal_clerkUIUrl: restInitState.__internal_clerkUIUrl || envVars.clerkUIUrl,
+ __internal_clerkUIVersion: restInitState.__internal_clerkUIVersion || envVars.clerkUIVersion,
signInForceRedirectUrl: restInitState.signInForceRedirectUrl,
prefetchUI: restInitState.prefetchUI ?? envVars.prefetchUI,
};
diff --git a/packages/upgrade/src/codemods/__tests__/__fixtures__/transform-internal-clerk-js-ui-props.fixtures.js b/packages/upgrade/src/codemods/__tests__/__fixtures__/transform-internal-clerk-js-ui-props.fixtures.js
new file mode 100644
index 00000000000..14efd63a29a
--- /dev/null
+++ b/packages/upgrade/src/codemods/__tests__/__fixtures__/transform-internal-clerk-js-ui-props.fixtures.js
@@ -0,0 +1,251 @@
+export const fixtures = [
+ {
+ name: 'JSX: renames clerkJSUrl to __internal_clerkJSUrl',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+ {
+ name: 'JSX: renames clerkJSVersion to __internal_clerkJSVersion',
+ source: `
+import { ClerkProvider } from '@clerk/react';
+
+export const App = () => (
+
+
+
+);
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/react';
+
+export const App = () => (
+
+
+
+);
+ `,
+ },
+ {
+ name: 'JSX: renames clerkUIUrl and clerkUIVersion',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+ {
+ name: 'JSX: renames all four props at once',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+ {
+ name: 'JSX: does not rename props on non-Clerk components',
+ source: `
+import { SomeProvider } from 'some-other-package';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ noChange: true,
+ },
+ {
+ name: 'JSX: handles aliased import',
+ source: `
+import { ClerkProvider as CP } from '@clerk/react';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider as CP } from '@clerk/react';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+ {
+ name: 'JSX: skips if __internal_ prop already exists',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+ {
+ name: 'Object: renames properties in object literal',
+ source: `
+const options = {
+ clerkJSUrl: 'https://js.example.com/clerk.js',
+ clerkJSVersion: '5.0.0',
+};
+ `,
+ output: `
+const options = {
+ __internal_clerkJSUrl: 'https://js.example.com/clerk.js',
+ __internal_clerkJSVersion: '5.0.0',
+};
+ `,
+ },
+ {
+ name: 'Object: renames all four properties',
+ source: `
+const options = {
+ clerkJSUrl: 'https://js.example.com/clerk.js',
+ clerkJSVersion: '5.0.0',
+ clerkUIUrl: 'https://ui.example.com/ui.js',
+ clerkUIVersion: '1.0.0',
+};
+ `,
+ output: `
+const options = {
+ __internal_clerkJSUrl: 'https://js.example.com/clerk.js',
+ __internal_clerkJSVersion: '5.0.0',
+ __internal_clerkUIUrl: 'https://ui.example.com/ui.js',
+ __internal_clerkUIVersion: '1.0.0',
+};
+ `,
+ },
+ {
+ name: 'No matching props (no changes)',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ noChange: true,
+ },
+ {
+ name: 'JSX: expression container value',
+ source: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+const jsUrl = 'https://js.example.com/clerk.js';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ output: `
+import { ClerkProvider } from '@clerk/nextjs';
+
+const jsUrl = 'https://js.example.com/clerk.js';
+
+export function App({ children }) {
+ return (
+
+ {children}
+
+ );
+}
+ `,
+ },
+];
diff --git a/packages/upgrade/src/codemods/__tests__/transform-internal-clerk-js-ui-props.test.js b/packages/upgrade/src/codemods/__tests__/transform-internal-clerk-js-ui-props.test.js
new file mode 100644
index 00000000000..a045cd5596d
--- /dev/null
+++ b/packages/upgrade/src/codemods/__tests__/transform-internal-clerk-js-ui-props.test.js
@@ -0,0 +1,17 @@
+import { applyTransform } from 'jscodeshift/dist/testUtils';
+import { describe, expect, it } from 'vitest';
+
+import transformer from '../transform-internal-clerk-js-ui-props.cjs';
+import { fixtures } from './__fixtures__/transform-internal-clerk-js-ui-props.fixtures';
+
+describe('transform-internal-clerk-js-ui-props', () => {
+ it.each(fixtures)('$name', ({ source, output, noChange }) => {
+ const result = applyTransform(transformer, {}, { source });
+
+ if (noChange) {
+ expect(result).toEqual('');
+ } else {
+ expect(result).toEqual(output.trim());
+ }
+ });
+});
diff --git a/packages/upgrade/src/codemods/transform-internal-clerk-js-ui-props.cjs b/packages/upgrade/src/codemods/transform-internal-clerk-js-ui-props.cjs
new file mode 100644
index 00000000000..2fbac369f63
--- /dev/null
+++ b/packages/upgrade/src/codemods/transform-internal-clerk-js-ui-props.cjs
@@ -0,0 +1,161 @@
+const CLERK_PACKAGE_PREFIX = '@clerk/';
+
+const PROP_RENAMES = new Map([
+ ['clerkJSUrl', '__internal_clerkJSUrl'],
+ ['clerkJSVersion', '__internal_clerkJSVersion'],
+ ['clerkUIUrl', '__internal_clerkUIUrl'],
+ ['clerkUIVersion', '__internal_clerkUIVersion'],
+]);
+
+const COMPONENTS_WITH_PROPS = new Set(['ClerkProvider']);
+
+module.exports = function transformInternalClerkJsUiProps({ source }, { jscodeshift: j, stats }) {
+ const root = j(source);
+ let dirty = false;
+
+ const { namedImports, namespaceImports } = collectClerkImports(root, j);
+
+ // Transform JSX attributes
+ root.find(j.JSXOpeningElement).forEach(path => {
+ const canonicalName = getCanonicalComponentName(path.node.name, namedImports, namespaceImports);
+ if (!canonicalName || !COMPONENTS_WITH_PROPS.has(canonicalName)) {
+ return;
+ }
+
+ for (const [oldName, newName] of PROP_RENAMES) {
+ if (renameJsxAttribute(j, path.node, oldName, newName)) {
+ dirty = true;
+ stats(oldName + 'Renamed');
+ }
+ }
+ });
+
+ // Transform object properties
+ for (const [oldName, newName] of PROP_RENAMES) {
+ if (renameObjectProperties(root, j, oldName, newName)) {
+ dirty = true;
+ stats(oldName + 'Renamed');
+ }
+ }
+
+ return dirty ? root.toSource() : undefined;
+};
+
+module.exports.parser = 'tsx';
+
+function collectClerkImports(root, j) {
+ const namedImports = new Map();
+ const namespaceImports = new Set();
+
+ root.find(j.ImportDeclaration).forEach(path => {
+ const sourceVal = path.node.source.value;
+ if (typeof sourceVal !== 'string' || !sourceVal.startsWith(CLERK_PACKAGE_PREFIX)) {
+ return;
+ }
+
+ for (const specifier of path.node.specifiers || []) {
+ if (j.ImportSpecifier.check(specifier)) {
+ const localName = specifier.local ? specifier.local.name : specifier.imported.name;
+ namedImports.set(localName, specifier.imported.name);
+ } else if (j.ImportNamespaceSpecifier.check(specifier) || j.ImportDefaultSpecifier.check(specifier)) {
+ namespaceImports.add(specifier.local.name);
+ }
+ }
+ });
+
+ return { namedImports, namespaceImports };
+}
+
+function getCanonicalComponentName(nameNode, namedImports, namespaceImports) {
+ if (!nameNode) {
+ return null;
+ }
+
+ if (nameNode.type === 'JSXIdentifier') {
+ return namedImports.get(nameNode.name) || nameNode.name;
+ }
+
+ if (nameNode.type === 'JSXMemberExpression') {
+ return getNamespaceMemberName(nameNode, namespaceImports);
+ }
+
+ return null;
+}
+
+function getNamespaceMemberName(memberNode, namespaceImports) {
+ if (memberNode.object.type === 'JSXIdentifier') {
+ return namespaceImports.has(memberNode.object.name) ? memberNode.property.name : null;
+ }
+
+ if (memberNode.object.type === 'JSXMemberExpression') {
+ const resolved = getNamespaceMemberName(memberNode.object, namespaceImports);
+ return resolved ? memberNode.property.name : null;
+ }
+
+ return null;
+}
+
+function renameJsxAttribute(j, jsxNode, oldName, newName) {
+ if (!jsxNode.attributes) {
+ return false;
+ }
+
+ const attrIndex = jsxNode.attributes.findIndex(attr => isJsxAttrNamed(attr, oldName));
+ if (attrIndex === -1) {
+ return false;
+ }
+
+ // If target already exists, just remove the old one
+ const targetExists = jsxNode.attributes.some(attr => isJsxAttrNamed(attr, newName));
+ if (targetExists) {
+ jsxNode.attributes.splice(attrIndex, 1);
+ return true;
+ }
+
+ jsxNode.attributes[attrIndex].name.name = newName;
+ return true;
+}
+
+function isJsxAttrNamed(attribute, name) {
+ return attribute && attribute.type === 'JSXAttribute' && attribute.name && attribute.name.name === name;
+}
+
+function renameObjectProperties(root, j, oldName, newName) {
+ let changed = false;
+
+ root.find(j.ObjectProperty).forEach(path => {
+ if (!isPropertyKeyNamed(path.node.key, oldName)) {
+ return;
+ }
+
+ if (path.node.shorthand) {
+ path.node.shorthand = false;
+ path.node.value = j.identifier(oldName);
+ }
+
+ if (path.node.key.type === 'Identifier') {
+ path.node.key.name = newName;
+ } else if (path.node.key.type === 'StringLiteral') {
+ path.node.key.value = newName;
+ } else if (path.node.key.type === 'Literal') {
+ path.node.key.value = newName;
+ }
+
+ changed = true;
+ });
+
+ return changed;
+}
+
+function isPropertyKeyNamed(keyNode, name) {
+ if (!keyNode) {
+ return false;
+ }
+ if (keyNode.type === 'Identifier') {
+ return keyNode.name === name;
+ }
+ if (keyNode.type === 'StringLiteral' || keyNode.type === 'Literal') {
+ return keyNode.value === name;
+ }
+ return false;
+}
diff --git a/packages/upgrade/src/versions/core-3/changes/clerk-js-ui-props-internalized.md b/packages/upgrade/src/versions/core-3/changes/clerk-js-ui-props-internalized.md
new file mode 100644
index 00000000000..e9dca2fdcc1
--- /dev/null
+++ b/packages/upgrade/src/versions/core-3/changes/clerk-js-ui-props-internalized.md
@@ -0,0 +1,28 @@
+---
+title: '`clerkJSUrl`, `clerkJSVersion`, `clerkUIUrl`, and `clerkUIVersion` props removed'
+matcher:
+ - 'clerkJSUrl'
+ - 'clerkJSVersion'
+ - 'clerkUIUrl'
+ - 'clerkUIVersion'
+category: 'deprecation-removal'
+---
+
+The `clerkJSUrl`, `clerkJSVersion`, `clerkUIUrl`, and `clerkUIVersion` props have been removed from `ClerkProvider` and related configuration options. These props were intended for internal use and are no longer part of the public API.
+
+If you are using these props, prefix them with `__internal_` to continue using them. Note that these are internal APIs and may change without notice.
+
+A codemod is available to automatically apply this change:
+
+```diff
+
+```
diff --git a/packages/upgrade/src/versions/core-3/index.js b/packages/upgrade/src/versions/core-3/index.js
index b30b1a8ba32..3b893520fe6 100644
--- a/packages/upgrade/src/versions/core-3/index.js
+++ b/packages/upgrade/src/versions/core-3/index.js
@@ -31,5 +31,6 @@ export default {
// Migrate @clerk/react-router/api.server → @clerk/react-router/server
{ name: 'transform-react-router-api-server', packages: ['react-router'] },
{ name: 'transform-satellite-auto-sync', packages: ['nextjs', 'react', 'expo', 'astro', 'tanstack-react-start'] },
+ 'transform-internal-clerk-js-ui-props',
],
};
diff --git a/packages/vue/src/plugin.ts b/packages/vue/src/plugin.ts
index cb61569ee5e..04573bbaa45 100644
--- a/packages/vue/src/plugin.ts
+++ b/packages/vue/src/plugin.ts
@@ -6,6 +6,7 @@ import type {
ClerkOptions,
ClientResource,
InitialState,
+ InternalClerkScriptProps,
IsomorphicClerkOptions,
MultiDomainAndOrProxy,
Resources,
@@ -23,7 +24,10 @@ declare global {
}
}
-export type PluginOptions = Without &
+export type PluginOptions = Without<
+ IsomorphicClerkOptions,
+ 'domain' | 'proxyUrl' | 'appearance' | keyof InternalClerkScriptProps
+> &
MultiDomainAndOrProxy & {
initialState?: InitialState;
appearance?: Appearance;
diff --git a/playground/app-router/src/app/layout.tsx b/playground/app-router/src/app/layout.tsx
index c90b61270fd..89d40d4d778 100644
--- a/playground/app-router/src/app/layout.tsx
+++ b/playground/app-router/src/app/layout.tsx
@@ -13,7 +13,7 @@ export const metadata = {
export default function RootLayout({ children }: { children: React.ReactNode }) {
// console.log(auth());
return (
-
+