diff --git a/.changeset/remove-deprecated-props.md b/.changeset/remove-deprecated-props.md new file mode 100644 index 00000000000..3fb68930414 --- /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": 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. 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/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 ab74fa77b5c..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; @@ -1699,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. @@ -1786,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. * 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/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/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 - + ); }