From a32d7bc186d5e6718891da92ce24491a04851652 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 19 Nov 2025 13:52:54 -0600 Subject: [PATCH 1/3] feat(repo): Remove deprecated props --- .changeset/remove-deprecated-props.md | 11 ++ .../src/components/CustomUserButton.astro | 2 +- .../astro-node/src/layouts/react/Layout.astro | 5 +- integration/templates/react-cra/src/App.tsx | 2 +- integration/templates/react-vite/src/App.tsx | 2 +- packages/astro/src/stores/external.ts | 2 +- .../clerk-js/src/core/__tests__/clerk.test.ts | 104 +----------------- packages/clerk-js/src/core/clerk.ts | 23 +--- .../clerk-js/src/core/resources/Client.ts | 8 -- packages/localizations/README.md | 1 + packages/nextjs/src/server/clerkMiddleware.ts | 5 - packages/nextjs/src/server/index.ts | 7 +- .../src/utils/mergeNextClerkPropsWithEnv.ts | 2 - .../src/client/ReactRouterClerkProvider.tsx | 4 - packages/react-router/src/client/types.ts | 2 - .../server/__tests__/clerkMiddleware.test.ts | 6 - .../src/server/clerkMiddleware.ts | 4 - .../src/server/legacyAuthenticateRequest.ts | 4 +- .../react-router/src/server/loadOptions.ts | 4 - packages/react-router/src/server/types.ts | 7 +- packages/react-router/src/server/utils.ts | 2 - .../src/components/controlComponents.tsx | 5 +- .../clerk-js/__tests__/redirectUrls.test.ts | 58 ---------- .../internal/clerk-js/assertNoLegacyProp.ts | 25 ----- .../src/internal/clerk-js/redirectUrls.ts | 42 +------ packages/shared/src/types/clerk.ts | 69 +----------- packages/shared/src/types/client.ts | 6 +- packages/shared/src/types/redirects.ts | 20 +--- .../tanstack-react-start/src/client/utils.ts | 6 - .../src/server/loadOptions.ts | 5 - .../tanstack-react-start/src/server/types.ts | 4 +- .../CreateOrganizationForm.tsx | 9 +- .../CreateOrganizationPage.tsx | 3 +- .../__tests__/CreateOrganization.test.tsx | 100 ----------------- .../OrganizationList/OrganizationListPage.tsx | 3 +- .../__tests__/OrganizationList.test.tsx | 20 ---- .../OrganizationSwitcherPopover.tsx | 3 +- .../__tests__/OrganizationSwitcher.test.tsx | 17 --- .../UserButton/__tests__/UserButton.test.tsx | 20 ---- .../contexts/components/CreateOrganization.ts | 1 - .../contexts/components/OrganizationList.ts | 1 - .../components/OrganizationSwitcher.ts | 1 - .../ui/src/contexts/components/UserButton.ts | 17 +-- .../app-router/src/app/protected/page.tsx | 1 - playground/vite-react-ts/src/App.tsx | 2 +- 45 files changed, 42 insertions(+), 603 deletions(-) create mode 100644 .changeset/remove-deprecated-props.md delete mode 100644 packages/shared/src/internal/clerk-js/assertNoLegacyProp.ts diff --git a/.changeset/remove-deprecated-props.md b/.changeset/remove-deprecated-props.md new file mode 100644 index 00000000000..bcd3c0bf27e --- /dev/null +++ b/.changeset/remove-deprecated-props.md @@ -0,0 +1,11 @@ +--- +"@clerk/nextjs": major +"@clerk/clerk-react": major +"@clerk/clerk-js": major +"@clerk/shared": major +"@clerk/ui": major +"@clerk/react-router": major +"@clerk/tanstack-react-start": major +--- + +Remove all previously deprecated UI props across the Next.js, React and clerk-js SDKs. The legacy `afterSign(In|Up)Url`/`redirectUrl` props, `UserButton` sign-out overrides, organization `hideSlug` flags, `OrganizationSwitcher`'s `afterSwitchOrganizationUrl`, `Client.activeSessions`, `setActive({ beforeEmit })`, and the `ClerkMiddlewareAuthObject` type alias are no longer exported. Components now rely solely on the new redirect options and server-side configuration. diff --git a/integration/templates/astro-node/src/components/CustomUserButton.astro b/integration/templates/astro-node/src/components/CustomUserButton.astro index 7586c0db5ba..6eed2bea4a9 100644 --- a/integration/templates/astro-node/src/components/CustomUserButton.astro +++ b/integration/templates/astro-node/src/components/CustomUserButton.astro @@ -2,7 +2,7 @@ import { UserButton } from '@clerk/astro/components'; --- - + diff --git a/integration/templates/astro-node/src/layouts/react/Layout.astro b/integration/templates/astro-node/src/layouts/react/Layout.astro index 2bc68f059e2..41b878880e3 100644 --- a/integration/templates/astro-node/src/layouts/react/Layout.astro +++ b/integration/templates/astro-node/src/layouts/react/Layout.astro @@ -80,10 +80,7 @@ import { LanguagePicker } from '../../components/LanguagePicker'; - + diff --git a/integration/templates/react-cra/src/App.tsx b/integration/templates/react-cra/src/App.tsx index 393eaf66314..38197953f08 100644 --- a/integration/templates/react-cra/src/App.tsx +++ b/integration/templates/react-cra/src/App.tsx @@ -10,7 +10,7 @@ function App() { Signed In - + ); } diff --git a/integration/templates/react-vite/src/App.tsx b/integration/templates/react-vite/src/App.tsx index fd040382878..3c7aabd5906 100644 --- a/integration/templates/react-vite/src/App.tsx +++ b/integration/templates/react-vite/src/App.tsx @@ -6,7 +6,7 @@ import { ClientId } from './client-id'; function App() { return (
- + Loading organization switcher} /> SignedOut diff --git a/packages/astro/src/stores/external.ts b/packages/astro/src/stores/external.ts index e454b03dfba..3903ea9f0fb 100644 --- a/packages/astro/src/stores/external.ts +++ b/packages/astro/src/stores/external.ts @@ -70,7 +70,7 @@ export const $organizationStore = computed([$authStore], auth => auth.organizati * It is a nanostore, for instructions on how to use nanostores please review the [documentation](https://github.com/nanostores/nanostores) * * @example - * $clientStore.subscribe((client) => console.log(client.activeSessions)) + * $clientStore.subscribe((client) => console.log(client?.signedInSessions?.length)) */ export const $clientStore = computed([$csrState], csr => csr.client); diff --git a/packages/clerk-js/src/core/__tests__/clerk.test.ts b/packages/clerk-js/src/core/__tests__/clerk.test.ts index 1cccffbbcd8..63405363870 100644 --- a/packages/clerk-js/src/core/__tests__/clerk.test.ts +++ b/packages/clerk-js/src/core/__tests__/clerk.test.ts @@ -246,100 +246,6 @@ describe('Clerk singleton', () => { await sut.setActive({ session: mockSession as any as ActiveSessionResource }); }); - it('calls __unstable__onAfterSetActive after beforeEmit and session.touch', async () => { - const beforeEmitMock = vi.fn(); - mockSession.touch.mockReturnValueOnce(Promise.resolve()); - mockClientFetch.mockReturnValue(Promise.resolve({ signedInSessions: [mockSession] })); - - (window as any).__unstable__onAfterSetActive = () => { - expect(mockSession.touch).toHaveBeenCalled(); - expect(beforeEmitMock).toHaveBeenCalled(); - }; - - const sut = new Clerk(productionPublishableKey); - await sut.load(); - await sut.setActive({ session: mockSession as any as ActiveSessionResource, beforeEmit: beforeEmitMock }); - }); - - // TODO: @dimkl include set transitive state - it('calls session.touch -> set cookie -> before emit with touched session on session switch', async () => { - const mockSession2 = { - id: '2', - remove: vi.fn(), - status: 'active', - user: {}, - touch: vi.fn(), - getToken: vi.fn(), - }; - mockClientFetch.mockReturnValue( - Promise.resolve({ - signedInSessions: [mockSession, mockSession2], - }), - ); - - const sut = new Clerk(productionPublishableKey); - await sut.load(); - - const executionOrder: string[] = []; - mockSession2.touch.mockImplementationOnce(() => { - sut.session = mockSession2 as any; - executionOrder.push('session.touch'); - return Promise.resolve(); - }); - mockSession2.getToken.mockImplementation(() => { - executionOrder.push('set cookie'); - return 'mocked-token-2'; - }); - const beforeEmitMock = vi.fn().mockImplementationOnce(() => { - executionOrder.push('before emit'); - return Promise.resolve(); - }); - - await sut.setActive({ session: mockSession2 as any as ActiveSessionResource, beforeEmit: beforeEmitMock }); - - await waitFor(() => { - expect(executionOrder).toEqual(['session.touch', 'set cookie', 'before emit']); - expect(mockSession2.touch).toHaveBeenCalled(); - expect(mockSession2.getToken).toHaveBeenCalled(); - expect(beforeEmitMock).toHaveBeenCalledWith(mockSession2); - expect(sut.session).toMatchObject(mockSession2); - }); - }); - - // TODO: @dimkl include set transitive state - it('calls with lastActiveOrganizationId session.touch -> set cookie -> before emit -> set accessors with touched session on organization switch', async () => { - mockClientFetch.mockReturnValue(Promise.resolve({ signedInSessions: [mockSession] })); - const sut = new Clerk(productionPublishableKey); - await sut.load(); - - const executionOrder: string[] = []; - mockSession.touch.mockImplementationOnce(() => { - sut.session = mockSession as any; - executionOrder.push('session.touch'); - return Promise.resolve(); - }); - mockSession.getToken.mockImplementation(() => { - executionOrder.push('set cookie'); - return 'mocked-token'; - }); - - const beforeEmitMock = vi.fn().mockImplementationOnce(() => { - executionOrder.push('before emit'); - return Promise.resolve(); - }); - - await sut.setActive({ organization: { id: 'org_id' } as Organization, beforeEmit: beforeEmitMock }); - - await waitFor(() => { - expect(executionOrder).toEqual(['session.touch', 'set cookie', 'before emit']); - expect(mockSession.touch).toHaveBeenCalled(); - expect(mockSession.getToken).toHaveBeenCalled(); - expect((mockSession as any as ActiveSessionResource)?.lastActiveOrganizationId).toEqual('org_id'); - expect(beforeEmitMock).toHaveBeenCalledWith(mockSession); - expect(sut.session).toMatchObject(mockSession); - }); - }); - it('sets active organization by slug', async () => { const mockSession2 = { id: '1', @@ -465,24 +371,16 @@ describe('Clerk singleton', () => { const sut = new Clerk(productionPublishableKey); await sut.load({ standardBrowser: false }); - const executionOrder: string[] = []; mockSession.touch.mockImplementationOnce(() => { sut.session = mockSession as any; - executionOrder.push('session.touch'); - return Promise.resolve(); - }); - const beforeEmitMock = vi.fn().mockImplementationOnce(() => { - executionOrder.push('before emit'); return Promise.resolve(); }); - await sut.setActive({ organization: { id: 'org_id' } as Organization, beforeEmit: beforeEmitMock }); + await sut.setActive({ organization: { id: 'org_id' } as Organization }); - expect(executionOrder).toEqual(['session.touch', 'before emit']); expect(mockSession.touch).toHaveBeenCalled(); expect((mockSession as any as ActiveSessionResource)?.lastActiveOrganizationId).toEqual('org_id'); expect(mockSession.getToken).toHaveBeenCalled(); - expect(beforeEmitMock).toHaveBeenCalledWith(mockSession); expect(sut.session).toMatchObject(mockSession); }); }); diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 63c7e8690e6..1742c7c4598 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -1,6 +1,5 @@ import { inBrowser as inClientSide, isValidBrowserOnline } from '@clerk/shared/browser'; import { clerkEvents, createClerkEventBus } from '@clerk/shared/clerkEventBus'; -import { deprecated } from '@clerk/shared/deprecated'; import { ClerkRuntimeError, EmailLinkError, @@ -9,7 +8,6 @@ import { isClerkAPIResponseError, isClerkRuntimeError, } from '@clerk/shared/error'; -import { assertNoLegacyProp } from '@clerk/shared/internal/clerk-js/assertNoLegacyProp'; import { disabledAllAPIKeysFeatures, disabledAllBillingFeatures, @@ -496,8 +494,6 @@ export class Clerk implements ClerkInterface { this.#emit(); }); - assertNoLegacyProp(this.#options); - if (this.#options.sdkMetadata) { Clerk.sdkMetadata = this.#options.sdkMetadata; } @@ -1300,7 +1296,7 @@ export class Clerk implements ClerkInterface { * `setActive` can be used to set the active session and/or organization. */ public setActive = async (params: SetActiveParams): Promise => { - const { organization, beforeEmit, redirectUrl, navigate: setActiveNavigate } = params; + const { organization, redirectUrl, navigate: setActiveNavigate } = params; let { session } = params; this.__internal_setActiveInProgress = true; debugLogger.debug( @@ -1405,29 +1401,18 @@ export class Clerk implements ClerkInterface { eventBus.emit(events.TokenUpdate, { token: null }); } - //2. If there's a beforeEmit, typically we're navigating. Emit the session as - // undefined, then wait for beforeEmit to complete before emitting the new session. + //2. When navigation is required we emit the session as undefined, + // then wait for navigation to finish before emitting the new session. // When undefined, neither SignedIn nor SignedOut renders, which avoids flickers or // automatic reloading when reloading shouldn't be happening. const tracker = createBeforeUnloadTracker(this.#options.standardBrowser); - if (beforeEmit) { - deprecated( - 'Clerk.setActive({beforeEmit})', - 'Use the `redirectUrl` property instead. Example `Clerk.setActive({redirectUrl:"/"})`', - ); - await tracker.track(async () => { - this.#setTransitiveState(); - await beforeEmit(newSession); - }); - } - const taskUrl = newSession?.status === 'pending' && newSession?.currentTask && this.#options.taskUrls?.[newSession?.currentTask.key]; - if (!beforeEmit && (redirectUrl || taskUrl || setActiveNavigate)) { + if (redirectUrl || taskUrl || setActiveNavigate) { await tracker.track(async () => { if (!this.client) { // Typescript is not happy because since thinks this.client might have changed to undefined because the function is asynchronous. diff --git a/packages/clerk-js/src/core/resources/Client.ts b/packages/clerk-js/src/core/resources/Client.ts index 3371b8435c0..f246d7efbad 100644 --- a/packages/clerk-js/src/core/resources/Client.ts +++ b/packages/clerk-js/src/core/resources/Client.ts @@ -1,5 +1,4 @@ import type { - ActiveSessionResource, ClientJSON, ClientJSONSnapshot, ClientResource, @@ -57,13 +56,6 @@ export class Client extends BaseResource implements ClientResource { return this.signIn; } - /** - * @deprecated Use `signedInSessions()` instead. - */ - get activeSessions(): ActiveSessionResource[] { - return this.sessions.filter(s => s.status === 'active') as ActiveSessionResource[]; - } - get signedInSessions(): SignedInSessionResource[] { return this.sessions.filter(s => s.status === 'active' || s.status === 'pending') as SignedInSessionResource[]; } diff --git a/packages/localizations/README.md b/packages/localizations/README.md index 560fdb73126..dcd5092fc6c 100644 --- a/packages/localizations/README.md +++ b/packages/localizations/README.md @@ -66,6 +66,7 @@ We're open to all community contributions! If you'd like to contribute in any wa 1. Open the [`localizations/src/en-US.ts`](https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts) file and add your new key to the object. `en-US` is the default language. If you feel comfortable adding your message in another language than English, feel free to also edit other files. 1. Use the new localization key inside the component. There are two ways: + - The string is inside a component like ``: ```diff diff --git a/packages/nextjs/src/server/clerkMiddleware.ts b/packages/nextjs/src/server/clerkMiddleware.ts index 971a8705130..671c034af63 100644 --- a/packages/nextjs/src/server/clerkMiddleware.ts +++ b/packages/nextjs/src/server/clerkMiddleware.ts @@ -64,11 +64,6 @@ export type ClerkMiddlewareSessionAuthObject = (SignedInAuthObject | SignedOutAu redirectToSignUp: RedirectFun; }; -/** - * @deprecated Use `ClerkMiddlewareSessionAuthObject` instead. - */ -export type ClerkMiddlewareAuthObject = ClerkMiddlewareSessionAuthObject; - export type ClerkMiddlewareAuth = AuthFn; type ClerkMiddlewareHandler = ( diff --git a/packages/nextjs/src/server/index.ts b/packages/nextjs/src/server/index.ts index a2bdebbf685..da0d281273e 100644 --- a/packages/nextjs/src/server/index.ts +++ b/packages/nextjs/src/server/index.ts @@ -44,12 +44,7 @@ export { buildClerkProps } from './buildClerkProps'; export { auth } from '../app-router/server/auth'; export { currentUser } from '../app-router/server/currentUser'; export { clerkMiddleware } from './clerkMiddleware'; -export type { - ClerkMiddlewareAuth, - ClerkMiddlewareSessionAuthObject, - ClerkMiddlewareAuthObject, - ClerkMiddlewareOptions, -} from './clerkMiddleware'; +export type { ClerkMiddlewareAuth, ClerkMiddlewareSessionAuthObject, ClerkMiddlewareOptions } from './clerkMiddleware'; /** * Re-export resource types from @clerk/backend diff --git a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts index 0f9bfb8c974..5e758db5cdb 100644 --- a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts +++ b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts @@ -24,8 +24,6 @@ export const mergeNextClerkPropsWithEnv = (props: Omit { authorizedParties: [], signInUrl: '', signUpUrl: '', - afterSignInUrl: '', - afterSignUpUrl: '', secretKey: 'sk_test_...', publishableKey: 'pk_test_...', } as unknown as ReturnType); @@ -77,8 +75,6 @@ describe('clerkMiddleware', () => { authorizedParties: [], signInUrl: '', signUpUrl: '', - afterSignInUrl: '', - afterSignUpUrl: '', acceptsToken: 'any', }); @@ -107,8 +103,6 @@ describe('clerkMiddleware', () => { authorizedParties: ['https://example.com'], signInUrl: '/sign-in', signUpUrl: '/sign-up', - afterSignInUrl: '/dashboard', - afterSignUpUrl: '/welcome', }; const middleware = clerkMiddleware(options); diff --git a/packages/react-router/src/server/clerkMiddleware.ts b/packages/react-router/src/server/clerkMiddleware.ts index 4f059d28c18..e84dc1d1cca 100644 --- a/packages/react-router/src/server/clerkMiddleware.ts +++ b/packages/react-router/src/server/clerkMiddleware.ts @@ -50,8 +50,6 @@ export const clerkMiddleware = (options?: ClerkMiddlewareOptions): MiddlewareFun authorizedParties, signInUrl, signUpUrl, - afterSignInUrl, - afterSignUpUrl, organizationSyncOptions, } = loadedOptions; @@ -69,8 +67,6 @@ export const clerkMiddleware = (options?: ClerkMiddlewareOptions): MiddlewareFun organizationSyncOptions, signInUrl, signUpUrl, - afterSignInUrl, - afterSignUpUrl, acceptsToken: 'any', }); diff --git a/packages/react-router/src/server/legacyAuthenticateRequest.ts b/packages/react-router/src/server/legacyAuthenticateRequest.ts index 7b2d704cee8..7096059372b 100644 --- a/packages/react-router/src/server/legacyAuthenticateRequest.ts +++ b/packages/react-router/src/server/legacyAuthenticateRequest.ts @@ -14,7 +14,7 @@ export async function legacyAuthenticateRequest( const { audience, authorizedParties } = opts; const { apiUrl, secretKey, jwtKey, proxyUrl, isSatellite, domain, publishableKey, machineSecretKey } = opts; - const { signInUrl, signUpUrl, afterSignInUrl, afterSignUpUrl } = opts; + const { signInUrl, signUpUrl } = opts; const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), { apiUrl, @@ -29,8 +29,6 @@ export async function legacyAuthenticateRequest( authorizedParties, signInUrl, signUpUrl, - afterSignInUrl, - afterSignUpUrl, }); const locationHeader = requestState.headers.get(constants.Headers.Location); diff --git a/packages/react-router/src/server/loadOptions.ts b/packages/react-router/src/server/loadOptions.ts index 6c64a7face8..2ae4dab747f 100644 --- a/packages/react-router/src/server/loadOptions.ts +++ b/packages/react-router/src/server/loadOptions.ts @@ -47,8 +47,6 @@ export const loadOptions = (args: DataFunctionArgs, overrides: ClerkMiddlewareOp overrides.signInFallbackRedirectUrl || getPublicEnvVariables(context).signInFallbackRedirectUrl; const signUpFallbackRedirectUrl = overrides.signUpFallbackRedirectUrl || getPublicEnvVariables(context).signUpFallbackRedirectUrl; - const afterSignInUrl = overrides.afterSignInUrl || getPublicEnvVariables(context).afterSignInUrl; - const afterSignUpUrl = overrides.afterSignUpUrl || getPublicEnvVariables(context).afterSignUpUrl; let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && isProxyUrlRelative(relativeOrAbsoluteProxyUrl)) { @@ -80,8 +78,6 @@ export const loadOptions = (args: DataFunctionArgs, overrides: ClerkMiddlewareOp proxyUrl, signInUrl, signUpUrl, - afterSignInUrl, - afterSignUpUrl, signInForceRedirectUrl, signUpForceRedirectUrl, signInFallbackRedirectUrl, diff --git a/packages/react-router/src/server/types.ts b/packages/react-router/src/server/types.ts index 650dd0d1cf2..6fb34a48905 100644 --- a/packages/react-router/src/server/types.ts +++ b/packages/react-router/src/server/types.ts @@ -6,7 +6,6 @@ import type { SignedOutAuthObject, } from '@clerk/backend/internal'; import type { - LegacyRedirectProps, MultiDomainAndOrProxy, SignInFallbackRedirectUrl, SignInForceRedirectUrl, @@ -47,8 +46,7 @@ export type ClerkMiddlewareOptions = { SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & - SignUpFallbackRedirectUrl & - LegacyRedirectProps; + SignUpFallbackRedirectUrl; export type RootAuthLoaderOptions = ClerkMiddlewareOptions & { /** @@ -69,8 +67,7 @@ export type RequestStateWithRedirectUrls = RequestState & SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & - SignUpFallbackRedirectUrl & - LegacyRedirectProps; + SignUpFallbackRedirectUrl; export type RootAuthLoaderCallback = ( args: LoaderFunctionArgsWithAuth, diff --git a/packages/react-router/src/server/utils.ts b/packages/react-router/src/server/utils.ts index 4d770a5fa22..1b0bd9a9fe7 100644 --- a/packages/react-router/src/server/utils.ts +++ b/packages/react-router/src/server/utils.ts @@ -87,8 +87,6 @@ export function getResponseClerkState(requestState: RequestStateWithRedirectUrls __isSatellite: requestState.isSatellite, __signInUrl: requestState.signInUrl, __signUpUrl: requestState.signUpUrl, - __afterSignInUrl: requestState.afterSignInUrl, - __afterSignUpUrl: requestState.afterSignUpUrl, __signInForceRedirectUrl: requestState.signInForceRedirectUrl, __signUpForceRedirectUrl: requestState.signUpForceRedirectUrl, __signInFallbackRedirectUrl: requestState.signInFallbackRedirectUrl, diff --git a/packages/react/src/components/controlComponents.tsx b/packages/react/src/components/controlComponents.tsx index 647598f622e..bdeefbfa05a 100644 --- a/packages/react/src/components/controlComponents.tsx +++ b/packages/react/src/components/controlComponents.tsx @@ -146,10 +146,7 @@ export const Protect = ({ children, fallback, treatPendingAsSignedOut, ...restAu export const RedirectToSignIn = withClerk(({ clerk, ...props }: WithClerkProp) => { const { client, session } = clerk; - const hasSignedInSessions = client.signedInSessions - ? client.signedInSessions.length > 0 - : // Compat for clerk-js<5.54.0 (which was released with the `signedInSessions` property) - client.activeSessions && client.activeSessions.length > 0; + const hasSignedInSessions = (client.signedInSessions?.length ?? 0) > 0; React.useEffect(() => { if (session === null && hasSignedInSessions) { diff --git a/packages/shared/src/internal/clerk-js/__tests__/redirectUrls.test.ts b/packages/shared/src/internal/clerk-js/__tests__/redirectUrls.test.ts index 8fb89f1665a..a40d0e09c6d 100644 --- a/packages/shared/src/internal/clerk-js/__tests__/redirectUrls.test.ts +++ b/packages/shared/src/internal/clerk-js/__tests__/redirectUrls.test.ts @@ -77,64 +77,6 @@ describe('redirectUrls', () => { }); describe('get redirect urls', () => { - // TODO: v6 - remove this test - it('prioritizes new props over legacy props ', () => { - const redirectUrls = new RedirectUrls({ - signInFallbackRedirectUrl: 'sign-in-fallback-redirect-url', - signUpFallbackRedirectUrl: 'sign-up-fallback-redirect-url', - afterSignInUrl: 'after-sign-in-url', - afterSignUpUrl: 'after-sign-up-url', - }); - - expect(redirectUrls.getAfterSignInUrl()).toBe(`${mockWindowLocation.href}sign-in-fallback-redirect-url`); - expect(redirectUrls.getAfterSignUpUrl()).toBe(`${mockWindowLocation.href}sign-up-fallback-redirect-url`); - }); - - // TODO: v6 - remove this test - it('falls back to legacy props if no new props are found', () => { - const redirectUrls = new RedirectUrls({ - signUpFallbackRedirectUrl: 'sign-up-fallback-redirect-url', - afterSignInUrl: 'after-sign-in-url', - afterSignUpUrl: 'after-sign-up-url', - }); - - expect(redirectUrls.getAfterSignInUrl()).toBe(`${mockWindowLocation.href}after-sign-in-url`); - expect(redirectUrls.getAfterSignUpUrl()).toBe(`${mockWindowLocation.href}sign-up-fallback-redirect-url`); - }); - - // TODO: v6 - remove this test - it('falls back to legacy redirect prop if no new props are found', () => { - const redirectUrls = new RedirectUrls( - { - signUpFallbackRedirectUrl: 'sign-up-fallback-redirect-url', - }, - { - redirectUrl: 'redirect-url', - }, - ); - - expect(redirectUrls.getAfterSignInUrl()).toBe(`${mockWindowLocation.href}redirect-url`); - expect(redirectUrls.getAfterSignUpUrl()).toBe(`${mockWindowLocation.href}sign-up-fallback-redirect-url`); - }); - - // TODO: v6 - remove this test - it('falls back to legacy redirect prop if no new props are found', () => { - const redirectUrls = new RedirectUrls( - { - signUpForceRedirectUrl: 'sign-up-fallback-redirect-url', - }, - { - redirectUrl: 'redirect-url', - }, - { - redirect_url: 'redirect-url-params', - }, - ); - - expect(redirectUrls.getAfterSignInUrl()).toBe(`${mockWindowLocation.href}redirect-url-params`); - expect(redirectUrls.getAfterSignUpUrl()).toBe(`${mockWindowLocation.href}sign-up-fallback-redirect-url`); - }); - it('prioritizes force urls among other urls in the same group', () => { const redirectUrls = new RedirectUrls({ signInForceRedirectUrl: 'sign-in-force-redirect-url', diff --git a/packages/shared/src/internal/clerk-js/assertNoLegacyProp.ts b/packages/shared/src/internal/clerk-js/assertNoLegacyProp.ts deleted file mode 100644 index 89f6a5a58d3..00000000000 --- a/packages/shared/src/internal/clerk-js/assertNoLegacyProp.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { logger } from '../../logger'; - -export function assertNoLegacyProp(props: Record) { - const legacyProps = ['redirectUrl', 'afterSignInUrl', 'afterSignUpUrl', 'after_sign_in_url', 'after_sign_up_url']; - const legacyProp = Object.keys(props).find(key => legacyProps.includes(key)); - - if (legacyProp && props[legacyProp]) { - logger.warnOnce( - `Clerk: The prop "${legacyProp}" is deprecated and should be replaced with the new "fallbackRedirectUrl" or "forceRedirectUrl" props instead. Learn more: https://clerk.com/docs/guides/custom-redirects#redirect-url-props`, - ); - } -} - -export function warnForNewPropShadowingLegacyProp( - newKey: string | undefined, - newValue: string | undefined | null, - legacyKey: string | undefined, - legacyValue: string | undefined | null, -) { - if (newValue && legacyValue) { - logger.warnOnce( - `Clerk: The "${newKey}" prop ("${newValue}") has priority over the legacy "${legacyKey}" (or "redirectUrl") ("${legacyValue}"), which will be completely ignored in this case. "${legacyKey}" (or "redirectUrl" prop) should be replaced with the new "fallbackRedirectUrl" or "forceRedirectUrl" props instead. Learn more: https://clerk.com/docs/guides/custom-redirects#redirect-url-props`, - ); - } -} diff --git a/packages/shared/src/internal/clerk-js/redirectUrls.ts b/packages/shared/src/internal/clerk-js/redirectUrls.ts index 055e6984ec1..1d2a8797da5 100644 --- a/packages/shared/src/internal/clerk-js/redirectUrls.ts +++ b/packages/shared/src/internal/clerk-js/redirectUrls.ts @@ -1,19 +1,16 @@ import { applyFunctionToObj, filterProps, removeUndefined } from '../../object'; import type { ClerkOptions, RedirectOptions } from '../../types'; import { camelToSnake } from '../../underscore'; -import { assertNoLegacyProp, warnForNewPropShadowingLegacyProp } from './assertNoLegacyProp'; import { isAllowedRedirect, relativeToAbsoluteUrl } from './url'; type ComponentMode = 'modal' | 'mounted'; export class RedirectUrls { - private static keys: (keyof RedirectOptions)[] = [ + private static keys: (keyof RedirectOptions | 'redirectUrl')[] = [ 'signInForceRedirectUrl', 'signInFallbackRedirectUrl', 'signUpForceRedirectUrl', 'signUpFallbackRedirectUrl', - 'afterSignInUrl', - 'afterSignUpUrl', 'redirectUrl', ]; @@ -77,19 +74,13 @@ export class RedirectUrls { this.fromSearchParams.signInFallbackRedirectUrl || this.fromProps.signInFallbackRedirectUrl || this.fromOptions.signInFallbackRedirectUrl; - const afterSignInUrl = - this.fromSearchParams.afterSignInUrl || this.fromProps.afterSignInUrl || this.fromOptions.afterSignInUrl; - const afterSignUpUrl = - this.fromSearchParams.afterSignUpUrl || this.fromProps.afterSignUpUrl || this.fromOptions.afterSignUpUrl; - const redirectUrl = this.fromSearchParams.redirectUrl || this.fromProps.redirectUrl || this.fromOptions.redirectUrl; + const redirectUrl = this.fromSearchParams.redirectUrl; - const res: RedirectOptions = { + const res: RedirectOptions & { redirectUrl?: string | null } = { signUpForceRedirectUrl, signUpFallbackRedirectUrl, signInFallbackRedirectUrl, signInForceRedirectUrl, - afterSignInUrl, - afterSignUpUrl, redirectUrl, }; @@ -107,37 +98,14 @@ export class RedirectUrls { #getRedirectUrl(prefix: 'signIn' | 'signUp') { const forceKey = `${prefix}ForceRedirectUrl` as const; const fallbackKey = `${prefix}FallbackRedirectUrl` as const; - let newKeyInUse: string | undefined; - - const legacyPropKey = `after${prefix[0].toUpperCase()}${prefix.slice(1)}Url` as 'afterSignInUrl' | 'afterSignUpUrl'; let result; // Prioritize forceRedirectUrl result = this.fromSearchParams[forceKey] || this.fromProps[forceKey] || this.fromOptions[forceKey]; - if (result) { - newKeyInUse = forceKey; - } // Try to get redirect_url, only allowed as a search param result ||= this.fromSearchParams.redirectUrl; - if (result) { - newKeyInUse = 'redirectUrl'; - } // Otherwise, fallback to fallbackRedirectUrl result ||= this.fromSearchParams[fallbackKey] || this.fromProps[fallbackKey] || this.fromOptions[fallbackKey]; - if (result) { - newKeyInUse = fallbackKey; - } - - // TODO: v6 - // Remove the compatibility layer for afterSignInUrl and afterSignUpUrl - const legacyValue = - this.fromSearchParams[legacyPropKey] || - this.fromProps[legacyPropKey] || - this.fromProps.redirectUrl || - this.fromOptions[legacyPropKey]; - - warnForNewPropShadowingLegacyProp(newKeyInUse, result, legacyPropKey, legacyValue); - result ||= legacyValue; if (!result && this.mode === 'modal') { return window.location.href; @@ -147,8 +115,7 @@ export class RedirectUrls { } #parse(obj: unknown) { - assertNoLegacyProp(obj as any); - const res = {} as RedirectOptions; + const res = {} as RedirectOptions & { redirectUrl?: string | null }; RedirectUrls.keys.forEach(key => { // @ts-expect-error res[key] = obj[key]; @@ -159,7 +126,6 @@ export class RedirectUrls { } #parseSearchParams(obj: any) { - assertNoLegacyProp(obj); const res = {} as typeof this.fromSearchParams; RedirectUrls.keys.forEach(key => { if (obj instanceof URLSearchParams) { diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index c2f385cef37..2d4798aefd1 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -46,7 +46,6 @@ import type { ClerkPaginationParams } from './pagination'; import type { AfterMultiSessionSingleSignOutUrl, AfterSignOutUrl, - LegacyRedirectProps, NewSubscriptionRedirectUrl, RedirectOptions, RedirectUrlProp, @@ -140,7 +139,6 @@ export type SDKMetadata = { export type ListenerCallback = (emission: Resources) => void; export type UnsubscribeCallback = () => void; -export type BeforeEmitCallback = (session?: SignedInSessionResource | null) => void | Promise; export type SetActiveNavigate = ({ session }: { session: SessionResource }) => void | Promise; export type SignOutCallback = () => void | Promise; @@ -958,8 +956,7 @@ export type HandleOAuthCallbackParams = TransferableOption & SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & - SignUpFallbackRedirectUrl & - LegacyRedirectProps & { + SignUpFallbackRedirectUrl & { /** * Full URL or path where the SignIn component is mounted. */ @@ -1029,28 +1026,12 @@ type ClerkOptionsNavigation = routerDebug?: boolean; }; -type ClerkOptionsLegacyRedirectProps = { - /** - * @deprecated Use `signInFallbackRedirectUrl` or `signInForceRedirectUrl` instead. - */ - afterSignInUrl?: string | null; - /** - * @deprecated Use `signUpFallbackRedirectUrl` or `signUpForceRedirectUrl` instead. - */ - afterSignUpUrl?: string | null; - /** - * @deprecated Use `signInFallbackRedirectUrl`, `signInForceRedirectUrl`, `signUpFallbackRedirectUrl`, or `signUpForceRedirectUrl` instead. - */ - redirectUrl?: string | null; -}; - export type ClerkOptions = ClerkOptionsNavigation & SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & NewSubscriptionRedirectUrl & - ClerkOptionsLegacyRedirectProps & AfterSignOutUrl & AfterMultiSessionSingleSignOutUrl & { /** @@ -1296,13 +1277,6 @@ export type SetActiveParams = { */ organization?: OrganizationResource | string | null; - /** - * @deprecated Use `redirectUrl` instead. - * - * Callback run just before the active session and/or organization is set to the passed object. Can be used to set up for pre-navigation actions. - */ - beforeEmit?: BeforeEmitCallback; - /** * The full URL or path to redirect to just before the session and/or organization is set. */ @@ -1405,7 +1379,6 @@ export type SignInProps = RoutingOptions & { } & TransferableOption & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - LegacyRedirectProps & AfterSignOutUrl; export interface TransferableOption { @@ -1552,7 +1525,6 @@ export type SignUpProps = RoutingOptions & { oidcPrompt?: string; } & SignInFallbackRedirectUrl & SignInForceRedirectUrl & - LegacyRedirectProps & AfterSignOutUrl; export type SignUpModalProps = WithoutRouting; @@ -1664,12 +1636,6 @@ export type CreateOrganizationProps = RoutingOptions & { * prop of ClerkProvider (if one is provided) */ appearance?: CreateOrganizationTheme; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export type CreateOrganizationModalProps = WithoutRouting; @@ -1705,19 +1671,6 @@ export type UserButtonProps = UserButtonProfileMode & { */ __experimental_asStandalone?: boolean | ((opened: boolean) => void); - /** - * Full URL or path to navigate to after sign out is complete - * - * @deprecated Configure `afterSignOutUrl` as a global configuration, either in `` or in `await Clerk.load()`. - */ - afterSignOutUrl?: string; - /** - * Full URL or path to navigate to after signing out the current user is complete. - * This option applies to multi-session applications. - * - * @deprecated Configure `afterMultiSessionSingleSignOutUrl` as a global configuration, either in `` or in `await Clerk.load()`. - */ - afterMultiSessionSingleSignOutUrl?: string; /** * Full URL or path to navigate to on "Add another account" action. * Multi-session mode only. @@ -1792,14 +1745,6 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & * @default true */ hidePersonal?: boolean; - /** - * Full URL or path to navigate to after a successful organization switch. - * - * @default undefined - * - * @deprecated Use `afterSelectOrganizationUrl` or `afterSelectPersonalUrl`. - */ - afterSwitchOrganizationUrl?: string; /** * Full URL or path to navigate to after creating a new organization. * @@ -1837,12 +1782,6 @@ export type OrganizationSwitcherProps = CreateOrganizationMode & * the number of max allowed members is equal to 1 */ skipInvitationScreen?: boolean; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; /** * Customisation options to fully match the Clerk components to your own brand. * These options serve as overrides and will be merged with the global `appearance` @@ -1903,12 +1842,6 @@ export type OrganizationListProps = { * @default undefined` */ afterSelectPersonalUrl?: ((user: UserResource) => string) | LooseExtractedParams>; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export type WaitlistProps = { diff --git a/packages/shared/src/types/client.ts b/packages/shared/src/types/client.ts index 1a8585cfc39..51757fb39ee 100644 --- a/packages/shared/src/types/client.ts +++ b/packages/shared/src/types/client.ts @@ -1,6 +1,6 @@ import type { LastAuthenticationStrategy } from './json'; import type { ClerkResource } from './resource'; -import type { ActiveSessionResource, SessionResource, SignedInSessionResource } from './session'; +import type { SessionResource, SignedInSessionResource } from './session'; import type { SignInResource } from './signIn'; import type { SignUpResource } from './signUp'; import type { ClientJSONSnapshot } from './snapshots'; @@ -26,8 +26,4 @@ export interface ClientResource extends ClerkResource { updatedAt: Date | null; __internal_sendCaptchaToken: (params: unknown) => Promise; __internal_toSnapshot: () => ClientJSONSnapshot; - /** - * @deprecated Use `signedInSessions` instead. - */ - activeSessions: ActiveSessionResource[]; } diff --git a/packages/shared/src/types/redirects.ts b/packages/shared/src/types/redirects.ts index e77b5236b5f..478688bacae 100644 --- a/packages/shared/src/types/redirects.ts +++ b/packages/shared/src/types/redirects.ts @@ -15,24 +15,6 @@ export type AfterMultiSessionSingleSignOutUrl = { afterMultiSessionSingleSignOutUrl?: string | null; }; -/** - * @deprecated This will be removed in a future release. - */ -export type LegacyRedirectProps = { - /** - * @deprecated Use `fallbackRedirectUrl` or `forceRedirectUrl` instead. - */ - afterSignInUrl?: string | null; - /** - * @deprecated Use `fallbackRedirectUrl` or `forceRedirectUrl` instead. - */ - afterSignUpUrl?: string | null; - /** - * @deprecated Use `fallbackRedirectUrl` or `forceRedirectUrl` instead. - */ - redirectUrl?: string | null; -}; - /** * Redirect URLs for different actions. * Mainly used to be used to type internal Clerk functions. @@ -41,7 +23,7 @@ export type RedirectOptions = SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - LegacyRedirectProps; + RedirectUrlProp; export type AuthenticateWithRedirectParams = { /** diff --git a/packages/tanstack-react-start/src/client/utils.ts b/packages/tanstack-react-start/src/client/utils.ts index b5da1a723f8..e237b5d8b47 100644 --- a/packages/tanstack-react-start/src/client/utils.ts +++ b/packages/tanstack-react-start/src/client/utils.ts @@ -16,8 +16,6 @@ export const pickFromClerkInitState = ( __isSatellite, __signInUrl, __signUpUrl, - __afterSignInUrl, - __afterSignUpUrl, __clerkJSUrl, __clerkUiUrl, __clerkJSVersion, @@ -37,8 +35,6 @@ export const pickFromClerkInitState = ( isSatellite: !!__isSatellite, signInUrl: __signInUrl, signUpUrl: __signUpUrl, - afterSignInUrl: __afterSignInUrl, - afterSignUpUrl: __afterSignUpUrl, clerkJSUrl: __clerkJSUrl, clerkUiUrl: __clerkUiUrl, clerkJSVersion: __clerkJSVersion, @@ -61,8 +57,6 @@ export const mergeWithPublicEnvs = (restInitState: any) => { isSatellite: restInitState.isSatellite || getPublicEnvVariables().isSatellite, signInUrl: restInitState.signInUrl || getPublicEnvVariables().signInUrl, signUpUrl: restInitState.signUpUrl || getPublicEnvVariables().signUpUrl, - afterSignInUrl: restInitState.afterSignInUrl || getPublicEnvVariables().afterSignInUrl, - afterSignUpUrl: restInitState.afterSignUpUrl || getPublicEnvVariables().afterSignUpUrl, clerkJSUrl: restInitState.clerkJSUrl || getPublicEnvVariables().clerkJsUrl, clerkUiUrl: restInitState.clerkUiUrl || getPublicEnvVariables().clerkUiUrl, clerkJSVersion: restInitState.clerkJSVersion || getPublicEnvVariables().clerkJsVersion, diff --git a/packages/tanstack-react-start/src/server/loadOptions.ts b/packages/tanstack-react-start/src/server/loadOptions.ts index 55a72e028ab..5fc6e348618 100644 --- a/packages/tanstack-react-start/src/server/loadOptions.ts +++ b/packages/tanstack-react-start/src/server/loadOptions.ts @@ -6,7 +6,6 @@ import { isHttpOrHttps, isProxyUrlRelative } from '@clerk/shared/proxy'; import { handleValueOrFn } from '@clerk/shared/utils'; import { errorThrower } from '../utils'; -import { getPublicEnvVariables } from '../utils/env'; import { commonEnvs } from './constants'; import type { LoaderOptions } from './types'; @@ -22,8 +21,6 @@ export const loadOptions = (request: ClerkRequest, overrides: LoaderOptions = {} const relativeOrAbsoluteProxyUrl = handleValueOrFn(overrides?.proxyUrl, request.clerkUrl, commonEnv.PROXY_URL); const signInUrl = overrides.signInUrl || commonEnv.SIGN_IN_URL; const signUpUrl = overrides.signUpUrl || commonEnv.SIGN_UP_URL; - const afterSignInUrl = overrides.afterSignInUrl || getPublicEnvVariables().afterSignInUrl; - const afterSignUpUrl = overrides.afterSignUpUrl || getPublicEnvVariables().afterSignUpUrl; let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && isProxyUrlRelative(relativeOrAbsoluteProxyUrl)) { @@ -60,7 +57,5 @@ export const loadOptions = (request: ClerkRequest, overrides: LoaderOptions = {} proxyUrl, signInUrl, signUpUrl, - afterSignInUrl, - afterSignUpUrl, }; }; diff --git a/packages/tanstack-react-start/src/server/types.ts b/packages/tanstack-react-start/src/server/types.ts index fee085d8b31..55963186ade 100644 --- a/packages/tanstack-react-start/src/server/types.ts +++ b/packages/tanstack-react-start/src/server/types.ts @@ -1,7 +1,6 @@ import type { VerifyTokenOptions } from '@clerk/backend'; import type { OrganizationSyncOptions } from '@clerk/backend/internal'; import type { - LegacyRedirectProps, MultiDomainAndOrProxy, SignInFallbackRedirectUrl, SignInForceRedirectUrl, @@ -22,8 +21,7 @@ export type ClerkMiddlewareOptions = { SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & - SignUpFallbackRedirectUrl & - LegacyRedirectProps; + SignUpFallbackRedirectUrl; export type LoaderOptions = ClerkMiddlewareOptions; diff --git a/packages/ui/src/components/CreateOrganization/CreateOrganizationForm.tsx b/packages/ui/src/components/CreateOrganization/CreateOrganizationForm.tsx index 3e82e63cb6c..b91a4487873 100644 --- a/packages/ui/src/components/CreateOrganization/CreateOrganizationForm.tsx +++ b/packages/ui/src/components/CreateOrganization/CreateOrganizationForm.tsx @@ -34,12 +34,6 @@ type CreateOrganizationFormProps = { headerTitle?: LocalizationKey; headerSubtitle?: LocalizationKey; }; - /** - * @deprecated - * This prop will be removed in a future version. - * Configure whether organization slug is enabled via the Clerk Dashboard under Organization Settings. - */ - hideSlug?: boolean; }; export const CreateOrganizationForm = withCardStateProvider((props: CreateOrganizationFormProps) => { @@ -69,8 +63,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani const dataChanged = !!nameField.value; const canSubmit = dataChanged; - // Environment setting takes precedence over prop - const organizationSlugEnabled = !organizationSettings.slug.disabled && !props.hideSlug; + const organizationSlugEnabled = !organizationSettings.slug.disabled; const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); diff --git a/packages/ui/src/components/CreateOrganization/CreateOrganizationPage.tsx b/packages/ui/src/components/CreateOrganization/CreateOrganizationPage.tsx index bb4c6e75720..a27e66ba87f 100644 --- a/packages/ui/src/components/CreateOrganization/CreateOrganizationPage.tsx +++ b/packages/ui/src/components/CreateOrganization/CreateOrganizationPage.tsx @@ -11,7 +11,7 @@ import { CreateOrganizationForm } from './CreateOrganizationForm'; export const CreateOrganizationPage = withCardStateProvider(() => { const { closeCreateOrganization } = useClerk(); - const { mode, navigateAfterCreateOrganization, skipInvitationScreen, hideSlug } = useCreateOrganizationContext(); + const { mode, navigateAfterCreateOrganization, skipInvitationScreen } = useCreateOrganizationContext(); const card = useCardState(); const { showDevModeNotice } = useDevMode(); @@ -33,7 +33,6 @@ export const CreateOrganizationPage = withCardStateProvider(() => { closeCreateOrganization(); } }} - hideSlug={hideSlug} /> diff --git a/packages/ui/src/components/CreateOrganization/__tests__/CreateOrganization.test.tsx b/packages/ui/src/components/CreateOrganization/__tests__/CreateOrganization.test.tsx index 0173b0837b9..2e78ae9fbdf 100644 --- a/packages/ui/src/components/CreateOrganization/__tests__/CreateOrganization.test.tsx +++ b/packages/ui/src/components/CreateOrganization/__tests__/CreateOrganization.test.tsx @@ -80,40 +80,6 @@ describe('CreateOrganization', () => { expect(getByRole('heading', { name: 'Create organization', level: 1 })).toBeInTheDocument(); }); - describe('with `hideSlug` prop', () => { - it('renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); - }); - describe('with organization slug configured on environment', () => { it('when disabled, renders component without slug field', async () => { const { wrapper, fixtures } = await createFixtures(f => { @@ -178,72 +144,6 @@ describe('CreateOrganization', () => { expect(queryByText(/Invite new members/i)).toBeInTheDocument(); }); }); - - it('when enabled and `hideSlug` prop is passed, renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(true); - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); - - it('when disabled and `hideSlug` prop is passed, renders component without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withOrganizationSlug(false); // Environment disables slug - f.withUser({ - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.createOrganization.mockReturnValue( - Promise.resolve( - getCreatedOrg({ - maxAllowedMemberships: 1, - slug: 'new-org-1722578361', - }), - ), - ); - - props.setProps({ hideSlug: true }); - const { userEvent, getByRole, queryByText, queryByLabelText, getByLabelText } = render(, { - wrapper, - }); - - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - - await userEvent.type(getByLabelText(/Name/i), 'new org'); - await userEvent.click(getByRole('button', { name: /create organization/i })); - - await waitFor(() => { - expect(queryByText(/Invite new members/i)).toBeInTheDocument(); - }); - }); }); it('skips invitation screen', async () => { diff --git a/packages/ui/src/components/OrganizationList/OrganizationListPage.tsx b/packages/ui/src/components/OrganizationList/OrganizationListPage.tsx index 0d7327fe13c..dca8ee06b36 100644 --- a/packages/ui/src/components/OrganizationList/OrganizationListPage.tsx +++ b/packages/ui/src/components/OrganizationList/OrganizationListPage.tsx @@ -85,7 +85,7 @@ export const OrganizationListPage = withCardStateProvider(() => { const OrganizationListFlows = ({ showListInitially }: { showListInitially: boolean }) => { const card = useCardState(); - const { navigateAfterCreateOrganization, skipInvitationScreen, hideSlug } = useOrganizationListContext(); + const { navigateAfterCreateOrganization, skipInvitationScreen } = useOrganizationListContext(); const [isCreateOrganizationFlow, setCreateOrganizationFlow] = useState(!showListInitially); return ( <> @@ -112,7 +112,6 @@ const OrganizationListFlows = ({ showListInitially }: { showListInitially: boole onCancel={ showListInitially && isCreateOrganizationFlow ? () => setCreateOrganizationFlow(false) : undefined } - hideSlug={hideSlug} /> diff --git a/packages/ui/src/components/OrganizationList/__tests__/OrganizationList.test.tsx b/packages/ui/src/components/OrganizationList/__tests__/OrganizationList.test.tsx index 94703a98a02..01a50b59839 100644 --- a/packages/ui/src/components/OrganizationList/__tests__/OrganizationList.test.tsx +++ b/packages/ui/src/components/OrganizationList/__tests__/OrganizationList.test.tsx @@ -277,26 +277,6 @@ describe('OrganizationList', () => { }); }); - it('displays CreateOrganization without slug field', async () => { - const { wrapper, props } = await createFixtures(f => { - f.withOrganizations(); - f.withUser({ - email_addresses: ['test@clerk.com'], - create_organization_enabled: true, - }); - }); - - props.setProps({ hideSlug: true }); - const { findByRole, getByRole, userEvent, queryByLabelText } = render(, { wrapper }); - - await waitFor(async () => - expect(await findByRole('menuitem', { name: 'Create organization' })).toBeInTheDocument(), - ); - await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); - expect(queryByLabelText(/Name/i)).toBeInTheDocument(); - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - }); - it('does not display CreateOrganization within OrganizationList when disabled', async () => { const { wrapper } = await createFixtures(f => { f.withOrganizations(); diff --git a/packages/ui/src/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx b/packages/ui/src/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx index c72e8c8340f..e2042b63f72 100644 --- a/packages/ui/src/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx +++ b/packages/ui/src/components/OrganizationSwitcher/OrganizationSwitcherPopover.tsx @@ -49,7 +49,6 @@ export const OrganizationSwitcherPopover = React.forwardRef { diff --git a/packages/ui/src/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx b/packages/ui/src/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx index 2c9095f3c45..572b960519f 100644 --- a/packages/ui/src/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx +++ b/packages/ui/src/components/OrganizationSwitcher/__tests__/OrganizationSwitcher.test.tsx @@ -304,23 +304,6 @@ describe('OrganizationSwitcher', () => { expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); }); - it('opens create organization without slug field', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withOrganizations(); - f.withUser({ - email_addresses: ['test@clerk.com'], - create_organization_enabled: true, - }); - }); - - props.setProps({ hideSlug: true }); - const { getByRole, queryByLabelText, userEvent } = render(, { wrapper }); - await userEvent.click(getByRole('button', { name: 'Open organization switcher' })); - await userEvent.click(getByRole('menuitem', { name: 'Create organization' })); - expect(fixtures.clerk.openCreateOrganization).toHaveBeenCalled(); - expect(queryByLabelText(/Slug/i)).not.toBeInTheDocument(); - }); - it('does not display create organization button if permissions not present', async () => { const { wrapper, props } = await createFixtures(f => { f.withOrganizations(); diff --git a/packages/ui/src/components/UserButton/__tests__/UserButton.test.tsx b/packages/ui/src/components/UserButton/__tests__/UserButton.test.tsx index 4cad165f8f9..cc5c292751f 100644 --- a/packages/ui/src/components/UserButton/__tests__/UserButton.test.tsx +++ b/packages/ui/src/components/UserButton/__tests__/UserButton.test.tsx @@ -82,26 +82,6 @@ describe('UserButton', () => { expect(fixtures.router.navigate).toHaveBeenCalledWith('/'); }); - it('redirects to afterSignOutUrl when "Sign out" is clicked and afterSignOutUrl prop is passed', async () => { - const { wrapper, fixtures, props } = await createFixtures(f => { - f.withUser({ - first_name: 'First', - last_name: 'Last', - username: 'username1', - email_addresses: ['test@clerk.com'], - }); - }); - - fixtures.clerk.signOut.mockImplementation(callback => callback()); - props.setProps({ afterSignOutUrl: '/after-sign-out' }); - - const { getByText, getByRole, userEvent } = render(, { wrapper }); - await userEvent.click(getByRole('button', { name: 'Open user menu' })); - await userEvent.click(getByText('Sign out')); - - expect(fixtures.router.navigate).toHaveBeenCalledWith('/after-sign-out'); - }); - it.todo('navigates to sign in url when "Add account" is clicked'); describe('Multi Session Popover', () => { diff --git a/packages/ui/src/contexts/components/CreateOrganization.ts b/packages/ui/src/contexts/components/CreateOrganization.ts index dcc87e59324..e22bcd91cc2 100644 --- a/packages/ui/src/contexts/components/CreateOrganization.ts +++ b/packages/ui/src/contexts/components/CreateOrganization.ts @@ -38,7 +38,6 @@ export const useCreateOrganizationContext = () => { return { ...ctx, skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, navigateAfterCreateOrganization, componentName, }; diff --git a/packages/ui/src/contexts/components/OrganizationList.ts b/packages/ui/src/contexts/components/OrganizationList.ts index 25248247943..189b6f22a2b 100644 --- a/packages/ui/src/contexts/components/OrganizationList.ts +++ b/packages/ui/src/contexts/components/OrganizationList.ts @@ -79,7 +79,6 @@ export const useOrganizationListContext = () => { ...ctx, afterCreateOrganizationUrl, skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, hidePersonal: organizationSettings.forceOrganizationSelection || ctx.hidePersonal || false, navigateAfterCreateOrganization, navigateAfterSelectOrganization, diff --git a/packages/ui/src/contexts/components/OrganizationSwitcher.ts b/packages/ui/src/contexts/components/OrganizationSwitcher.ts index 86629b3ff80..291848554a3 100644 --- a/packages/ui/src/contexts/components/OrganizationSwitcher.ts +++ b/packages/ui/src/contexts/components/OrganizationSwitcher.ts @@ -100,7 +100,6 @@ export const useOrganizationSwitcherContext = () => { organizationProfileMode: organizationProfileMode || 'modal', createOrganizationMode: createOrganizationMode || 'modal', skipInvitationScreen: ctx.skipInvitationScreen || false, - hideSlug: ctx.hideSlug || false, afterCreateOrganizationUrl, afterLeaveOrganizationUrl, navigateOrganizationProfile, diff --git a/packages/ui/src/contexts/components/UserButton.ts b/packages/ui/src/contexts/components/UserButton.ts index 0ac80564a0a..779ca61f3a9 100644 --- a/packages/ui/src/contexts/components/UserButton.ts +++ b/packages/ui/src/contexts/components/UserButton.ts @@ -1,4 +1,3 @@ -import { deprecatedObjectProperty } from '@clerk/shared/deprecated'; import { useClerk } from '@clerk/shared/react'; import { createContext, useContext, useMemo } from 'react'; @@ -26,22 +25,10 @@ export const useUserButtonContext = () => { const signInUrl = ctx.signInUrl || options.signInUrl || displayConfig.signInUrl; const userProfileUrl = ctx.userProfileUrl || displayConfig.userProfileUrl; - if (ctx.afterSignOutUrl) { - deprecatedObjectProperty(ctx, 'afterSignOutUrl', `Move 'afterSignOutUrl' to '`); - } - - const afterSignOutUrl = ctx.afterSignOutUrl || clerk.buildAfterSignOutUrl(); + const afterSignOutUrl = clerk.buildAfterSignOutUrl(); const navigateAfterSignOut = () => navigate(afterSignOutUrl); - if (ctx.afterSignOutUrl) { - deprecatedObjectProperty( - ctx, - 'afterMultiSessionSingleSignOutUrl', - `Move 'afterMultiSessionSingleSignOutUrl' to '`, - ); - } - const afterMultiSessionSingleSignOutUrl = - ctx.afterMultiSessionSingleSignOutUrl || clerk.buildAfterMultiSessionSingleSignOutUrl(); + const afterMultiSessionSingleSignOutUrl = clerk.buildAfterMultiSessionSingleSignOutUrl(); const navigateAfterMultiSessionSingleSignOut = () => clerk.redirectWithAuth(afterMultiSessionSingleSignOutUrl); const afterSwitchSessionUrl = ctx.afterSwitchSessionUrl || displayConfig.afterSwitchSessionUrl; diff --git a/playground/app-router/src/app/protected/page.tsx b/playground/app-router/src/app/protected/page.tsx index ff3a74f16fd..b93598f1d56 100644 --- a/playground/app-router/src/app/protected/page.tsx +++ b/playground/app-router/src/app/protected/page.tsx @@ -23,7 +23,6 @@ export default async function Page() {

Clerk loaded

- server content diff --git a/playground/vite-react-ts/src/App.tsx b/playground/vite-react-ts/src/App.tsx index fd6576055ac..14bea78dc23 100644 --- a/playground/vite-react-ts/src/App.tsx +++ b/playground/vite-react-ts/src/App.tsx @@ -37,7 +37,7 @@ function NavBar() { User Profile - + ); } From 58cb3e4e09da4d7795a3c5f347342fbe76a3bc12 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 19 Nov 2025 13:57:15 -0600 Subject: [PATCH 2/3] wip --- packages/localizations/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/localizations/README.md b/packages/localizations/README.md index dcd5092fc6c..560fdb73126 100644 --- a/packages/localizations/README.md +++ b/packages/localizations/README.md @@ -66,7 +66,6 @@ We're open to all community contributions! If you'd like to contribute in any wa 1. Open the [`localizations/src/en-US.ts`](https://github.com/clerk/javascript/blob/main/packages/localizations/src/en-US.ts) file and add your new key to the object. `en-US` is the default language. If you feel comfortable adding your message in another language than English, feel free to also edit other files. 1. Use the new localization key inside the component. There are two ways: - - The string is inside a component like ``: ```diff From fcbd5bb6492c6ae09963d7b04f35e766333f70d2 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 19 Nov 2025 19:46:53 -0600 Subject: [PATCH 3/3] @clerk/tanstack-react-start minor --- .changeset/remove-deprecated-props.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/remove-deprecated-props.md b/.changeset/remove-deprecated-props.md index bcd3c0bf27e..3fb68930414 100644 --- a/.changeset/remove-deprecated-props.md +++ b/.changeset/remove-deprecated-props.md @@ -5,7 +5,7 @@ "@clerk/shared": major "@clerk/ui": major "@clerk/react-router": major -"@clerk/tanstack-react-start": major +"@clerk/tanstack-react-start": minor --- Remove all previously deprecated UI props across the Next.js, React and clerk-js SDKs. The legacy `afterSign(In|Up)Url`/`redirectUrl` props, `UserButton` sign-out overrides, organization `hideSlug` flags, `OrganizationSwitcher`'s `afterSwitchOrganizationUrl`, `Client.activeSessions`, `setActive({ beforeEmit })`, and the `ClerkMiddlewareAuthObject` type alias are no longer exported. Components now rely solely on the new redirect options and server-side configuration.