From 8b7b954951739ff76e6edc5460d8277239347a76 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Mon, 5 May 2025 11:11:30 +0300 Subject: [PATCH 1/3] refactor(repo): Rename __experimental_checkoutContinueUrl to checkoutContinueUrl --- packages/clerk-js/src/core/clerk.ts | 8 ++++---- .../src/ui/components/Checkout/CheckoutComplete.tsx | 6 +++--- .../clerk-js/src/ui/contexts/components/Checkout.ts | 11 ++++++----- packages/clerk-js/src/ui/types.ts | 4 ++-- .../nextjs/src/utils/mergeNextClerkPropsWithEnv.ts | 3 +-- packages/react-router/src/utils/env.ts | 2 +- packages/react/src/isomorphicClerk.ts | 6 +++--- packages/remix/src/ssr/loadOptions.ts | 6 +++--- packages/remix/src/ssr/types.ts | 6 +++--- packages/remix/src/ssr/utils.ts | 2 +- packages/tanstack-react-start/src/utils/env.ts | 2 +- packages/types/src/clerk.ts | 10 +++++----- packages/types/src/redirects.ts | 4 ++-- 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 25b5ad13860..ae60a8ec973 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -175,7 +175,7 @@ const defaultOptions: ClerkOptions = { signInForceRedirectUrl: undefined, signUpForceRedirectUrl: undefined, treatPendingAsSignedOut: true, - __experimental_checkoutContinueUrl: undefined, + checkoutContinueUrl: undefined, }; export class Clerk implements ClerkInterface { @@ -1378,12 +1378,12 @@ export class Clerk implements ClerkInterface { return this.buildUrlWithAuth(this.#options.afterSignOutUrl); } - public __experimental_buildCheckoutContinueUrl(): string { - if (!this.#options.__experimental_checkoutContinueUrl) { + public buildCheckoutContinueUrl(): string { + if (!this.#options.checkoutContinueUrl) { return this.buildAfterSignInUrl(); } - return this.#options.__experimental_checkoutContinueUrl; + return this.#options.checkoutContinueUrl; } public buildWaitlistUrl(options?: { initialValues?: Record }): string { diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx index 39465d51b01..d1f29af89b8 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx @@ -19,11 +19,11 @@ export const CheckoutComplete = ({ }) => { const router = useRouter(); const { setIsOpen } = useDrawerContext(); - const { __experimental_checkoutContinueUrl } = useCheckoutContext(); + const { checkoutContinueUrl } = useCheckoutContext(); const handleClose = () => { - if (__experimental_checkoutContinueUrl) { - void router.navigate(__experimental_checkoutContinueUrl); + if (checkoutContinueUrl) { + void router.navigate(checkoutContinueUrl); } if (setIsOpen) { setIsOpen(false); diff --git a/packages/clerk-js/src/ui/contexts/components/Checkout.ts b/packages/clerk-js/src/ui/contexts/components/Checkout.ts index ea85472fe80..8ae73aa3334 100644 --- a/packages/clerk-js/src/ui/contexts/components/Checkout.ts +++ b/packages/clerk-js/src/ui/contexts/components/Checkout.ts @@ -2,6 +2,7 @@ import { useClerk } from '@clerk/shared/react'; import { createContext, useContext, useMemo } from 'react'; import type { __experimental_CheckoutCtx } from '../../types'; + export const __experimental_CheckoutContext = createContext<__experimental_CheckoutCtx | null>(null); export const useCheckoutContext = () => { @@ -19,18 +20,18 @@ export const useCheckoutContext = () => { return undefined; } - if (context.__experimental_checkoutContinueUrl) { - return context.__experimental_checkoutContinueUrl; + if (context.checkoutContinueUrl) { + return context.checkoutContinueUrl; } - return clerk.__experimental_buildCheckoutContinueUrl?.(); - }, [context.portalRoot, context.__experimental_checkoutContinueUrl, clerk]); + return clerk.buildCheckoutContinueUrl?.(); + }, [context.portalRoot, context.checkoutContinueUrl, clerk]); const { componentName, ...ctx } = context; return { ...ctx, componentName, - __experimental_checkoutContinueUrl: checkoutContinueUrl, + checkoutContinueUrl: checkoutContinueUrl, }; }; diff --git a/packages/clerk-js/src/ui/types.ts b/packages/clerk-js/src/ui/types.ts index af7aef1ef07..45dd9d09543 100644 --- a/packages/clerk-js/src/ui/types.ts +++ b/packages/clerk-js/src/ui/types.ts @@ -1,5 +1,4 @@ import type { - __experimental_CheckoutContinueUrl, __experimental_CheckoutProps, __experimental_CommerceInvoiceResource, __experimental_CommercePlanResource, @@ -7,6 +6,7 @@ import type { __experimental_PlanDetailsProps, __experimental_PricingTableProps, __internal_UserVerificationProps, + CheckoutContinueUrl, CreateOrganizationProps, GoogleOneTapProps, OrganizationListProps, @@ -119,7 +119,7 @@ export type __experimental_PricingTableCtx = __experimental_PricingTableProps & export type __experimental_CheckoutCtx = __experimental_CheckoutProps & { componentName: 'Checkout'; -} & __experimental_CheckoutContinueUrl; +} & CheckoutContinueUrl; export type __experimental_PaymentSourcesCtx = { componentName: 'PaymentSources'; diff --git a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts index 80ea636ca2d..9068d0ea940 100644 --- a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts +++ b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts @@ -25,8 +25,7 @@ export const mergeNextClerkPropsWithEnv = (props: Omit { signUpFallbackRedirectUrl: getValue('CLERK_SIGN_UP_FALLBACK_REDIRECT_URL'), afterSignInUrl: getValue('CLERK_AFTER_SIGN_IN_URL'), afterSignUpUrl: getValue('CLERK_AFTER_SIGN_UP_URL'), - __experimental_checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), + checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), }; }; diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 73239079b99..5f43be3380d 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -323,12 +323,12 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - __experimental_buildCheckoutContinueUrl = (): string | void => { - const callback = () => this.clerkjs?.__experimental_buildCheckoutContinueUrl() || ''; + buildCheckoutContinueUrl = (): string | void => { + const callback = () => this.clerkjs?.buildCheckoutContinueUrl() || ''; if (this.clerkjs && this.loaded) { return callback(); } else { - this.premountMethodCalls.set('__experimental_buildCheckoutContinueUrl', callback); + this.premountMethodCalls.set('buildCheckoutContinueUrl', callback); } }; diff --git a/packages/remix/src/ssr/loadOptions.ts b/packages/remix/src/ssr/loadOptions.ts index cce8f2c6153..5241cc381b1 100644 --- a/packages/remix/src/ssr/loadOptions.ts +++ b/packages/remix/src/ssr/loadOptions.ts @@ -45,8 +45,8 @@ export const loadOptions = (args: LoaderFunctionArgs, overrides: RootAuthLoaderO overrides.signUpFallbackRedirectUrl || getEnvVariable('CLERK_SIGN_UP_FALLBACK_REDIRECT_URL', context) || ''; const afterSignInUrl = overrides.afterSignInUrl || getEnvVariable('CLERK_AFTER_SIGN_IN_URL', context) || ''; const afterSignUpUrl = overrides.afterSignUpUrl || getEnvVariable('CLERK_AFTER_SIGN_UP_URL', context) || ''; - const __experimental_checkoutContinueUrl = - overrides.__experimental_checkoutContinueUrl || getEnvVariable('CLERK_CHECKOUT_CONTINUE_URL', context) || ''; + const checkoutContinueUrl = + overrides.checkoutContinueUrl || getEnvVariable('CLERK_CHECKOUT_CONTINUE_URL', context) || ''; let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && isProxyUrlRelative(relativeOrAbsoluteProxyUrl)) { @@ -83,6 +83,6 @@ export const loadOptions = (args: LoaderFunctionArgs, overrides: RootAuthLoaderO signUpForceRedirectUrl, signInFallbackRedirectUrl, signUpFallbackRedirectUrl, - __experimental_checkoutContinueUrl, + checkoutContinueUrl, }; }; diff --git a/packages/remix/src/ssr/types.ts b/packages/remix/src/ssr/types.ts index 0f5e6bc0615..b83c502c142 100644 --- a/packages/remix/src/ssr/types.ts +++ b/packages/remix/src/ssr/types.ts @@ -1,7 +1,7 @@ import type { AuthObject, Organization, Session, User, VerifyTokenOptions } from '@clerk/backend'; import type { RequestState } from '@clerk/backend/internal'; import type { - __experimental_CheckoutContinueUrl, + CheckoutContinueUrl, LegacyRedirectProps, MultiDomainAndOrProxy, SignInFallbackRedirectUrl, @@ -37,7 +37,7 @@ export type RootAuthLoaderOptions = { SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - __experimental_CheckoutContinueUrl & + CheckoutContinueUrl & LegacyRedirectProps; export type RequestStateWithRedirectUrls = RequestState & @@ -45,7 +45,7 @@ export type RequestStateWithRedirectUrls = RequestState & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - __experimental_CheckoutContinueUrl & + CheckoutContinueUrl & LegacyRedirectProps; export type RootAuthLoaderCallback = ( diff --git a/packages/remix/src/ssr/utils.ts b/packages/remix/src/ssr/utils.ts index 56d43875342..dc25efc1609 100644 --- a/packages/remix/src/ssr/utils.ts +++ b/packages/remix/src/ssr/utils.ts @@ -94,7 +94,7 @@ export function getResponseClerkState(requestState: RequestStateWithRedirectUrls __signUpForceRedirectUrl: requestState.signUpForceRedirectUrl, __signInFallbackRedirectUrl: requestState.signInFallbackRedirectUrl, __signUpFallbackRedirectUrl: requestState.signUpFallbackRedirectUrl, - __experimental_checkoutContinueUrl: requestState.__experimental_checkoutContinueUrl, + checkoutContinueUrl: requestState.checkoutContinueUrl, __clerk_debug: debugRequestState(requestState), __clerkJSUrl: getEnvVariable('CLERK_JS', context), __clerkJSVersion: getEnvVariable('CLERK_JS_VERSION', context), diff --git a/packages/tanstack-react-start/src/utils/env.ts b/packages/tanstack-react-start/src/utils/env.ts index fa1bc745207..0f90ef373c2 100644 --- a/packages/tanstack-react-start/src/utils/env.ts +++ b/packages/tanstack-react-start/src/utils/env.ts @@ -21,6 +21,6 @@ export const getPublicEnvVariables = (context?: H3EventContext) => { telemetryDebug: isTruthy(getValue('CLERK_TELEMETRY_DEBUG')), afterSignInUrl: getValue('CLERK_AFTER_SIGN_IN_URL'), afterSignUpUrl: getValue('CLERK_AFTER_SIGN_UP_URL'), - __experimental_checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), + checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), } as const; }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 862aa28e4f8..511eeec8b2b 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -30,9 +30,9 @@ import type { OAuthProvider, OAuthScope } from './oauth'; import type { OrganizationResource } from './organization'; import type { OrganizationCustomRoleKey } from './organizationMembership'; import type { - __experimental_CheckoutContinueUrl, AfterMultiSessionSingleSignOutUrl, AfterSignOutUrl, + CheckoutContinueUrl, LegacyRedirectProps, RedirectOptions, RedirectUrlProp, @@ -569,7 +569,7 @@ export interface Clerk { /** * Returns the configured checkoutContinueUrl of the instance. */ - __experimental_buildCheckoutContinueUrl(): string; + buildCheckoutContinueUrl(): string; /** * Returns the configured afterMultiSessionSingleSignOutUrl of the instance. @@ -820,7 +820,7 @@ export type ClerkOptions = PendingSessionOptions & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - __experimental_CheckoutContinueUrl & + CheckoutContinueUrl & LegacyRedirectProps & AfterSignOutUrl & AfterMultiSessionSingleSignOutUrl & { @@ -1570,7 +1570,7 @@ export type WaitlistModalProps = WaitlistProps; type __experimental_PricingTableDefaultProps = { ctaPosition?: 'top' | 'bottom'; collapseFeatures?: boolean; - __experimental_checkoutContinueUrl?: string; + checkoutContinueUrl?: string; }; type __experimental_PricingTableBaseProps = { @@ -1596,7 +1596,7 @@ export type __experimental_CheckoutProps = { * Full URL or path to navigate to after checkout is complete and the user clicks the "Continue" button. * @default undefined */ - __experimental_checkoutContinueUrl?: string; + checkoutContinueUrl?: string; }; export type __experimental_PlanDetailsProps = { diff --git a/packages/types/src/redirects.ts b/packages/types/src/redirects.ts index f5b6867bd1a..447dc7494e3 100644 --- a/packages/types/src/redirects.ts +++ b/packages/types/src/redirects.ts @@ -122,9 +122,9 @@ export type SignInForceRedirectUrl = { signInForceRedirectUrl?: string | null; }; -export type __experimental_CheckoutContinueUrl = { +export type CheckoutContinueUrl = { /** * The URL to navigate to after the user completes the checkout and clicks the "Continue" button. */ - __experimental_checkoutContinueUrl?: string | null; + checkoutContinueUrl?: string | null; }; From 32ea0d4e8caa3663ef5af2e25cba57dfbd073fc0 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Mon, 5 May 2025 12:37:11 +0300 Subject: [PATCH 2/3] fix(clerk-js): Filter checkoutContinueUrl origins --- packages/clerk-js/package.json | 1 + .../src/ui/contexts/components/Checkout.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/clerk-js/package.json b/packages/clerk-js/package.json index fc4d6d025b5..2bda9e3641e 100644 --- a/packages/clerk-js/package.json +++ b/packages/clerk-js/package.json @@ -42,6 +42,7 @@ "clean": "rimraf ./dist", "dev": "rspack serve --config rspack.config.js", "dev:headless": "rspack serve --config rspack.config.js --env variant=\"clerk.headless.browser\"", + "dev:origin": "rspack serve --config rspack.config.js --env devOrigin=http://localhost:4000", "dev:sandbox": "rspack serve --config rspack.config.js --env devOrigin=http://localhost:4000 --env sandbox=1", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16 --ignore-rules named-exports", diff --git a/packages/clerk-js/src/ui/contexts/components/Checkout.ts b/packages/clerk-js/src/ui/contexts/components/Checkout.ts index 8ae73aa3334..a4fe05e4ab0 100644 --- a/packages/clerk-js/src/ui/contexts/components/Checkout.ts +++ b/packages/clerk-js/src/ui/contexts/components/Checkout.ts @@ -1,13 +1,16 @@ import { useClerk } from '@clerk/shared/react'; import { createContext, useContext, useMemo } from 'react'; +import { isAllowedRedirect } from '../../../utils'; import type { __experimental_CheckoutCtx } from '../../types'; +import { useOptions } from '../OptionsContext'; export const __experimental_CheckoutContext = createContext<__experimental_CheckoutCtx | null>(null); export const useCheckoutContext = () => { const context = useContext(__experimental_CheckoutContext); const clerk = useClerk(); + const options = useOptions(); if (!context || context.componentName !== 'Checkout') { throw new Error('Clerk: useCheckoutContext called outside Checkout.'); @@ -20,18 +23,15 @@ export const useCheckoutContext = () => { return undefined; } - if (context.checkoutContinueUrl) { - return context.checkoutContinueUrl; - } - - return clerk.buildCheckoutContinueUrl?.(); - }, [context.portalRoot, context.checkoutContinueUrl, clerk]); + const url = context.checkoutContinueUrl || clerk.buildCheckoutContinueUrl?.(); + return isAllowedRedirect(options?.allowedRedirectOrigins, window.location.origin)(url) ? url : undefined; + }, [context.portalRoot, context.checkoutContinueUrl, clerk, options?.allowedRedirectOrigins]); const { componentName, ...ctx } = context; return { ...ctx, componentName, - checkoutContinueUrl: checkoutContinueUrl, + checkoutContinueUrl, }; }; From 77cb9bdb88c99061c36772d73decd1b17000cc91 Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Mon, 5 May 2025 12:41:07 +0300 Subject: [PATCH 3/3] Create tidy-pots-sin.md --- .changeset/tidy-pots-sin.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/tidy-pots-sin.md diff --git a/.changeset/tidy-pots-sin.md b/.changeset/tidy-pots-sin.md new file mode 100644 index 00000000000..052ba682526 --- /dev/null +++ b/.changeset/tidy-pots-sin.md @@ -0,0 +1,11 @@ +--- +"@clerk/clerk-js": patch +"@clerk/nextjs": patch +"@clerk/react-router": patch +"@clerk/clerk-react": patch +"@clerk/remix": patch +"@clerk/tanstack-react-start": patch +"@clerk/types": patch +--- + +Rename __experimental_checkoutContinueUrl to checkoutContinueUrl