From 5fd35cdd31d6fb8c88008d493bee608b463e22e6 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 2 May 2025 15:55:47 -0400 Subject: [PATCH 01/12] feat(clerk-js,types): Add checkoutContinueUrl option --- packages/clerk-js/src/core/clerk.ts | 9 +++++++++ .../src/ui/components/Checkout/CheckoutComplete.tsx | 12 +++++++++++- .../src/ui/components/Checkout/CheckoutPage.tsx | 9 +++++++-- .../nextjs/src/utils/mergeNextClerkPropsWithEnv.ts | 1 + packages/react-router/src/utils/env.ts | 1 + packages/react/src/isomorphicClerk.ts | 9 +++++++++ packages/remix/src/ssr/loadOptions.ts | 3 +++ packages/remix/src/ssr/types.ts | 3 +++ packages/remix/src/ssr/utils.ts | 1 + packages/tanstack-react-start/src/utils/env.ts | 1 + packages/types/src/clerk.ts | 12 ++++++++++++ packages/types/src/redirects.ts | 7 +++++++ 12 files changed, 65 insertions(+), 3 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 2e693490fd0..ae60a8ec973 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -175,6 +175,7 @@ const defaultOptions: ClerkOptions = { signInForceRedirectUrl: undefined, signUpForceRedirectUrl: undefined, treatPendingAsSignedOut: true, + checkoutContinueUrl: undefined, }; export class Clerk implements ClerkInterface { @@ -1377,6 +1378,14 @@ export class Clerk implements ClerkInterface { return this.buildUrlWithAuth(this.#options.afterSignOutUrl); } + public buildCheckoutContinueUrl(): string { + if (!this.#options.checkoutContinueUrl) { + return this.buildAfterSignInUrl(); + } + + return this.#options.checkoutContinueUrl; + } + public buildWaitlistUrl(options?: { initialValues?: Record }): string { if (!this.environment || !this.environment.displayConfig) { return ''; diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx index f52c11cb318..dc73accb248 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx @@ -1,3 +1,4 @@ +import { useClerk } from '@clerk/shared/react'; import type { __experimental_CommerceCheckoutResource } from '@clerk/types'; import { Box, Button, descriptors, Heading, Icon, localizationKeys, Span, Text } from '../../customizables'; @@ -7,10 +8,19 @@ import { formatDate } from '../../utils'; const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1); -export const CheckoutComplete = ({ checkout }: { checkout: __experimental_CommerceCheckoutResource }) => { +export const CheckoutComplete = ({ + checkout, + checkoutContinueUrl, +}: { + checkout: __experimental_CommerceCheckoutResource; + checkoutContinueUrl?: string; +}) => { + const clerk = useClerk(); const { setIsOpen } = useDrawerContext(); + const resolvedCheckoutContinueUrl = checkoutContinueUrl || clerk.buildCheckoutContinueUrl(); const handleClose = () => { + void clerk.navigate(resolvedCheckoutContinueUrl); if (setIsOpen) { setIsOpen(false); } diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx index 3f888afc149..ab08dd61c42 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx @@ -9,7 +9,7 @@ import { CheckoutComplete } from './CheckoutComplete'; import { CheckoutForm } from './CheckoutForm'; export const CheckoutPage = (props: __experimental_CheckoutProps) => { - const { planId, planPeriod, subscriberType, onSubscriptionComplete } = props; + const { planId, planPeriod, subscriberType, onSubscriptionComplete, checkoutContinueUrl } = props; const { setIsOpen, isOpen } = useDrawerContext(); const { checkout, isLoading, invalidate, revalidate, updateCheckout, isMissingPayerEmail } = useCheckout({ @@ -42,7 +42,12 @@ export const CheckoutPage = (props: __experimental_CheckoutProps) => { if (checkout) { if (checkout?.status === 'completed') { - return ; + return ( + + ); } return ( diff --git a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts index 08d121031e7..9068d0ea940 100644 --- a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts +++ b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts @@ -25,6 +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'), + checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), }; }; diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 86907ce5c04..5f43be3380d 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -323,6 +323,15 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; + buildCheckoutContinueUrl = (): string | void => { + const callback = () => this.clerkjs?.buildCheckoutContinueUrl() || ''; + if (this.clerkjs && this.loaded) { + return callback(); + } else { + this.premountMethodCalls.set('buildCheckoutContinueUrl', callback); + } + }; + buildAfterMultiSessionSingleSignOutUrl = (): string | void => { const callback = () => this.clerkjs?.buildAfterMultiSessionSingleSignOutUrl() || ''; if (this.clerkjs && this.loaded) { diff --git a/packages/remix/src/ssr/loadOptions.ts b/packages/remix/src/ssr/loadOptions.ts index d65fbea3562..5241cc381b1 100644 --- a/packages/remix/src/ssr/loadOptions.ts +++ b/packages/remix/src/ssr/loadOptions.ts @@ -45,6 +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 checkoutContinueUrl = + overrides.checkoutContinueUrl || getEnvVariable('CLERK_CHECKOUT_CONTINUE_URL', context) || ''; let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && isProxyUrlRelative(relativeOrAbsoluteProxyUrl)) { @@ -81,5 +83,6 @@ export const loadOptions = (args: LoaderFunctionArgs, overrides: RootAuthLoaderO signUpForceRedirectUrl, signInFallbackRedirectUrl, signUpFallbackRedirectUrl, + checkoutContinueUrl, }; }; diff --git a/packages/remix/src/ssr/types.ts b/packages/remix/src/ssr/types.ts index fda77ed7f76..b83c502c142 100644 --- a/packages/remix/src/ssr/types.ts +++ b/packages/remix/src/ssr/types.ts @@ -1,6 +1,7 @@ import type { AuthObject, Organization, Session, User, VerifyTokenOptions } from '@clerk/backend'; import type { RequestState } from '@clerk/backend/internal'; import type { + CheckoutContinueUrl, LegacyRedirectProps, MultiDomainAndOrProxy, SignInFallbackRedirectUrl, @@ -36,6 +37,7 @@ export type RootAuthLoaderOptions = { SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & + CheckoutContinueUrl & LegacyRedirectProps; export type RequestStateWithRedirectUrls = RequestState & @@ -43,6 +45,7 @@ export type RequestStateWithRedirectUrls = RequestState & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & + CheckoutContinueUrl & LegacyRedirectProps; export type RootAuthLoaderCallback = ( diff --git a/packages/remix/src/ssr/utils.ts b/packages/remix/src/ssr/utils.ts index e1e1f129296..a7ed591dbb9 100644 --- a/packages/remix/src/ssr/utils.ts +++ b/packages/remix/src/ssr/utils.ts @@ -94,6 +94,7 @@ export function getResponseClerkState(requestState: RequestStateWithRedirectUrls __signUpForceRedirectUrl: requestState.signUpForceRedirectUrl, __signInFallbackRedirectUrl: requestState.signInFallbackRedirectUrl, __signUpFallbackRedirectUrl: requestState.signUpFallbackRedirectUrl, + __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 8c4c6d42dea..0f90ef373c2 100644 --- a/packages/tanstack-react-start/src/utils/env.ts +++ b/packages/tanstack-react-start/src/utils/env.ts @@ -21,5 +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'), + checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), } as const; }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 2a25b82e7dd..cdd2f2cdff4 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -32,6 +32,7 @@ import type { OrganizationCustomRoleKey } from './organizationMembership'; import type { AfterMultiSessionSingleSignOutUrl, AfterSignOutUrl, + CheckoutContinueUrl, LegacyRedirectProps, RedirectOptions, RedirectUrlProp, @@ -565,6 +566,11 @@ export interface Clerk { */ buildAfterSignOutUrl(): string; + /** + * Returns the configured checkoutContinueUrl of the instance. + */ + buildCheckoutContinueUrl(): string; + /** * Returns the configured afterMultiSessionSingleSignOutUrl of the instance. */ @@ -814,6 +820,7 @@ export type ClerkOptions = PendingSessionOptions & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & + CheckoutContinueUrl & LegacyRedirectProps & AfterSignOutUrl & AfterMultiSessionSingleSignOutUrl & { @@ -1584,6 +1591,11 @@ export type __experimental_CheckoutProps = { onSubscriptionComplete?: () => void; portalId?: string; portalRoot?: PortalRoot; + /** + * Full URL or path to navigate to after checkout is complete and the user clicks the "Continue" button. + * @default undefined + */ + checkoutContinueUrl?: string; }; export type __experimental_PlanDetailsProps = { diff --git a/packages/types/src/redirects.ts b/packages/types/src/redirects.ts index 59f593d827c..447dc7494e3 100644 --- a/packages/types/src/redirects.ts +++ b/packages/types/src/redirects.ts @@ -121,3 +121,10 @@ export type SignInForceRedirectUrl = { */ signInForceRedirectUrl?: string | null; }; + +export type CheckoutContinueUrl = { + /** + * The URL to navigate to after the user completes the checkout and clicks the "Continue" button. + */ + checkoutContinueUrl?: string | null; +}; From 10cf2aaa12bdc8033e3d9b15b3560fe1e9b0244d Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Fri, 2 May 2025 15:59:32 -0400 Subject: [PATCH 02/12] Add changeset --- .changeset/metal-zebras-jog.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/metal-zebras-jog.md diff --git a/.changeset/metal-zebras-jog.md b/.changeset/metal-zebras-jog.md new file mode 100644 index 00000000000..661861b2fbc --- /dev/null +++ b/.changeset/metal-zebras-jog.md @@ -0,0 +1,11 @@ +--- +'@clerk/tanstack-react-start': patch +'@clerk/react-router': patch +'@clerk/clerk-js': patch +'@clerk/nextjs': patch +'@clerk/clerk-react': patch +'@clerk/remix': patch +'@clerk/types': patch +--- + +Introduce `checkoutContinueUrl` option. From f96e8c2ad43f780c1e711facf4d9220df3b22cb4 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Sun, 4 May 2025 13:20:36 -0400 Subject: [PATCH 03/12] handle feedback --- packages/clerk-js/src/core/clerk.ts | 8 ++++---- .../ui/components/Checkout/CheckoutComplete.tsx | 13 ++++--------- .../src/ui/components/Checkout/CheckoutPage.tsx | 9 ++------- .../PricingTable/PricingTableDefault.tsx | 1 + packages/clerk-js/src/ui/hooks/useCheckout.ts | 15 ++++++++++++--- packages/clerk-js/src/ui/types.ts | 3 ++- 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index ae60a8ec973..25b5ad13860 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, - checkoutContinueUrl: undefined, + __experimental_checkoutContinueUrl: undefined, }; export class Clerk implements ClerkInterface { @@ -1378,12 +1378,12 @@ export class Clerk implements ClerkInterface { return this.buildUrlWithAuth(this.#options.afterSignOutUrl); } - public buildCheckoutContinueUrl(): string { - if (!this.#options.checkoutContinueUrl) { + public __experimental_buildCheckoutContinueUrl(): string { + if (!this.#options.__experimental_checkoutContinueUrl) { return this.buildAfterSignInUrl(); } - return this.#options.checkoutContinueUrl; + return this.#options.__experimental_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 b1cce8db8f9..95d2d4ca57e 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx @@ -1,6 +1,7 @@ import { useClerk } from '@clerk/shared/react'; import type { __experimental_CommerceCheckoutResource } from '@clerk/types'; +import { useCheckoutContext } from '../../contexts'; import { Box, Button, descriptors, Heading, Icon, localizationKeys, Span, Text } from '../../customizables'; import { Drawer, LineItems, useDrawerContext } from '../../elements'; import { Check } from '../../icons'; @@ -8,19 +9,13 @@ import { formatDate } from '../../utils'; const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1); -export const CheckoutComplete = ({ - checkout, - checkoutContinueUrl, -}: { - checkout: __experimental_CommerceCheckoutResource; - checkoutContinueUrl?: string; -}) => { +export const CheckoutComplete = ({ checkout }: { checkout: __experimental_CommerceCheckoutResource }) => { const clerk = useClerk(); const { setIsOpen } = useDrawerContext(); - const resolvedCheckoutContinueUrl = checkoutContinueUrl || clerk.buildCheckoutContinueUrl(); + const { __experimental_checkoutContinueUrl } = useCheckoutContext(); const handleClose = () => { - void clerk.navigate(resolvedCheckoutContinueUrl); + void clerk.navigate(__experimental_checkoutContinueUrl); if (setIsOpen) { setIsOpen(false); } diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx index 6d556eee885..428b6faff75 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx @@ -14,7 +14,7 @@ import { CheckoutForm } from './CheckoutForm'; export const CheckoutPage = (props: __experimental_CheckoutProps) => { const { translateError } = useLocalizations(); - const { planId, planPeriod, subscriberType, onSubscriptionComplete, checkoutContinueUrl } = props; + const { planId, planPeriod, subscriberType, onSubscriptionComplete } = props; const { setIsOpen, isOpen } = useDrawerContext(); const { checkout, isLoading, invalidate, revalidate, updateCheckout, errors } = useCheckout({ @@ -49,12 +49,7 @@ export const CheckoutPage = (props: __experimental_CheckoutProps) => { if (checkout) { if (checkout?.status === 'completed') { - return ( - - ); + return ; } return ( diff --git a/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx b/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx index 31bb9a7a9c8..b882578ed45 100644 --- a/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx +++ b/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx @@ -46,6 +46,7 @@ export function PricingTableDefault({ isCompact, props, }: PricingTableDefaultProps) { + console.log(props.__experimental_checkoutContinueUrl); return ( { - const { planId, planPeriod, subscriberType = 'user' } = props; - const { __experimental_commerce } = useClerk(); + const { planId, planPeriod, subscriberType = 'user', __experimental_checkoutContinueUrl } = props; + const { __experimental_commerce, __experimental_buildCheckoutContinueUrl } = useClerk(); const { organization } = useOrganization(); const [currentCheckout, setCurrentCheckout] = useState<__experimental_CommerceCheckoutResource | null>(null); + const checkoutContinueUrl = useMemo(() => { + if (__experimental_checkoutContinueUrl) { + return __experimental_checkoutContinueUrl; + } + + return __experimental_buildCheckoutContinueUrl?.(); + }, [__experimental_checkoutContinueUrl, __experimental_buildCheckoutContinueUrl]); + const { user } = useUser(); const { data: initialCheckout, @@ -48,5 +56,6 @@ export const useCheckout = (props: __experimental_CheckoutProps) => { invalidate, revalidate, errors: error?.errors, + checkoutContinueUrl, }; }; diff --git a/packages/clerk-js/src/ui/types.ts b/packages/clerk-js/src/ui/types.ts index 66e6061196d..af7aef1ef07 100644 --- a/packages/clerk-js/src/ui/types.ts +++ b/packages/clerk-js/src/ui/types.ts @@ -1,4 +1,5 @@ import type { + __experimental_CheckoutContinueUrl, __experimental_CheckoutProps, __experimental_CommerceInvoiceResource, __experimental_CommercePlanResource, @@ -118,7 +119,7 @@ export type __experimental_PricingTableCtx = __experimental_PricingTableProps & export type __experimental_CheckoutCtx = __experimental_CheckoutProps & { componentName: 'Checkout'; -}; +} & __experimental_CheckoutContinueUrl; export type __experimental_PaymentSourcesCtx = { componentName: 'PaymentSources'; From 256b382e1b0902357b130351fb14a128d802d6db Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Sun, 4 May 2025 13:20:59 -0400 Subject: [PATCH 04/12] handle feedback --- packages/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 | 9 +++++---- packages/types/src/redirects.ts | 4 ++-- 9 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts index 9068d0ea940..80ea636ca2d 100644 --- a/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts +++ b/packages/nextjs/src/utils/mergeNextClerkPropsWithEnv.ts @@ -25,7 +25,8 @@ 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'), - checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), + __experimental_checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), }; }; diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 5f43be3380d..73239079b99 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -323,12 +323,12 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - buildCheckoutContinueUrl = (): string | void => { - const callback = () => this.clerkjs?.buildCheckoutContinueUrl() || ''; + __experimental_buildCheckoutContinueUrl = (): string | void => { + const callback = () => this.clerkjs?.__experimental_buildCheckoutContinueUrl() || ''; if (this.clerkjs && this.loaded) { return callback(); } else { - this.premountMethodCalls.set('buildCheckoutContinueUrl', callback); + this.premountMethodCalls.set('__experimental_buildCheckoutContinueUrl', callback); } }; diff --git a/packages/remix/src/ssr/loadOptions.ts b/packages/remix/src/ssr/loadOptions.ts index 5241cc381b1..cce8f2c6153 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 checkoutContinueUrl = - overrides.checkoutContinueUrl || getEnvVariable('CLERK_CHECKOUT_CONTINUE_URL', context) || ''; + const __experimental_checkoutContinueUrl = + overrides.__experimental_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, - checkoutContinueUrl, + __experimental_checkoutContinueUrl, }; }; diff --git a/packages/remix/src/ssr/types.ts b/packages/remix/src/ssr/types.ts index b83c502c142..0f5e6bc0615 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 { - CheckoutContinueUrl, + __experimental_CheckoutContinueUrl, LegacyRedirectProps, MultiDomainAndOrProxy, SignInFallbackRedirectUrl, @@ -37,7 +37,7 @@ export type RootAuthLoaderOptions = { SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - CheckoutContinueUrl & + __experimental_CheckoutContinueUrl & LegacyRedirectProps; export type RequestStateWithRedirectUrls = RequestState & @@ -45,7 +45,7 @@ export type RequestStateWithRedirectUrls = RequestState & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - CheckoutContinueUrl & + __experimental_CheckoutContinueUrl & LegacyRedirectProps; export type RootAuthLoaderCallback = ( diff --git a/packages/remix/src/ssr/utils.ts b/packages/remix/src/ssr/utils.ts index a7ed591dbb9..56d43875342 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, - __checkoutContinueUrl: requestState.checkoutContinueUrl, + __experimental_checkoutContinueUrl: requestState.__experimental_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 0f90ef373c2..fa1bc745207 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'), - checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), + __experimental_checkoutContinueUrl: getValue('CLERK_CHECKOUT_CONTINUE_URL'), } as const; }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index cdd2f2cdff4..862aa28e4f8 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. */ - buildCheckoutContinueUrl(): string; + __experimental_buildCheckoutContinueUrl(): string; /** * Returns the configured afterMultiSessionSingleSignOutUrl of the instance. @@ -820,7 +820,7 @@ export type ClerkOptions = PendingSessionOptions & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & - CheckoutContinueUrl & + __experimental_CheckoutContinueUrl & LegacyRedirectProps & AfterSignOutUrl & AfterMultiSessionSingleSignOutUrl & { @@ -1570,6 +1570,7 @@ export type WaitlistModalProps = WaitlistProps; type __experimental_PricingTableDefaultProps = { ctaPosition?: 'top' | 'bottom'; collapseFeatures?: boolean; + __experimental_checkoutContinueUrl?: string; }; type __experimental_PricingTableBaseProps = { @@ -1595,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 */ - checkoutContinueUrl?: string; + __experimental_checkoutContinueUrl?: string; }; export type __experimental_PlanDetailsProps = { diff --git a/packages/types/src/redirects.ts b/packages/types/src/redirects.ts index 447dc7494e3..f5b6867bd1a 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 CheckoutContinueUrl = { +export type __experimental_CheckoutContinueUrl = { /** * The URL to navigate to after the user completes the checkout and clicks the "Continue" button. */ - checkoutContinueUrl?: string | null; + __experimental_checkoutContinueUrl?: string | null; }; From 5d6013f66f9957dafa02367fe1ee5ad67edeba16 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Sun, 4 May 2025 13:38:35 -0400 Subject: [PATCH 05/12] fixes --- .../src/ui/components/Checkout/CheckoutComplete.tsx | 7 ++++--- .../clerk-js/src/ui/contexts/components/Checkout.ts | 13 ++++++++++++- packages/clerk-js/src/ui/hooks/useCheckout.ts | 10 +++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx index e515d7fd4f0..fe419a3bd41 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx @@ -1,12 +1,13 @@ -import { useClerk } from '@clerk/shared/react'; import type { __experimental_CommerceCheckoutResource } from '@clerk/types'; import { useCheckoutContext } from '../../contexts'; import { Box, Button, descriptors, Heading, localizationKeys, Span, Text } from '../../customizables'; import { Drawer, LineItems, useDrawerContext } from '../../elements'; import { transitionDurationValues, transitionTiming } from '../../foundations/transitions'; +import { useRouter } from '../../router'; import { animations } from '../../styledSystem'; import { formatDate } from '../../utils'; + const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1); export const CheckoutComplete = ({ @@ -16,12 +17,12 @@ export const CheckoutComplete = ({ checkout: __experimental_CommerceCheckoutResource; isMotionSafe: boolean; }) => { - const clerk = useClerk(); + const router = useRouter(); const { setIsOpen } = useDrawerContext(); const { __experimental_checkoutContinueUrl } = useCheckoutContext(); const handleClose = () => { - void clerk.navigate(__experimental_checkoutContinueUrl); + void router.navigate(__experimental_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 58809fa6688..65883bbdae9 100644 --- a/packages/clerk-js/src/ui/contexts/components/Checkout.ts +++ b/packages/clerk-js/src/ui/contexts/components/Checkout.ts @@ -1,4 +1,5 @@ -import { createContext, useContext } from 'react'; +import { useClerk } from '@clerk/shared/react'; +import { createContext, useContext, useMemo } from 'react'; import type { __experimental_CheckoutCtx } from '../../types'; @@ -6,15 +7,25 @@ export const __experimental_CheckoutContext = createContext<__experimental_Check export const useCheckoutContext = () => { const context = useContext(__experimental_CheckoutContext); + const clerk = useClerk(); if (!context || context.componentName !== 'Checkout') { throw new Error('Clerk: useCheckoutContext called outside Checkout.'); } + const checkoutContinueUrl = useMemo(() => { + if (context.__experimental_checkoutContinueUrl) { + return context.__experimental_checkoutContinueUrl; + } + + return clerk.__experimental_buildCheckoutContinueUrl?.(); + }, [context.__experimental_checkoutContinueUrl, clerk]); + const { componentName, ...ctx } = context; return { ...ctx, componentName, + __experimental_checkoutContinueUrl: checkoutContinueUrl, }; }; diff --git a/packages/clerk-js/src/ui/hooks/useCheckout.ts b/packages/clerk-js/src/ui/hooks/useCheckout.ts index fd44d17bc1b..bbdfb6c3b10 100644 --- a/packages/clerk-js/src/ui/hooks/useCheckout.ts +++ b/packages/clerk-js/src/ui/hooks/useCheckout.ts @@ -7,7 +7,7 @@ import { useFetch } from './useFetch'; export const useCheckout = (props: __experimental_CheckoutProps) => { const { planId, planPeriod, subscriberType = 'user', __experimental_checkoutContinueUrl } = props; - const { __experimental_commerce, __experimental_buildCheckoutContinueUrl } = useClerk(); + const clerk = useClerk(); const { organization } = useOrganization(); const [currentCheckout, setCurrentCheckout] = useState<__experimental_CommerceCheckoutResource | null>(null); @@ -16,8 +16,8 @@ export const useCheckout = (props: __experimental_CheckoutProps) => { return __experimental_checkoutContinueUrl; } - return __experimental_buildCheckoutContinueUrl?.(); - }, [__experimental_checkoutContinueUrl, __experimental_buildCheckoutContinueUrl]); + return clerk.__experimental_buildCheckoutContinueUrl?.(); + }, [__experimental_checkoutContinueUrl, clerk]); const { user } = useUser(); const { @@ -27,7 +27,7 @@ export const useCheckout = (props: __experimental_CheckoutProps) => { revalidate, error: _error, } = useFetch( - __experimental_commerce?.__experimental_billing.startCheckout, + clerk.__experimental_commerce?.__experimental_billing.startCheckout, { planId, planPeriod, @@ -56,6 +56,6 @@ export const useCheckout = (props: __experimental_CheckoutProps) => { invalidate, revalidate, errors: error?.errors, - checkoutContinueUrl, + __experimental_checkoutContinueUrl: checkoutContinueUrl, }; }; From 56859aabbd6286bc8ad941980992c7afcf55f1a8 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Sun, 4 May 2025 13:45:41 -0400 Subject: [PATCH 06/12] remove log --- .../src/ui/components/PricingTable/PricingTableDefault.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx b/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx index 936ec9a94ba..7f403eefb44 100644 --- a/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx +++ b/packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx @@ -46,7 +46,6 @@ export function PricingTableDefault({ isCompact, props, }: PricingTableDefaultProps) { - console.log(props.__experimental_checkoutContinueUrl); return ( Date: Sun, 4 May 2025 12:49:41 -0500 Subject: [PATCH 07/12] remove from useCheckout --- packages/clerk-js/src/ui/hooks/useCheckout.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/clerk-js/src/ui/hooks/useCheckout.ts b/packages/clerk-js/src/ui/hooks/useCheckout.ts index bbdfb6c3b10..1098186a229 100644 --- a/packages/clerk-js/src/ui/hooks/useCheckout.ts +++ b/packages/clerk-js/src/ui/hooks/useCheckout.ts @@ -1,24 +1,16 @@ import type { ClerkAPIResponseError } from '@clerk/shared/error'; import { useClerk, useOrganization, useUser } from '@clerk/shared/react'; import type { __experimental_CheckoutProps, __experimental_CommerceCheckoutResource } from '@clerk/types'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useFetch } from './useFetch'; export const useCheckout = (props: __experimental_CheckoutProps) => { - const { planId, planPeriod, subscriberType = 'user', __experimental_checkoutContinueUrl } = props; + const { planId, planPeriod, subscriberType = 'user' } = props; const clerk = useClerk(); const { organization } = useOrganization(); const [currentCheckout, setCurrentCheckout] = useState<__experimental_CommerceCheckoutResource | null>(null); - const checkoutContinueUrl = useMemo(() => { - if (__experimental_checkoutContinueUrl) { - return __experimental_checkoutContinueUrl; - } - - return clerk.__experimental_buildCheckoutContinueUrl?.(); - }, [__experimental_checkoutContinueUrl, clerk]); - const { user } = useUser(); const { data: initialCheckout, @@ -56,6 +48,5 @@ export const useCheckout = (props: __experimental_CheckoutProps) => { invalidate, revalidate, errors: error?.errors, - __experimental_checkoutContinueUrl: checkoutContinueUrl, }; }; From 9d9b7222826d00e9855c035758018f4513a6af09 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Sun, 4 May 2025 14:02:07 -0500 Subject: [PATCH 08/12] pnpm dedupe --- pnpm-lock.yaml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e27425af1e8..9b9af6df765 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3486,82 +3486,66 @@ packages: '@miniflare/cache@2.14.4': resolution: {integrity: sha512-ayzdjhcj+4mjydbNK7ZGDpIXNliDbQY4GPcY2KrYw0v1OSUdj5kZUkygD09fqoGRfAks0d91VelkyRsAXX8FQA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/core@2.14.4': resolution: {integrity: sha512-FMmZcC1f54YpF4pDWPtdQPIO8NXfgUxCoR9uyrhxKJdZu7M6n8QKopPVNuaxR40jcsdxb7yKoQoFWnHfzJD9GQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/d1@2.14.4': resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/durable-objects@2.14.4': resolution: {integrity: sha512-+JrmHP6gHHrjxV8S3axVw5lGHLgqmAGdcO/1HJUPswAyJEd3Ah2YnKhpo+bNmV4RKJCtEq9A2hbtVjBTD2YzwA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/html-rewriter@2.14.4': resolution: {integrity: sha512-GB/vZn7oLbnhw+815SGF+HU5EZqSxbhIa3mu2L5MzZ2q5VOD5NHC833qG8c2GzDPhIaZ99ITY+ZJmbR4d+4aNQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/kv@2.14.4': resolution: {integrity: sha512-QlERH0Z+klwLg0xw+/gm2yC34Nnr/I0GcQ+ASYqXeIXBwjqOtMBa3YVQnocaD+BPy/6TUtSpOAShHsEj76R2uw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/queues@2.14.4': resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/r2@2.14.4': resolution: {integrity: sha512-4ctiZWh7Ty7LB3brUjmbRiGMqwyDZgABYaczDtUidblo2DxX4JZPnJ/ZAyxMPNJif32kOJhcg6arC2hEthR9Sw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/runner-vm@2.14.4': resolution: {integrity: sha512-Nog0bB9SVhPbZAkTWfO4lpLAUsBXKEjlb4y+y66FJw77mPlmPlVdpjElCvmf8T3VN/pqh83kvELGM+/fucMf4g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared-test-environment@2.14.4': resolution: {integrity: sha512-FdU2/8wEd00vIu+MfofLiHcfZWz+uCbE2VTL85KpyYfBsNGAbgRtzFMpOXdoXLqQfRu6MBiRwWpb2FbMrBzi7g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared@2.14.4': resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/sites@2.14.4': resolution: {integrity: sha512-O5npWopi+fw9W9Ki0gy99nuBbgDva/iXy8PDC4dAXDB/pz45nISDqldabk0rL2t4W2+lY6LXKzdOw+qJO1GQTA==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-file@2.14.4': resolution: {integrity: sha512-JxcmX0hXf4cB0cC9+s6ZsgYCq+rpyUKRPCGzaFwymWWplrO3EjPVxKCcMxG44jsdgsII6EZihYUN2J14wwCT7A==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-memory@2.14.4': resolution: {integrity: sha512-9jB5BqNkMZ3SFjbPFeiVkLi1BuSahMhc/W1Y9H0W89qFDrrD+z7EgRgDtHTG1ZRyi9gIlNtt9qhkO1B6W2qb2A==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/watcher@2.14.4': resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/web-sockets@2.14.4': resolution: {integrity: sha512-stTxvLdJ2IcGOs76AnvGYAzGvx8JvQPRxC5DW0P5zdAAnhL33noqb5LKdPt3P37BKp9FzBKZHuihQI9oVqwm0g==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@modelcontextprotocol/sdk@1.7.0': resolution: {integrity: sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==} @@ -3855,6 +3839,7 @@ packages: '@oxc-parser/wasm@0.60.0': resolution: {integrity: sha512-Dkf9/D87WGBCW3L0+1DtpAfL4SrNsgeRvxwjpKCtbH7Kf6K+pxrT0IridaJfmWKu1Ml+fDvj+7HEyBcfUC/TXQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@oxc-project/types@0.56.5': resolution: {integrity: sha512-skY3kOJwp22W4RkaadH1hZ3hqFHjkRrIIE0uQ4VUg+/Chvbl+2pF+B55IrIk2dgsKXS57YEUsJuN6I6s4rgFjA==} @@ -14122,7 +14107,6 @@ packages: vitest-environment-miniflare@2.14.4: resolution: {integrity: sha512-DzwQWdY42sVYR6aUndw9FdCtl/i0oh3NkbkQpw+xq5aYQw5eiJn5kwnKaKQEWaoBe8Cso71X2i1EJGvi1jZ2xw==} engines: {node: '>=16.13'} - deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 peerDependencies: vitest: '>=0.23.0' From cfb14c12b4e93171c8d50f4cb8df982a7e455f47 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Sun, 4 May 2025 20:58:26 -0500 Subject: [PATCH 09/12] restore lockfile from main --- pnpm-lock.yaml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9b9af6df765..e27425af1e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3486,66 +3486,82 @@ packages: '@miniflare/cache@2.14.4': resolution: {integrity: sha512-ayzdjhcj+4mjydbNK7ZGDpIXNliDbQY4GPcY2KrYw0v1OSUdj5kZUkygD09fqoGRfAks0d91VelkyRsAXX8FQA==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/core@2.14.4': resolution: {integrity: sha512-FMmZcC1f54YpF4pDWPtdQPIO8NXfgUxCoR9uyrhxKJdZu7M6n8QKopPVNuaxR40jcsdxb7yKoQoFWnHfzJD9GQ==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/d1@2.14.4': resolution: {integrity: sha512-pMBVq9XWxTDdm+RRCkfXZP+bREjPg1JC8s8C0JTovA9OGmLQXqGTnFxIaS9vf1d8k3uSUGhDzPTzHr0/AUW1gA==} engines: {node: '>=16.7'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/durable-objects@2.14.4': resolution: {integrity: sha512-+JrmHP6gHHrjxV8S3axVw5lGHLgqmAGdcO/1HJUPswAyJEd3Ah2YnKhpo+bNmV4RKJCtEq9A2hbtVjBTD2YzwA==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/html-rewriter@2.14.4': resolution: {integrity: sha512-GB/vZn7oLbnhw+815SGF+HU5EZqSxbhIa3mu2L5MzZ2q5VOD5NHC833qG8c2GzDPhIaZ99ITY+ZJmbR4d+4aNQ==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/kv@2.14.4': resolution: {integrity: sha512-QlERH0Z+klwLg0xw+/gm2yC34Nnr/I0GcQ+ASYqXeIXBwjqOtMBa3YVQnocaD+BPy/6TUtSpOAShHsEj76R2uw==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/queues@2.14.4': resolution: {integrity: sha512-aXQ5Ik8Iq1KGMBzGenmd6Js/jJgqyYvjom95/N9GptCGpiVWE5F0XqC1SL5rCwURbHN+aWY191o8XOFyY2nCUA==} engines: {node: '>=16.7'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/r2@2.14.4': resolution: {integrity: sha512-4ctiZWh7Ty7LB3brUjmbRiGMqwyDZgABYaczDtUidblo2DxX4JZPnJ/ZAyxMPNJif32kOJhcg6arC2hEthR9Sw==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/runner-vm@2.14.4': resolution: {integrity: sha512-Nog0bB9SVhPbZAkTWfO4lpLAUsBXKEjlb4y+y66FJw77mPlmPlVdpjElCvmf8T3VN/pqh83kvELGM+/fucMf4g==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared-test-environment@2.14.4': resolution: {integrity: sha512-FdU2/8wEd00vIu+MfofLiHcfZWz+uCbE2VTL85KpyYfBsNGAbgRtzFMpOXdoXLqQfRu6MBiRwWpb2FbMrBzi7g==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/shared@2.14.4': resolution: {integrity: sha512-upl4RSB3hyCnITOFmRZjJj4A72GmkVrtfZTilkdq5Qe5TTlzsjVeDJp7AuNUM9bM8vswRo+N5jOiot6O4PVwwQ==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/sites@2.14.4': resolution: {integrity: sha512-O5npWopi+fw9W9Ki0gy99nuBbgDva/iXy8PDC4dAXDB/pz45nISDqldabk0rL2t4W2+lY6LXKzdOw+qJO1GQTA==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-file@2.14.4': resolution: {integrity: sha512-JxcmX0hXf4cB0cC9+s6ZsgYCq+rpyUKRPCGzaFwymWWplrO3EjPVxKCcMxG44jsdgsII6EZihYUN2J14wwCT7A==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/storage-memory@2.14.4': resolution: {integrity: sha512-9jB5BqNkMZ3SFjbPFeiVkLi1BuSahMhc/W1Y9H0W89qFDrrD+z7EgRgDtHTG1ZRyi9gIlNtt9qhkO1B6W2qb2A==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/watcher@2.14.4': resolution: {integrity: sha512-PYn05ET2USfBAeXF6NZfWl0O32KVyE8ncQ/ngysrh3hoIV7l3qGGH7ubeFx+D8VWQ682qYhwGygUzQv2j1tGGg==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@miniflare/web-sockets@2.14.4': resolution: {integrity: sha512-stTxvLdJ2IcGOs76AnvGYAzGvx8JvQPRxC5DW0P5zdAAnhL33noqb5LKdPt3P37BKp9FzBKZHuihQI9oVqwm0g==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 '@modelcontextprotocol/sdk@1.7.0': resolution: {integrity: sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==} @@ -3839,7 +3855,6 @@ packages: '@oxc-parser/wasm@0.60.0': resolution: {integrity: sha512-Dkf9/D87WGBCW3L0+1DtpAfL4SrNsgeRvxwjpKCtbH7Kf6K+pxrT0IridaJfmWKu1Ml+fDvj+7HEyBcfUC/TXQ==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@oxc-project/types@0.56.5': resolution: {integrity: sha512-skY3kOJwp22W4RkaadH1hZ3hqFHjkRrIIE0uQ4VUg+/Chvbl+2pF+B55IrIk2dgsKXS57YEUsJuN6I6s4rgFjA==} @@ -14107,6 +14122,7 @@ packages: vitest-environment-miniflare@2.14.4: resolution: {integrity: sha512-DzwQWdY42sVYR6aUndw9FdCtl/i0oh3NkbkQpw+xq5aYQw5eiJn5kwnKaKQEWaoBe8Cso71X2i1EJGvi1jZ2xw==} engines: {node: '>=16.13'} + deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 peerDependencies: vitest: '>=0.23.0' From 4080a36a5d8ee58af32d2d04f75cdb0189ffaf03 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Sun, 4 May 2025 21:14:12 -0500 Subject: [PATCH 10/12] do not navigate on checkout continue click in a modal setting --- .../src/ui/components/Checkout/CheckoutComplete.tsx | 4 +++- packages/clerk-js/src/ui/contexts/components/Checkout.ts | 9 +++++++-- .../src/ui/lazyModules/MountedCheckoutDrawer.tsx | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx index fe419a3bd41..39465d51b01 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx @@ -22,7 +22,9 @@ export const CheckoutComplete = ({ const { __experimental_checkoutContinueUrl } = useCheckoutContext(); const handleClose = () => { - void router.navigate(__experimental_checkoutContinueUrl); + if (__experimental_checkoutContinueUrl) { + void router.navigate(__experimental_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 65883bbdae9..ea85472fe80 100644 --- a/packages/clerk-js/src/ui/contexts/components/Checkout.ts +++ b/packages/clerk-js/src/ui/contexts/components/Checkout.ts @@ -2,7 +2,6 @@ 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 = () => { @@ -14,12 +13,18 @@ export const useCheckoutContext = () => { } const checkoutContinueUrl = useMemo(() => { + // When we're rendered via the PricingTable with mode = 'modal' we provide a `portalRoot` value + // we want to keep users within the context of the modal, so we do this to prevent navigating away + if (context.portalRoot) { + return undefined; + } + if (context.__experimental_checkoutContinueUrl) { return context.__experimental_checkoutContinueUrl; } return clerk.__experimental_buildCheckoutContinueUrl?.(); - }, [context.__experimental_checkoutContinueUrl, clerk]); + }, [context.portalRoot, context.__experimental_checkoutContinueUrl, clerk]); const { componentName, ...ctx } = context; diff --git a/packages/clerk-js/src/ui/lazyModules/MountedCheckoutDrawer.tsx b/packages/clerk-js/src/ui/lazyModules/MountedCheckoutDrawer.tsx index b92f8eecaf1..b232a8d39b5 100644 --- a/packages/clerk-js/src/ui/lazyModules/MountedCheckoutDrawer.tsx +++ b/packages/clerk-js/src/ui/lazyModules/MountedCheckoutDrawer.tsx @@ -42,6 +42,7 @@ export function MountedCheckoutDrawer({ planPeriod={checkoutDrawer.props.planPeriod} subscriberType={checkoutDrawer.props.subscriberType} onSubscriptionComplete={checkoutDrawer.props.onSubscriptionComplete} + portalRoot={checkoutDrawer.props.portalRoot} /> )} From 5719f67cc832c734b6834d7d319655a83f23a904 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Sun, 4 May 2025 21:20:55 -0500 Subject: [PATCH 11/12] fix pnpm dedupe --- pnpm-lock.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e27425af1e8..47ebc2e2094 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3855,6 +3855,7 @@ packages: '@oxc-parser/wasm@0.60.0': resolution: {integrity: sha512-Dkf9/D87WGBCW3L0+1DtpAfL4SrNsgeRvxwjpKCtbH7Kf6K+pxrT0IridaJfmWKu1Ml+fDvj+7HEyBcfUC/TXQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@oxc-project/types@0.56.5': resolution: {integrity: sha512-skY3kOJwp22W4RkaadH1hZ3hqFHjkRrIIE0uQ4VUg+/Chvbl+2pF+B55IrIk2dgsKXS57YEUsJuN6I6s4rgFjA==} From 7b2bc7af85193dc5d43baf6f4706ee9ec2a6eb5e Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Sun, 4 May 2025 21:26:54 -0500 Subject: [PATCH 12/12] bundlewatch --- packages/clerk-js/bundlewatch.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json index d24606d3c2d..baab3fe9030 100644 --- a/packages/clerk-js/bundlewatch.config.json +++ b/packages/clerk-js/bundlewatch.config.json @@ -4,7 +4,7 @@ { "path": "./dist/clerk.browser.js", "maxSize": "68KB" }, { "path": "./dist/clerk.legacy.browser.js", "maxSize": "110KB" }, { "path": "./dist/clerk.headless*.js", "maxSize": "52KB" }, - { "path": "./dist/ui-common*.js", "maxSize": "102KB" }, + { "path": "./dist/ui-common*.js", "maxSize": "102.5KB" }, { "path": "./dist/vendors*.js", "maxSize": "39KB" }, { "path": "./dist/coinbase*.js", "maxSize": "38KB" }, { "path": "./dist/createorganization*.js", "maxSize": "5KB" },