diff --git a/.changeset/proud-donuts-shop.md b/.changeset/proud-donuts-shop.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/proud-donuts-shop.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/witty-doors-hear.md b/.changeset/witty-doors-hear.md index 63639d0a30f..28178bb81fb 100644 --- a/.changeset/witty-doors-hear.md +++ b/.changeset/witty-doors-hear.md @@ -4,18 +4,20 @@ '@clerk/types': minor --- -Expose stable commerce stable apis under `Clerk.commerce` +Expose Clerk Billing APIs. ## Render the pricing table component - `Clerk.mountPricingTable` - `Clerk.unmountPricingTable` -## Commerce namespace -- `Clerk.commerce.initializePaymentSource()` -- `Clerk.commerce.addPaymentSource()` -- `Clerk.commerce.getPaymentSources()` -- `Clerk.commerce.billing` - - `Clerk.commerce.billing.getPlans()` - - `Clerk.commerce.billing.getSubscriptions()` - - `Clerk.commerce.billing.getInvoices()` - - `Clerk.commerce.billing.startCheckout()` +## Manage payment methods +- `Clerk.[user|organization].initializePaymentSource()` +- `Clerk.[user|organization].addPaymentSource()` +- `Clerk.[user|organization].getPaymentSources()` + +## Billing namespace +- `Clerk.billing` + - `Clerk.billing.getPlans()` + - `Clerk.billing.getSubscriptions()` + - `Clerk.billing.getInvoices()` + - `Clerk.billing.startCheckout()` diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 2af08c16035..05aab92a514 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -29,7 +29,7 @@ import type { ClerkOptions, ClientJSONSnapshot, ClientResource, - CommerceNamespace, + CommerceBillingNamespace, CreateOrganizationParams, CreateOrganizationProps, CredentialReturn, @@ -131,7 +131,7 @@ import { eventBus, events } from './events'; import type { FapiClient, FapiRequestCallback } from './fapiClient'; import { createFapiClient } from './fapiClient'; import { createClientFromJwt } from './jwt-client'; -import { Commerce } from './modules/commerce'; +import { CommerceBilling } from './modules/commerce'; import { BaseResource, Client, @@ -187,7 +187,7 @@ export class Clerk implements ClerkInterface { version: __PKG_VERSION__, environment: process.env.NODE_ENV || 'production', }; - private static _commerce: CommerceNamespace; + private static _billing: CommerceBillingNamespace; public client: ClientResource | undefined; public session: SignedInSessionResource | null | undefined; @@ -316,11 +316,11 @@ export class Clerk implements ClerkInterface { return this.#options.standardBrowser || false; } - get commerce(): CommerceNamespace { - if (!Clerk._commerce) { - Clerk._commerce = new Commerce(); + get billing(): CommerceBillingNamespace { + if (!Clerk._billing) { + Clerk._billing = new CommerceBilling(); } - return Clerk._commerce; + return Clerk._billing; } public __internal_getOption(key: K): ClerkOptions[K] { diff --git a/packages/clerk-js/src/core/modules/commerce/Commerce.ts b/packages/clerk-js/src/core/modules/commerce/Commerce.ts deleted file mode 100644 index 61958719d00..00000000000 --- a/packages/clerk-js/src/core/modules/commerce/Commerce.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { - AddPaymentSourceParams, - ClerkPaginatedResponse, - CommerceBillingNamespace, - CommerceInitializedPaymentSourceJSON, - CommerceNamespace, - CommercePaymentSourceJSON, - GetPaymentSourcesParams, - InitializePaymentSourceParams, -} from '@clerk/types'; - -import { convertPageToOffsetSearchParams } from '../../../utils/convertPageToOffsetSearchParams'; -import { BaseResource, CommerceInitializedPaymentSource, CommercePaymentSource } from '../../resources/internal'; -import { CommerceBilling } from './CommerceBilling'; - -export class Commerce implements CommerceNamespace { - private static _billing: CommerceBillingNamespace; - - get billing(): CommerceBillingNamespace { - if (!Commerce._billing) { - Commerce._billing = new CommerceBilling(); - } - return Commerce._billing; - } - - initializePaymentSource = async (params: InitializePaymentSourceParams) => { - const { orgId, ...rest } = params; - const json = ( - await BaseResource._fetch({ - path: orgId - ? `/organizations/${orgId}/commerce/payment_sources/initialize` - : `/me/commerce/payment_sources/initialize`, - method: 'POST', - body: rest as any, - }) - )?.response as unknown as CommerceInitializedPaymentSourceJSON; - return new CommerceInitializedPaymentSource(json); - }; - - addPaymentSource = async (params: AddPaymentSourceParams) => { - const { orgId, ...rest } = params; - - const json = ( - await BaseResource._fetch({ - path: orgId ? `/organizations/${orgId}/commerce/payment_sources` : `/me/commerce/payment_sources`, - method: 'POST', - body: rest as any, - }) - )?.response as unknown as CommercePaymentSourceJSON; - return new CommercePaymentSource(json); - }; - - getPaymentSources = async (params: GetPaymentSourcesParams) => { - const { orgId, ...rest } = params; - - return await BaseResource._fetch({ - path: orgId ? `/organizations/${orgId}/commerce/payment_sources` : `/me/commerce/payment_sources`, - method: 'GET', - search: convertPageToOffsetSearchParams(rest), - }).then(res => { - const { data: paymentSources, total_count } = - res?.response as unknown as ClerkPaginatedResponse; - return { - total_count, - data: paymentSources.map(paymentSource => new CommercePaymentSource(paymentSource)), - }; - }); - }; -} diff --git a/packages/clerk-js/src/core/modules/commerce/index.ts b/packages/clerk-js/src/core/modules/commerce/index.ts index 8a1ec90e17c..0a2889868cc 100644 --- a/packages/clerk-js/src/core/modules/commerce/index.ts +++ b/packages/clerk-js/src/core/modules/commerce/index.ts @@ -1,2 +1,2 @@ -export * from './Commerce'; export * from './CommerceBilling'; +export * from './payment-source-methods'; diff --git a/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts b/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts new file mode 100644 index 00000000000..5ce956d4f65 --- /dev/null +++ b/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts @@ -0,0 +1,55 @@ +import type { + AddPaymentSourceParams, + ClerkPaginatedResponse, + CommerceInitializedPaymentSourceJSON, + CommercePaymentSourceJSON, + GetPaymentSourcesParams, + InitializePaymentSourceParams, +} from '@clerk/types'; + +import { convertPageToOffsetSearchParams } from '../../../utils/convertPageToOffsetSearchParams'; +import { BaseResource, CommerceInitializedPaymentSource, CommercePaymentSource } from '../../resources/internal'; + +export const initializePaymentSource = async (params: InitializePaymentSourceParams) => { + const { orgId, ...rest } = params; + const json = ( + await BaseResource._fetch({ + path: orgId + ? `/organizations/${orgId}/commerce/payment_sources/initialize` + : `/me/commerce/payment_sources/initialize`, + method: 'POST', + body: rest as any, + }) + )?.response as unknown as CommerceInitializedPaymentSourceJSON; + return new CommerceInitializedPaymentSource(json); +}; + +export const addPaymentSource = async (params: AddPaymentSourceParams) => { + const { orgId, ...rest } = params; + + const json = ( + await BaseResource._fetch({ + path: orgId ? `/organizations/${orgId}/commerce/payment_sources` : `/me/commerce/payment_sources`, + method: 'POST', + body: rest as any, + }) + )?.response as unknown as CommercePaymentSourceJSON; + return new CommercePaymentSource(json); +}; + +export const getPaymentSources = async (params: GetPaymentSourcesParams) => { + const { orgId, ...rest } = params; + + return await BaseResource._fetch({ + path: orgId ? `/organizations/${orgId}/commerce/payment_sources` : `/me/commerce/payment_sources`, + method: 'GET', + search: convertPageToOffsetSearchParams(rest), + }).then(res => { + const { data: paymentSources, total_count } = + res?.response as unknown as ClerkPaginatedResponse; + return { + total_count, + data: paymentSources.map(paymentSource => new CommercePaymentSource(paymentSource)), + }; + }); +}; diff --git a/packages/clerk-js/src/core/resources/Organization.ts b/packages/clerk-js/src/core/resources/Organization.ts index 41307a1be5c..de44023c6e0 100644 --- a/packages/clerk-js/src/core/resources/Organization.ts +++ b/packages/clerk-js/src/core/resources/Organization.ts @@ -31,6 +31,7 @@ import type { import { convertPageToOffsetSearchParams } from '../../utils/convertPageToOffsetSearchParams'; import { unixEpochToDate } from '../../utils/date'; +import { addPaymentSource, getPaymentSources, initializePaymentSource } from '../modules/commerce'; import { BaseResource, CommerceSubscription, OrganizationInvitation, OrganizationMembership } from './internal'; import { OrganizationDomain } from './OrganizationDomain'; import { OrganizationMembershipRequest } from './OrganizationMembershipRequest'; @@ -282,6 +283,27 @@ export class Organization extends BaseResource implements OrganizationResource { }).then(res => new Organization(res?.response as OrganizationJSON)); }; + initializePaymentSource: typeof initializePaymentSource = params => { + return initializePaymentSource({ + ...params, + orgId: this.id, + }); + }; + + addPaymentSource: typeof addPaymentSource = params => { + return addPaymentSource({ + ...params, + orgId: this.id, + }); + }; + + getPaymentSources: typeof getPaymentSources = params => { + return getPaymentSources({ + ...params, + orgId: this.id, + }); + }; + protected fromJSON(data: OrganizationJSON | OrganizationJSONSnapshot | null): this { if (!data) { return this; diff --git a/packages/clerk-js/src/core/resources/User.ts b/packages/clerk-js/src/core/resources/User.ts index fad27ab973f..d7b920b51ec 100644 --- a/packages/clerk-js/src/core/resources/User.ts +++ b/packages/clerk-js/src/core/resources/User.ts @@ -36,6 +36,7 @@ import { unixEpochToDate } from '../../utils/date'; import { normalizeUnsafeMetadata } from '../../utils/resourceParams'; import { getFullName } from '../../utils/user'; import { eventBus, events } from '../events'; +import { addPaymentSource, getPaymentSources, initializePaymentSource } from '../modules/commerce'; import { BackupCode } from './BackupCode'; import { BaseResource, @@ -290,6 +291,18 @@ export class User extends BaseResource implements UserResource { return new DeletedObject(json); }; + initializePaymentSource: typeof initializePaymentSource = params => { + return initializePaymentSource(params); + }; + + addPaymentSource: typeof addPaymentSource = params => { + return addPaymentSource(params); + }; + + getPaymentSources: typeof getPaymentSources = params => { + return getPaymentSources(params); + }; + get verifiedExternalAccounts() { return this.externalAccounts.filter(externalAccount => externalAccount.verification?.status == 'verified'); } diff --git a/packages/clerk-js/src/core/resources/__tests__/__snapshots__/Organization.test.ts.snap b/packages/clerk-js/src/core/resources/__tests__/__snapshots__/Organization.test.ts.snap index c75d48deaf9..658708a9b1f 100644 --- a/packages/clerk-js/src/core/resources/__tests__/__snapshots__/Organization.test.ts.snap +++ b/packages/clerk-js/src/core/resources/__tests__/__snapshots__/Organization.test.ts.snap @@ -3,6 +3,7 @@ exports[`Organization has the same initial properties 1`] = ` Organization { "addMember": [Function], + "addPaymentSource": [Function], "adminDeleteEnabled": true, "createDomain": [Function], "createdAt": 1970-01-01T00:00:12.345Z, @@ -12,11 +13,13 @@ Organization { "getInvitations": [Function], "getMembershipRequests": [Function], "getMemberships": [Function], + "getPaymentSources": [Function], "getRoles": [Function], "getSubscriptions": [Function], "hasImage": true, "id": "test_id", "imageUrl": "https://img.clerk.com/eyJ0eXBlIjoiZGVmYXVsdCIsImlpZCI6Imluc18xbHlXRFppb2JyNjAwQUtVZVFEb1NsckVtb00iLCJyaWQiOiJ1c2VyXzJKbElJQTN2VXNjWXh1N2VUMnhINmFrTGgxOCIsImluaXRpYWxzIjoiREsifQ?width=160", + "initializePaymentSource": [Function], "inviteMember": [Function], "inviteMembers": [Function], "maxAllowedMemberships": 3, diff --git a/packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationMembership.test.ts.snap b/packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationMembership.test.ts.snap index f5ef5e33515..5814f81b9dd 100644 --- a/packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationMembership.test.ts.snap +++ b/packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationMembership.test.ts.snap @@ -7,6 +7,7 @@ OrganizationMembership { "id": "test_id", "organization": Organization { "addMember": [Function], + "addPaymentSource": [Function], "adminDeleteEnabled": true, "createDomain": [Function], "createdAt": 1970-01-01T00:00:12.345Z, @@ -16,11 +17,13 @@ OrganizationMembership { "getInvitations": [Function], "getMembershipRequests": [Function], "getMemberships": [Function], + "getPaymentSources": [Function], "getRoles": [Function], "getSubscriptions": [Function], "hasImage": true, "id": "test_org_id", "imageUrl": "https://img.clerk.com/eyJ0eXBlIjoiZGVmYXVsdCIsImlpZCI6Imluc18xbHlXRFppb2JyNjAwQUtVZVFEb1NsckVtb00iLCJyaWQiOiJ1c2VyXzJKbElJQTN2VXNjWXh1N2VUMnhINmFrTGgxOCIsImluaXRpYWxzIjoiREsifQ?width=160", + "initializePaymentSource": [Function], "inviteMember": [Function], "inviteMembers": [Function], "maxAllowedMemberships": 3, diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx index 917c1b61ca1..de9e4bf4d48 100644 --- a/packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx +++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx @@ -1,4 +1,4 @@ -import { useClerk, useOrganization, useUser } from '@clerk/shared/react'; +import { useOrganization } from '@clerk/shared/react'; import type { ClerkAPIError, ClerkRuntimeError, @@ -114,22 +114,18 @@ const CheckoutFormElements = ({ checkout: CommerceCheckoutResource; onCheckoutComplete: (checkout: CommerceCheckoutResource) => void; }) => { - const { commerce } = useClerk(); - const { user } = useUser(); const { organization } = useOrganization(); - const { subscriberType } = useCheckoutContext(); + const { subscriber, subscriberType } = useCheckoutContext(); const [paymentMethodSource, setPaymentMethodSource] = useState('existing'); const [isSubmitting, setIsSubmitting] = useState(false); const [submitError, setSubmitError] = useState(); const { data, revalidate: revalidatePaymentSources } = useFetch( - commerce?.getPaymentSources, - { - ...(subscriberType === 'org' ? { orgId: organization?.id } : {}), - }, + subscriber().getPaymentSources, + {}, undefined, - `commerce-payment-sources-${user?.id}`, + `commerce-payment-sources-${subscriber().id}`, ); const { data: paymentSources } = data || { data: [] }; diff --git a/packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx b/packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx index daeb1e312b8..9815d27a818 100644 --- a/packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx +++ b/packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx @@ -37,12 +37,13 @@ export const AddPaymentSource = (props: AddPaymentSourceProps) => { onPayWithTestPaymentSourceSuccess, showPayWithTestCardSection, } = props; - const { commerce } = useClerk(); const { commerceSettings } = useEnvironment(); const { organization } = useOrganization(); const { user } = useUser(); const subscriberType = useSubscriberTypeContext(); + const resource = subscriberType === 'org' ? organization : user; + const stripePromiseRef = useRef | null>(null); const [stripe, setStripe] = useState(null); @@ -73,13 +74,12 @@ export const AddPaymentSource = (props: AddPaymentSourceProps) => { invalidate, revalidate: revalidateInitializedPaymentSource, } = useFetch( - commerce.initializePaymentSource, + resource?.initializePaymentSource, { gateway: 'stripe', - ...(subscriberType === 'org' ? { orgId: organization?.id } : {}), }, undefined, - `commerce-payment-source-initialize-${user?.id}`, + `commerce-payment-source-initialize-${resource?.id}`, ); const externalGatewayId = initializedPaymentSource?.externalGatewayId; diff --git a/packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx b/packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx index 0285de5ae0f..cfb178c54b4 100644 --- a/packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx +++ b/packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx @@ -1,4 +1,4 @@ -import { useClerk, useOrganization, useUser } from '@clerk/shared/react'; +import { useClerk, useOrganization } from '@clerk/shared/react'; import type { CommercePaymentSourceResource } from '@clerk/types'; import type { SetupIntent } from '@stripe/stripe-js'; import { Fragment, useRef } from 'react'; @@ -16,15 +16,14 @@ import { PaymentSourceRow } from './PaymentSourceRow'; const AddScreen = ({ onSuccess }: { onSuccess: () => void }) => { const { close } = useActionContext(); - const { commerce } = useClerk(); + const clerk = useClerk(); const subscriberType = useSubscriberTypeContext(); - const { organization } = useOrganization(); const onAddPaymentSourceSuccess = async (context: { stripeSetupIntent?: SetupIntent }) => { - await commerce.addPaymentSource({ + const resource = subscriberType === 'org' ? clerk?.organization : clerk.user; + await resource?.addPaymentSource({ gateway: 'stripe', paymentToken: context.stripeSetupIntent?.payment_method as string, - ...(subscriberType === 'org' ? { orgId: organization?.id } : {}), }); onSuccess(); close(); @@ -85,16 +84,16 @@ const RemoveScreen = ({ }; export const PaymentSources = () => { - const { commerce } = useClerk(); - const { organization } = useOrganization(); + const clerk = useClerk(); const subscriberType = useSubscriberTypeContext(); - const { user } = useUser(); + const resource = subscriberType === 'org' ? clerk?.organization : clerk.user; + const { data, revalidate } = useFetch( - commerce?.getPaymentSources, - { ...(subscriberType === 'org' ? { orgId: organization?.id } : {}) }, + resource?.getPaymentSources, + {}, undefined, - `commerce-payment-sources-${user?.id}`, + `commerce-payment-sources-${resource?.id}`, ); const { data: paymentSources } = data || { data: [] }; diff --git a/packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx b/packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx index a466e21f969..fed5dfdeb2b 100644 --- a/packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx +++ b/packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx @@ -14,6 +14,9 @@ const PricingTableRoot = (props: PricingTableProps) => { const subscriberType = useSubscriberTypeContext(); const isCompact = mode === 'modal'; const { organization } = useOrganization(); + const { user } = useUser(); + + const resource = subscriberType === 'org' ? organization : user; const { plans, handleSelectPlan } = usePlansContext(); @@ -27,17 +30,7 @@ const PricingTableRoot = (props: PricingTableProps) => { handleSelectPlan({ mode, plan, planPeriod, event }); }; - const { commerce } = useClerk(); - - const { user } = useUser(); - useFetch( - user ? commerce?.getPaymentSources : undefined, - { - ...(subscriberType === 'org' ? { orgId: organization?.id } : {}), - }, - undefined, - `commerce-payment-sources-${user?.id}`, - ); + useFetch(resource?.getPaymentSources, {}, undefined, `commerce-payment-sources-${resource?.id}`); return ( (null); export const useCheckoutContext = () => { @@ -29,9 +35,22 @@ export const useCheckoutContext = () => { const { componentName, ...ctx } = context; + const subscriber = () => { + if (ctx.subscriberType === 'org' && clerk.organization) { + invariant(clerk.organization, 'Clerk: subscriberType is "org" but no active organization was found'); + + return clerk.organization; + } + + invariant(clerk.user, 'Clerk: no active user found'); + + return clerk.user; + }; + return { ...ctx, componentName, newSubscriptionRedirectUrl, + subscriber, }; }; diff --git a/packages/clerk-js/src/ui/contexts/components/Invoices.tsx b/packages/clerk-js/src/ui/contexts/components/Invoices.tsx index 5495c4f188a..bc11ef8bf45 100644 --- a/packages/clerk-js/src/ui/contexts/components/Invoices.tsx +++ b/packages/clerk-js/src/ui/contexts/components/Invoices.tsx @@ -9,16 +9,18 @@ import { useSubscriberTypeContext } from './SubscriberType'; const InvoicesContext = createContext(null); export const InvoicesContextProvider = ({ children }: PropsWithChildren) => { - const { commerce } = useClerk(); + const { billing } = useClerk(); const { organization } = useOrganization(); const subscriberType = useSubscriberTypeContext(); const { user } = useUser(); + const resource = subscriberType === 'org' ? organization : user; + const { data, isLoading, revalidate } = useFetch( - commerce?.billing.getInvoices, + billing.getInvoices, { ...(subscriberType === 'org' ? { orgId: organization?.id } : {}) }, undefined, - `commerce-invoices-${user?.id}`, + `commerce-invoices-${resource?.id}`, ); const { data: invoices, total_count: totalCount } = data || { data: [], totalCount: 0 }; diff --git a/packages/clerk-js/src/ui/contexts/components/Plans.tsx b/packages/clerk-js/src/ui/contexts/components/Plans.tsx index e8f00ada03f..0011c694129 100644 --- a/packages/clerk-js/src/ui/contexts/components/Plans.tsx +++ b/packages/clerk-js/src/ui/contexts/components/Plans.tsx @@ -18,22 +18,26 @@ import { useSubscriberTypeContext } from './SubscriberType'; const PlansContext = createContext(null); export const useSubscriptions = (subscriberType?: CommerceSubscriberType) => { - const { commerce } = useClerk(); + const { billing } = useClerk(); const { organization } = useOrganization(); const { user } = useUser(); + const resource = subscriberType === 'org' ? organization : user; + return useFetch( - user ? commerce?.billing.getSubscriptions : undefined, + user ? billing.getSubscriptions : undefined, { orgId: subscriberType === 'org' ? organization?.id : undefined }, undefined, - `commerce-subscriptions-${user?.id}`, + `commerce-subscriptions-${resource?.id}`, ); }; export const PlansContextProvider = ({ children }: PropsWithChildren) => { - const { commerce } = useClerk(); + const { billing } = useClerk(); const { organization } = useOrganization(); const { user, isSignedIn } = useUser(); const subscriberType = useSubscriberTypeContext(); + const resource = subscriberType === 'org' ? organization : user; + const { data: subscriptions, isLoading: isLoadingSubscriptions, @@ -44,7 +48,7 @@ export const PlansContextProvider = ({ children }: PropsWithChildren) => { data: plans, isLoading: isLoadingPlans, revalidate: revalidatePlans, - } = useFetch(commerce?.billing.getPlans, { subscriberType }, undefined, 'commerce-plans'); + } = useFetch(billing.getPlans, { subscriberType }, undefined, 'commerce-plans'); // Revalidates the next time the hooks gets mounted const { revalidate: revalidateInvoices } = useFetch( @@ -53,7 +57,7 @@ export const PlansContextProvider = ({ children }: PropsWithChildren) => { ...(subscriberType === 'org' ? { orgId: organization?.id } : {}), }, undefined, - `commerce-invoices-${user?.id}`, + `commerce-invoices-${resource?.id}`, ); const revalidate = useCallback(() => { diff --git a/packages/clerk-js/src/ui/hooks/useCheckout.ts b/packages/clerk-js/src/ui/hooks/useCheckout.ts index 53ac8c52a0b..676afdffb9b 100644 --- a/packages/clerk-js/src/ui/hooks/useCheckout.ts +++ b/packages/clerk-js/src/ui/hooks/useCheckout.ts @@ -19,7 +19,7 @@ export const useCheckout = (props: __internal_CheckoutProps) => { revalidate, error: _error, } = useFetch( - clerk.commerce?.billing.startCheckout, + clerk.billing?.startCheckout, { planId, planPeriod, diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts index 050d12d68a5..d9b18bf73c3 100644 --- a/packages/react/src/isomorphicClerk.ts +++ b/packages/react/src/isomorphicClerk.ts @@ -16,7 +16,7 @@ import type { ClerkOptions, ClerkStatus, ClientResource, - CommerceNamespace, + CommerceBillingNamespace, CreateOrganizationParams, CreateOrganizationProps, DomainOrProxyUrl, @@ -97,12 +97,12 @@ type IsomorphicLoadedClerk = Without< | '__internal_addNavigationListener' | '__internal_getCachedResources' | '__internal_reloadInitialResources' - | 'commerce' + | 'billing' | '__internal_setComponentNavigationContext' | '__internal_setActiveInProgress' > & { client: ClientResource | undefined; - commerce: CommerceNamespace | undefined; + billing: CommerceBillingNamespace | undefined; }; export class IsomorphicClerk implements IsomorphicLoadedClerk { @@ -682,8 +682,8 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } } - get commerce(): CommerceNamespace | undefined { - return this.clerkjs?.commerce; + get billing(): CommerceBillingNamespace | undefined { + return this.clerkjs?.billing; } __unstable__setEnvironment(...args: any): void { diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 7ddf374c650..2c4c320745e 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -16,7 +16,7 @@ import type { } from './appearance'; import type { ClientResource } from './client'; import type { - CommerceNamespace, + CommerceBillingNamespace, CommercePlanResource, CommerceSubscriberType, CommerceSubscriptionPlanPeriod, @@ -181,8 +181,8 @@ export interface Clerk { /** Current User. */ user: UserResource | null | undefined; - /** Commerce Object */ - commerce: CommerceNamespace; + /** Billing Object */ + billing: CommerceBillingNamespace; telemetry: TelemetryCollector | undefined; diff --git a/packages/types/src/commerce.ts b/packages/types/src/commerce.ts index c84efc223e2..413baae8851 100644 --- a/packages/types/src/commerce.ts +++ b/packages/types/src/commerce.ts @@ -5,14 +5,6 @@ import type { ClerkResource } from './resource'; type WithOptionalOrgType = T & { orgId?: string; }; -export interface CommerceNamespace { - billing: CommerceBillingNamespace; - getPaymentSources: ( - params: GetPaymentSourcesParams, - ) => Promise>; - initializePaymentSource: (params: InitializePaymentSourceParams) => Promise; - addPaymentSource: (params: AddPaymentSourceParams) => Promise; -} export interface CommerceBillingNamespace { getPlans: () => Promise; @@ -25,6 +17,16 @@ export type CommerceSubscriberType = 'org' | 'user'; export type CommerceSubscriptionStatus = 'active' | 'ended' | 'upcoming'; export type CommerceSubscriptionPlanPeriod = 'month' | 'annual'; +export interface CommercePaymentSourceMethods { + initializePaymentSource: ( + params: Exclude, + ) => Promise; + addPaymentSource: (params: Exclude) => Promise; + getPaymentSources: ( + params: Exclude, + ) => Promise>; +} + export interface CommerceProductResource extends ClerkResource { id: string; slug: string | null; diff --git a/packages/types/src/organization.ts b/packages/types/src/organization.ts index b99d70b2eca..b6f7750112e 100644 --- a/packages/types/src/organization.ts +++ b/packages/types/src/organization.ts @@ -1,4 +1,4 @@ -import type { CommerceSubscriptionResource, GetSubscriptionsParams } from './commerce'; +import type { CommercePaymentSourceMethods, CommerceSubscriptionResource, GetSubscriptionsParams } from './commerce'; import type { OrganizationDomainResource, OrganizationEnrollmentMode } from './organizationDomain'; import type { OrganizationInvitationResource, OrganizationInvitationStatus } from './organizationInvitation'; import type { OrganizationCustomRoleKey, OrganizationMembershipResource } from './organizationMembership'; @@ -35,7 +35,7 @@ declare global { * * @interface */ -export interface OrganizationResource extends ClerkResource { +export interface OrganizationResource extends ClerkResource, CommercePaymentSourceMethods { id: string; name: string; slug: string | null; diff --git a/packages/types/src/user.ts b/packages/types/src/user.ts index e9dadc8e406..dc7bc5294dd 100644 --- a/packages/types/src/user.ts +++ b/packages/types/src/user.ts @@ -1,4 +1,5 @@ import type { BackupCodeResource } from './backupCode'; +import type { CommercePaymentSourceMethods } from './commerce'; import type { DeletedObjectResource } from './deletedObject'; import type { EmailAddressResource } from './emailAddress'; import type { EnterpriseAccountResource } from './enterpriseAccount'; @@ -60,7 +61,7 @@ declare global { * * The ClerkJS SDK provides some helper [methods](#methods) on the `User` object to help retrieve and update user information and authentication status. */ -export interface UserResource extends ClerkResource { +export interface UserResource extends ClerkResource, CommercePaymentSourceMethods { id: string; externalId: string | null; primaryEmailAddressId: string | null;