Skip to content

Conversation

panteliselef
Copy link
Member

@panteliselef panteliselef commented Sep 11, 2025

Description

Renames Commerce**** -> Billing**** for @clerk/types and @clerk/clerk-js .In follow up PRs we will address @clerk/backend and localization keys

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Introduces Billing (Beta): new Billing namespace and resources for plans, subscriptions, checkouts, statements, payments, and payment sources.
    • UI components and hooks updated to surface Billing types (Checkout, PricingTable, PlanDetails, Subscriptions, Payment flows).
    • Adds createBillingPaginatedHook alias and Billing-aware React hooks (plans, statements, payment attempts/methods, checkout).
  • Refactor

    • Renames Commerce* public types/resources/helpers to Billing* and updates money/totals utilities and warning text.
  • Chores

    • Adds semantic-release changeset for Billing Beta.

@panteliselef panteliselef requested review from aeliox and a team September 11, 2025 18:24
@panteliselef panteliselef self-assigned this Sep 11, 2025
Copy link

changeset-bot bot commented Sep 11, 2025

🦋 Changeset detected

Latest commit: a0a88ad

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@clerk/clerk-js Minor
@clerk/types Minor
@clerk/backend Patch
@clerk/shared Patch
@clerk/clerk-react Patch
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/elements Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/localizations Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/themes Patch
@clerk/vue Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

vercel bot commented Sep 11, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Sep 11, 2025 6:37pm

Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

Walkthrough

Renames public APIs and types from "Commerce" to "Billing" across packages: backend, clerk-js, shared React hooks/components, UI, and @clerk/types. Money-amount, plan/subscription/payment/statement resources, warnings, utilities, and some resourceType/string keys are updated; a Billing alias hook is added.

Changes

Cohort / File(s) Summary
Release metadata
/.changeset/yummy-snails-work.md
Adds changeset entries describing Commerce→Billing rename and package version bumps.
Backend resources
packages/backend/src/api/resources/...
Switches CommerceMoneyAmountBillingMoneyAmount for plan/subscription/subscription-item types and constructor/public fields; updates imports and JSON mapping helpers.
Core Clerk surface
packages/clerk-js/src/core/clerk.ts, .../modules/checkout/manager.ts, .../modules/checkout/__tests__/manager.spec.ts
Replaces Commerce* namespace/types with Billing*; Clerk.billing backing/getter types now BillingNamespace; checkout manager and tests now use BillingCheckoutResource.
Billing module implementation
packages/clerk-js/src/core/modules/commerce/*.ts, .../commerce/payment-source-methods.ts
Renames CommerceBillingBilling; updates method signatures, resource mappings, JSON types and internal constructions to Billing* equivalents; payment-source methods use Billing JSON/resources.
Resource classes
packages/clerk-js/src/core/resources/Commerce*.ts
Renames resource classes and implemented interfaces from Commerce* → Billing*; updates all public fields/types to Billing* (money, plan, payer, payment, statement, subscription, etc.); removes subscription field on payments in favor of subscriptionItem.
Warnings
packages/clerk-js/src/core/warnings.ts
Replaces commerce warning helpers with billing variants and exposes cannotRenderAnyBillingComponent.
UI: Checkout / Payments / Payment Sources / Statements
packages/clerk-js/src/ui/components/...
Replaces Commerce* resource types with Billing* in component props, state generics, and imports (CheckoutForm, PaymentAttempts, PaymentSources, Statements). No runtime logic changes.
UI: Plans & Pricing
packages/clerk-js/src/ui/components/Plans/*, .../PricingTable/*
Switches plan and planPeriod types and handler signatures to Billing* across PlanDetails and PricingTable components.
UI: Subscriptions
packages/clerk-js/src/ui/components/SubscriptionDetails/*, .../Subscriptions/*, tests
Updates subscription-related types (plan, item, status, period) to Billing* in components, contexts, helpers and tests.
Utils
packages/clerk-js/src/utils/commerce.ts
Renames helpers: commerceMoneyAmountFromJSONbillingMoneyAmountFromJSON, commerceTotalsFromJSONbillingTotalsFromJSON; maps JSON → Billing types.
Shared React: components & contexts
packages/shared/src/react/commerce.tsx, .../contexts.tsx
PaymentElementProvider and checkout context use BillingCheckoutResource and BillingSubscriptionPlanPeriod; SWR key adjusted for billing initialization.
Shared React: hooks
packages/shared/src/react/hooks/*
Adds createBillingPaginatedHook alias; converts hooks generics and resourceType strings from commerce-* → billing-* (usePaymentAttempts, usePaymentMethods, usePlans, useStatements, etc.); wiring now calls clerk.billing endpoints.
Types: core surface
packages/types/src/clerk.ts
Clerk.billing typed as BillingNamespace; checkout/plan/planPeriod/CheckoutResult and other checkout-related types updated to Billing*.
Types: billing domain
packages/types/src/commerce.ts
Comprehensive rename Commerce* → Billing* for namespace, resources, enums, unions, JSON/resource types; removes internal CommerceFeature snapshot; replaces subscription with subscriptionItem on payment resource.
Types: JSON DTOs
packages/types/src/json.ts
Renames CommerceJSON → BillingJSON and CommerceMoneyAmountJSON → BillingMoneyAmountJSON; updates nested JSON typings and one field (free_trial_ends_at) now required in BillingCheckoutJSON.
Types: org / user
packages/types/src/organization.ts, packages/types/src/user.ts
OrganizationResource and UserResource now extend BillingPaymentSourceMethods instead of Commerce*.
Types: snapshots
packages/types/src/snapshots.ts
Removes CommercePlanJSONSnapshot and CommerceFeatureJSONSnapshot declarations.
Misc tests & react surface
packages/react/src/**, other tests
Test files updated to use Billing* types (e.g., PlanDetailsButton.test, SubscriptionsList.test).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App
  participant Clerk as Clerk SDK
  participant Billing as Billing Namespace
  participant API as Backend API

  App->>Clerk: clerk.billing.startCheckout(params)
  Clerk->>Billing: Billing.startCheckout(params)
  Billing->>API: POST /.../checkout (sends BillingCheckoutJSON)
  API-->>Billing: BillingCheckoutJSON
  Billing-->>Clerk: BillingCheckout (resource)
  Clerk-->>App: BillingCheckoutResource

  Note over App,Billing: Confirm flow
  App->>Billing: checkout.confirm()
  Billing->>API: POST /.../checkout/confirm
  API-->>Billing: BillingCheckoutJSON (updated)
  Billing-->>App: Updated BillingCheckoutResource
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely and accurately summarizes the primary change — renaming "commerce" identifiers to "billing" within the clerk-js and types packages. It is brief, follows conventional commit style (chore(scope):), and clearly communicates the main intent to reviewers scanning PR history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I thump my paws: “Billing’s here!”
Commerce hopped away, now names are clear.
Plans and payments, statements too—
New carrots, same garden, shiny and new.
With types aligned and hooks that sing,
I twitch my nose—release the spring! 🥕🐇

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/bill-1249-rename-types-for-commerce-to-billing

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

pkg-pr-new bot commented Sep 11, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@6757

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@6757

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@6757

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@6757

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@6757

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@6757

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@6757

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@6757

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@6757

@clerk/express

npm i https://pkg.pr.new/@clerk/express@6757

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@6757

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@6757

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@6757

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@6757

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@6757

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@6757

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@6757

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@6757

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@6757

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@6757

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@6757

@clerk/types

npm i https://pkg.pr.new/@clerk/types@6757

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@6757

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@6757

commit: a0a88ad

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)

283-284: Hard-coded English "upcoming" breaks localization.
Replace the inline string with a localized prefix.

Use a localized label and a derived display name:

// inside SubscriptionDetailsFooter
const { t } = useLocalizations();
const planDisplay =
  selectedSubscription.status === 'upcoming'
    ? `${t(localizationKeys('commerce.upcoming'))} ${selectedSubscription.plan.name}`
    : selectedSubscription.plan.name;

// Then in the title's localization params:
localizationKeys('commerce.cancelSubscriptionTitle', { plan: planDisplay })
packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (1)

115-118: Avoid in-place sort; it mutates hook data.

Sorting paymentMethods directly can mutate shared state and cause subtle bugs. Copy before sorting and return a stable comparator.

-  const sortedPaymentSources = useMemo(
-    () => paymentMethods.sort((a, b) => (a.isDefault && !b.isDefault ? -1 : 1)),
-    [paymentMethods],
-  );
+  const sortedPaymentSources = useMemo(
+    () =>
+      [...paymentMethods].sort((a, b) => {
+        if (a.isDefault === b.isDefault) return 0;
+        return a.isDefault ? -1 : 1;
+      }),
+    [paymentMethods],
+  );
packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1)

53-68: Fix comparator and avoid mutating subscriptionItems.

  • Current comparator returns 1 for most non-active pairs, which is unstable and incorrect.
  • Sorting in place mutates source data.
-  const sortedSubscriptions = useMemo(
-    () =>
-      subscriptionItems.sort((a, b) => {
-        // always put active subscriptions first
-        if (a.status === 'active' && b.status !== 'active') {
-          return -1;
-        }
-
-        if (b.status === 'active' && a.status !== 'active') {
-          return 1;
-        }
-
-        return 1;
-      }),
-    [subscriptionItems],
-  );
+  const sortedSubscriptions = useMemo(
+    () =>
+      [...subscriptionItems].sort((a, b) => {
+        const aActive = a.status === 'active';
+        const bActive = b.status === 'active';
+        if (aActive && !bActive) return -1;
+        if (bActive && !aActive) return 1;
+        return 0;
+      }),
+    [subscriptionItems],
+  );
packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1)

210-215: Localize the aria-label.

Hard-coded aria-label violates the localization guideline for user-facing strings. Use a localization key.

-        <SegmentedControl.Root
-          aria-label='Payment method source'
+        <SegmentedControl.Root
+          aria-label={t => t.localize(localizationKeys('commerce.checkout.paymentMethodSourceAriaLabel'))}

If SegmentedControl.Root supports an ariaLabel/ariaLabelKey prop, prefer that variant.

packages/clerk-js/src/core/resources/CommercePaymentSource.ts (2)

46-58: Add explicit return type and JSDoc; keep API contracts clear.

Return type is currently inferred; declare it explicitly and document params/return.

Apply:

-  public async remove(params?: RemovePaymentSourceParams) {
+  public async remove(params?: RemovePaymentSourceParams): Promise<DeletedObject> {

60-71: Avoid any in request body and add explicit return type.

Use a precise type for the payload and declare the return type.

Apply:

-  public async makeDefault(params?: MakeDefaultPaymentSourceParams) {
+  public async makeDefault(params?: MakeDefaultPaymentSourceParams): Promise<null> {
     const { orgId } = params ?? {};
     await BaseResource._fetch({
       path: orgId
         ? `/organizations/${orgId}/commerce/payers/default_payment_source`
         : `/me/commerce/payers/default_payment_source`,
       method: 'PUT',
-      body: { payment_source_id: this.id } as any,
+      body: { payment_source_id: this.id } satisfies { payment_source_id: string },
     });
packages/clerk-js/src/core/resources/CommerceCheckout.ts (1)

56-87: Tighten types & correct backoff comment — packages/clerk-js/src/core/resources/CommerceCheckout.ts

  • Change shouldRetry(error: any, iterations: number) to shouldRetry(error: unknown, iterations: number) (matches retry.ts signature).
  • Remove as any on body; pass the typed param (body: params) or call _basePatch with an explicit generic (this._basePatch<ConfirmCheckoutParams>({ ..., body: params })) if the compiler requires — avoid any.
  • Fix the comment: with initialDelay = 2000, maxDelayBetweenRetries = 2000, factor = 1.1, jitter = false delays are constant ≈2s for each retry (3 retries). Either update the comment to say "constant 2s delay between attempts" or change maxDelayBetweenRetries/factor to implement increasing backoff.
  • Confirm the /commerce/checkouts/.../confirm path is the intended endpoint post-rename and plan a migration if backend paths move to /billing/....
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (1)

1-18: Add explicit return type for startCheckout and import the resource type.

Public API should declare return types; align with BillingNamespace#startCheckout.

@@
 import type {
   BillingCheckoutJSON,
+  BillingCheckoutResource,
   BillingNamespace,
@@
-  startCheckout = async (params: CreateCheckoutParams) => {
+  startCheckout = async (params: CreateCheckoutParams): Promise<BillingCheckoutResource> => {
     const { orgId, ...rest } = params;
     const json = (
       await BaseResource._fetch<BillingCheckoutJSON>({
         path: orgId ? `/organizations/${orgId}/commerce/checkouts` : `/me/commerce/checkouts`,
         method: 'POST',
         body: rest as any,
       })
     )?.response as unknown as BillingCheckoutJSON;
     return new BillingCheckout(json);
   };

Also applies to: 123-134

🧹 Nitpick comments (41)
.changeset/yummy-snails-work.md (1)

8-8: Add BREAKING/migration notes or explicit deprecation policy.

Clarify impact and how to migrate. If aliases exist, note stability and removal timeline; if not, call out the breaking rename and add a link to docs/codemod.

Proposed replacement:

-[Billing Beta] Rename types, interfaces and classes that contain `commerce` to use `billing` instead.
+[Billing Beta] Rename all public `Commerce*` types, interfaces, classes, and resource identifiers to `Billing*`.
+
+BREAKING:
+- If no deprecation aliases are provided, this release removes `Commerce*` exports and requires migrating imports and type references to `Billing*`.
+- If deprecation aliases are provided, `Commerce*` exports remain as deprecated and will be removed in the next major. Please migrate to `Billing*`.
+
+Migration:
+- Replace imports/usages: `CommerceX` → `BillingX` (plans, subscriptions, payments, statements, checkout, money amounts, resourceType strings, hooks).
+- See docs/changelog for a complete mapping and examples.
packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (2)

151-159: Consider localizing payment status text

{paymentAttempt.status} is rendered verbatim. If you expose statuses to end users, prefer localized labels or a status-to-key map.


178-181: Migrate i18n keys from commerce. → billing. (or add alias mappings)**

Multiple UI files still call localizationKeys('commerce.'); update to 'billing.' or add alias entries in your i18n bundle to avoid drift. Example locations: packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (≈178, 239, 246), packages/clerk-js/src/ui/contexts/components/Plans.tsx, packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx. Locate all occurrences with:
rg -n --hidden --no-ignore-vcs -S "localizationKeys(['"]commerce." packages/clerk-js/src/ui

packages/backend/src/api/resources/CommerceSubscription.ts (1)

6-10: Docstring still references CommerceSubscriptionResource

Update the reference to the Billing equivalent to avoid confusion.

- * The `CommerceSubscription` object is similar to the [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) object
+ * The `CommerceSubscription` object is similar to the [`BillingSubscriptionResource`](/docs/references/javascript/types/billing-subscription-resource) object
packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx (1)

15-40: Guard rows during loading and add explicit return types

Prevent potential runtime errors when paymentAttempts is temporarily undefined and prefer explicit return types for exported/components.

-export const PaymentAttemptsList = () => {
+export const PaymentAttemptsList = (): JSX.Element => {
   const { data: paymentAttempts, isLoading, count } = usePaymentAttempts();
 ...
-      rows={paymentAttempts.map(i => (
+      rows={(paymentAttempts ?? []).map(i => (
         <PaymentAttemptsListRow
           key={i.id}
           paymentAttempt={i}
         />
       ))}

Also:

-const PaymentAttemptsListRow = ({ paymentAttempt }: { paymentAttempt: BillingPaymentResource }) => {
+const PaymentAttemptsListRow = ({ paymentAttempt }: { paymentAttempt: BillingPaymentResource }): JSX.Element => {

Optionally localize status text instead of rendering {status} directly.

Also applies to: 43-86

packages/backend/src/api/resources/CommerceSubscriptionItem.ts (2)

93-106: Deduplicate money JSON mapping via shared helper

You’re re-implementing the JSON→money mapping. Prefer using/centralizing a single helper (e.g., billingMoneyAmountFromJSON) to avoid drift.

I can extract a shared helper or wire this to the existing one if present.


6-10: Docstring mentions Commerce endpoints

If this resource is now part of the Billing rename, refresh the links/descriptions to reference Billing docs to prevent confusion.

- ... in the [Backend API](https://clerk.com/docs/reference/backend-api/tag/commerce/get/commerce/subscription_items)
+ ... in the [Backend API](https://clerk.com/docs/reference/backend-api/tag/billing/get/billing/subscription_items)
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)

80-91: Updated generics to Billing types — OK; consider removing as any.
If you want to avoid as any, we can tighten the return type with a discriminated union and avoid the cast.

packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx (1)

52-70: selectPlan typing verified — handler & checkout props use Billing types

  • Confirmed: handleSelectPlan expects plan: BillingPlanResource and planPeriod: BillingSubscriptionPlanPeriod (packages/clerk-js/src/ui/contexts/components/Plans.tsx).
  • Confirmed: __internal_CheckoutProps defines planPeriod: BillingSubscriptionPlanPeriod (packages/types/src/clerk.ts).
  • Optional nitpick: add explicit return type : void to selectPlan (packages/clerk-js/src/ui/components/PricingTable/PricingTable.tsx).
packages/shared/src/react/hooks/createCommerceHook.tsx (1)

114-116: Public alias added; add JSDoc and consider deprecating the Commerce-named factory

Add a short JSDoc so the alias shows up correctly in API docs and guides users toward the Billing naming.

-// Billing alias factory for paginated hooks
-export const createBillingPaginatedHook = createCommercePaginatedHook;
+/** 
+ * Public alias for billing resources. Mirrors `createCommercePaginatedHook`.
+ * @public
+ */
+export const createBillingPaginatedHook = createCommercePaginatedHook;

Optionally, mark createCommercePaginatedHook as deprecated in its JSDoc to steer new usage to the Billing alias.

packages/shared/src/react/hooks/useCheckout.ts (1)

43-46: Update comment to reference Billing types

Doc still mentions “CommerceCheckoutResource”; update to “BillingCheckoutResource”.

- * On status === 'needs_confirmation' or 'completed', all properties are defined the same as the CommerceCheckoutResource.
+ * On status === 'needs_confirmation' or 'completed', all properties are defined the same as the BillingCheckoutResource.
packages/clerk-js/src/ui/components/Statements/StatementsList.tsx (1)

1-1: Type rename to Billing is consistent

Prop and import updates are correct. Optional: the onPageChange={_ => {}} no-op suggests pagination isn’t wired—ensure this is intentional for the current scope.

Also applies to: 42-42

packages/clerk-js/src/ui/components/Subscriptions/__tests__/SubscriptionsList.test.tsx (1)

318-318: Fix typo in test title ("upcomming" → "upcoming").

Keeps test descriptions clean.

-  it('renders upcomming badge when current subscription is canceled but active', async () => {
+  it('renders upcoming badge when current subscription is canceled but active', async () => {
packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx (1)

65-71: Prefer useMemo over useRef for derived identifier string.

ref.current is always truthy with the current template; the null-guard never triggers. Use useMemo for clarity and drop the dead check.

-  const ref = useRef(
-    `${paymentSource.paymentMethod === 'card' ? paymentSource.cardType : paymentSource.paymentMethod} ${paymentSource.paymentMethod === 'card' ? `⋯ ${paymentSource.last4}` : '-'}`,
-  );
-
-  if (!ref.current) {
-    return null;
-  }
+  const identifier = useMemo(
+    () =>
+      `${paymentSource.paymentMethod === 'card' ? paymentSource.cardType : paymentSource.paymentMethod} ${
+        paymentSource.paymentMethod === 'card' ? `⋯ ${paymentSource.last4}` : '-'
+      }`,
+    [paymentSource.cardType, paymentSource.last4, paymentSource.paymentMethod],
+  );

And update usages:

-          identifier: ref.current,
+          identifier,
-          paymentSource: ref.current,
+          paymentSource: identifier,
packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1)

163-163: Redundant key on .

Parent already assigns key to . The inner key is unnecessary.

-    <Tr key={subscription.id}>
+    <Tr>
packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1)

356-360: Improve label formatting for non-card methods.

capitalize will render apple_pay as Apple_pay. Consider humanizing wallet names.

-        const label =
-          source.paymentMethod !== 'card'
-            ? `${capitalize(source.paymentMethod)}`
-            : `${capitalize(source.cardType)} ⋯ ${source.last4}`;
+        const pretty = (s: string) => s.replace(/[_-]+/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
+        const label =
+          source.paymentMethod !== 'card'
+            ? pretty(source.paymentMethod)
+            : `${pretty(source.cardType)} ⋯ ${source.last4}`;
packages/shared/src/react/hooks/usePaymentAttempts.tsx (1)

4-4: Rename the alias to avoid confusion.

Use the actual name to reduce cognitive overhead.

-import { createBillingPaginatedHook as createCommercePaginatedHook } from './createCommerceHook';
+import { createBillingPaginatedHook } from './createCommerceHook';
@@
-export const usePaymentAttempts = createCommercePaginatedHook<BillingPaymentResource, GetPaymentAttemptsParams>({
+export const usePaymentAttempts = createBillingPaginatedHook<BillingPaymentResource, GetPaymentAttemptsParams>({

Also applies to: 9-9

packages/backend/src/api/resources/CommercePlan.ts (1)

71-79: Annotate helper’s return type for clarity.

Make the return type explicit to match project TS guidelines.

-    const formatAmountJSON = (fee: CommercePlanJSON['fee']) => {
+    const formatAmountJSON = (fee: CommercePlanJSON['fee']): BillingMoneyAmount => {
       return {
         amount: fee.amount,
         amountFormatted: fee.amount_formatted,
         currency: fee.currency,
         currencySymbol: fee.currency_symbol,
       };
     };
packages/clerk-js/src/utils/commerce.ts (1)

10-17: Renamed money conversion looks good; add temporary aliases to ease migration.

Provide deprecated aliases so downstreams don’t break immediately.

 // existing function unchanged
 export const billingMoneyAmountFromJSON = (data: BillingMoneyAmountJSON): BillingMoneyAmount => {
   return {
     amount: data.amount,
     amountFormatted: data.amount_formatted,
     currency: data.currency,
     currencySymbol: data.currency_symbol,
   };
 };
+
+// TODO: Remove in next major
+/** @deprecated Use billingMoneyAmountFromJSON */
+export const commerceMoneyAmountFromJSON = billingMoneyAmountFromJSON;

Additionally (outside the shown range), consider adding:

// TODO: Remove in next major
/** @deprecated Use billingTotalsFromJSON */
export const commerceTotalsFromJSON = billingTotalsFromJSON;
packages/shared/src/react/hooks/usePlans.tsx (1)

4-4: Rename alias to reduce cognitive overhead (use “Billing” consistently).

Import createBillingPaginatedHook without aliasing it to Commerce, and use it directly when creating the hook.

-import { createBillingPaginatedHook as createCommercePaginatedHook } from './createCommerceHook';
+import { createBillingPaginatedHook } from './createCommerceHook';
@@
-export const usePlans = createCommercePaginatedHook<BillingPlanResource, GetPlansParams>({
+export const usePlans = createBillingPaginatedHook<BillingPlanResource, GetPlansParams>({

Also applies to: 9-9

packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (3)

132-140: Remove hard-coded fallback text when using localization keys.

Guideline: don’t render hard-coded strings. Drop the literal “Billing cycle” and rely solely on localizationKey.

-                    <Text
+                    <Text
                       id={segmentedControlId}
                       colorScheme='secondary'
                       variant='caption'
                       localizationKey={localizationKeys('commerce.pricingTable.billingCycle')}
-                    >
-                      Billing cycle
-                    </Text>
+                    />

141-144: Tighten SegmentedControl typing to avoid casting.

If SegmentedControl.Root supports generics, parameterize it with BillingSubscriptionPlanPeriod to drop the as cast.

-                    <SegmentedControl.Root
+                    <SegmentedControl.Root<BillingSubscriptionPlanPeriod>
                       aria-labelledby={segmentedControlId}
                       value={planPeriod}
-                      onChange={value => setPlanPeriod(value as BillingSubscriptionPlanPeriod)}
+                      onChange={value => setPlanPeriod(value)}
                     >

200-208: Guard against empty plan names when deriving initials.

plan.name[0] can throw if name is an empty string. Use optional chaining with a fallback.

-                              initials={plan.name[0]}
+                              initials={plan.name?.[0] ?? ''}
packages/clerk-js/src/core/resources/CommercePayment.ts (1)

15-47: Rename and JSON mapping look correct; consider adding JSDoc for the public resource.

The class aligns with BillingPaymentResource and uses the Billing JSON helpers. Add a short JSDoc to meet the “public APIs must be documented” guideline.

+/**
+ * Billing payment resource.
+ * @public
+ */
 export class BillingPayment extends BaseResource implements BillingPaymentResource {
packages/clerk-js/src/core/resources/CommercePaymentSource.ts (1)

74-94: Document experimental surface on the initializer resource.

Add a brief class-level JSDoc (experimental notice) and property docs (externalClientSecret, externalGatewayId, paymentMethodOrder).

packages/clerk-js/src/core/resources/CommerceCheckout.ts (1)

13-16: Align filenames with renamed types.

Imports refer to ./CommercePayer while class is BillingPayer. Consider renaming the file to BillingPayer.ts (and this file to BillingCheckout.ts) for consistency in a follow-up.

packages/clerk-js/src/core/modules/checkout/__tests__/manager.spec.ts (2)

188-191: DRY the repeated mocked function type.

Introduce a small alias to reduce noise and improve readability.

Apply near the top:

+type AsyncCheckoutOp = MockedFunction<() => Promise<BillingCheckoutResource>>;

Then replace occurrences like:

-const mockOperation: MockedFunction<() => Promise<BillingCheckoutResource>> = vi.fn().mockResolvedValue(mockCheckout);
+const mockOperation: AsyncCheckoutOp = vi.fn().mockResolvedValue(mockCheckout);

Also applies to: 214-221, 234-237, 259-262, 274-277, 293-296, 318-324, 337-340, 362-364, 409-415, 435-438, 461-463, 642-644, 670-673, 687-693


362-364: Use fake timers to avoid real timeouts in concurrency tests.

Real setTimeout can slow tests and be flaky under load.

Example:

beforeEach(() => {
  vi.useFakeTimers();
});

it('deduplicates concurrent start ops', async () => {
  const op: AsyncCheckoutOp = vi.fn().mockImplementation(
    () => new Promise(resolve => setTimeout(() => resolve(createMockCheckoutResource()), 50)),
  );
  const p = Promise.all([manager.executeOperation('start', op), manager.executeOperation('start', op)]);
  await vi.advanceTimersByTimeAsync(50);
  await p;
});

Want me to push a test refactor PR with fake timers?

Also applies to: 409-415, 687-693

packages/types/src/clerk.ts (2)

1062-1076: Experimental flag still named commerce. Confirm intent or add a billing alias.

If the product surface moved to “Billing”, consider introducing experimental.billing?: boolean (keeping commerce for back-compat, deprecating it in docs).


587-591: Wording nit: “commerce functionality” → “billing functionality”.

Update the docstring for clarity with the new naming.

Apply:

- * Loads Stripe libraries for commerce functionality
+ * Loads Stripe libraries for billing functionality
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (2)

31-46: Prefer await over .then for consistency and readability.

Minor cleanup; apply a consistent async style across methods.

Also applies to: 64-81, 94-112


30-30: Add JSDoc to the public Billing namespace.

Document that this is experimental and surfaces Billing endpoints under /commerce/* paths to avoid confusion.

@@
+/**
+ * Billing namespace client.
+ * @experimental Subject to change while in public beta.
+ * Note: Underlying API paths still use `/commerce/*`.
+ */
 export class Billing implements BillingNamespace {
packages/types/src/json.ts (2)

892-894: Remove stale TODO for free_trial_ends_at.

The field is now required (number | null), so the TODO is obsolete.

@@
-  // TODO(@COMMERCE): Remove optional after GA.
   free_trial_ends_at: number | null;

653-680: Clarify discriminants still read commerce_* while types are Billing.*

To reduce developer confusion during the rename, add a short JSDoc note on these DTOs that object remains commerce_* for wire compatibility.

Also applies to: 724-731, 755-767, 808-828, 880-896

packages/clerk-js/src/core/resources/CommerceSubscription.ts (1)

71-73: Refresh TODO wording.

Align the tag with Billing and clarify the open question.

-  //TODO(@COMMERCE): Why can this be undefined ?
+  // TODO(@BILLING): Confirm when `amount` is expected to be undefined (e.g., free plan/legacy items).
packages/types/src/commerce.ts (5)

511-514: Prefer optional property over union with undefined.

-  walletType: string | undefined;
+  walletType?: string;

1225-1231: JSDoc/type mismatch for freeTrialEndsAt.

Doc says “Unix timestamp (milliseconds)” but the type is Date | null.

-  /**
-   * Unix timestamp (milliseconds) of when the free trial ends.
-   */
+  /**
+   * Date when the free trial ends.
+   */
   freeTrialEndsAt: Date | null;

239-246: Clarify annualMonthlyFee semantics.

Name is ambiguous. At minimum, document it as “monthly equivalent when billed annually.”

   /**
    * @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change.
    * It is advised to pin the SDK version and the clerk-js version to a specific version to avoid breaking changes.
    * @example
    * ```tsx
    * <ClerkProvider clerkJsVersion="x.x.x" />
    * ```
    */
-  annualMonthlyFee: BillingMoneyAmount;
+  /**
+   * Monthly equivalent when billed annually (e.g. $20/mo if annualFee is $240).
+   */
+  annualMonthlyFee: BillingMoneyAmount;

807-809: Update leftover TODO namespace; decide nullability.

-  //TODO(@COMMERCE): should this be nullable ?
+  // TODO(@BILLING): should this be nullable?

If nullable, change to paymentSourceId: string | null;.


1-4: File name still commerce.ts.

Consider renaming to billing.ts and re-export from commerce.ts to avoid breaking imports.

Example new file (outside this diff):

// packages/types/src/billing.ts
export * from './commerce';

And keep commerce.ts with a deprecation JSDoc on the module.

packages/clerk-js/src/core/resources/CommerceFeature.ts (1)

17-29: JSON mapping is correct; tiny readability nit (optional).

A small destructuring makes field assignments slightly clearer.

-  protected fromJSON(data: FeatureJSON | null): this {
+  protected fromJSON(data: FeatureJSON | null): this {
     if (!data) {
       return this;
     }
-
-    this.id = data.id;
-    this.name = data.name;
-    this.description = data.description;
-    this.slug = data.slug;
-    this.avatarUrl = data.avatar_url;
+    const { id, name, description, slug, avatar_url } = data;
+    this.id = id;
+    this.name = name;
+    this.description = description;
+    this.slug = slug;
+    this.avatarUrl = avatar_url;

Comment on lines +2 to +5
'@clerk/clerk-js': minor
'@clerk/types': minor
'@clerk/backend': patch
'@clerk/shared': patch
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Semver levels likely incorrect for public API/type renames — should be major.

Renaming exported types/classes from Commerce* → Billing* is a breaking change for consumers. Unless you ship full backwards-compatible aliases for all renamed public exports (and keep them in the public surface), bump these packages to major to avoid releasing a breaking change under minor/patch.

Apply this diff if there are breaking changes:

-'@clerk/clerk-js': minor
-'@clerk/types': minor
-'@clerk/backend': patch
-'@clerk/shared': patch
+'@clerk/clerk-js': major
+'@clerk/types': major
+'@clerk/backend': major
+'@clerk/shared': major

If you do have deprecation aliases covering all renamed exports, keep minor but explicitly state that in the description (see next comment).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'@clerk/clerk-js': minor
'@clerk/types': minor
'@clerk/backend': patch
'@clerk/shared': patch
'@clerk/clerk-js': major
'@clerk/types': major
'@clerk/backend': major
'@clerk/shared': major
🤖 Prompt for AI Agents
.changeset/yummy-snails-work.md around lines 2 to 5: The changeset lists
minor/patch bumps for packages where exported types/classes were renamed from
Commerce* to Billing*, which is a breaking API change for consumers; either
change the version bumps to major for any package that removed/renamed public
exports, or add and keep backwards-compatible aliases (exporting the old
Commerce* names re-exporting the new Billing* symbols) in the public surface so
the change truly remains non-breaking; update the changeset to use major for the
affected packages unless you add comprehensive deprecation aliases and then
document that in the changeset description.

Comment on lines +39 to 44
const { data: plans, total_count } = res as unknown as ClerkPaginatedResponse<BillingPlanJSON>;

return {
total_count,
data: plans.map(plan => new CommercePlan(plan)),
data: plans.map(plan => new BillingPlan(plan)),
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix inconsistent _fetch response handling (.response vs raw).

Some methods read from res?.response while others treat res as the payload. This will break at runtime if _fetch consistently wraps responses. Normalize to res?.response in all methods below.

@@
-    }).then(res => {
-      const { data: plans, total_count } = res as unknown as ClerkPaginatedResponse<BillingPlanJSON>;
+    }).then(res => {
+      const { data: plans, total_count } =
+        (res as any)?.response as ClerkPaginatedResponse<BillingPlanJSON>;
       return {
         total_count,
         data: plans.map(plan => new BillingPlan(plan)),
       };
     });
@@
-    })) as unknown as BillingPlanJSON;
+    ))?.response as unknown as BillingPlanJSON;
     return new BillingPlan(plan);
@@
-    }).then(res => {
-      const { data: payments, total_count } = res as unknown as ClerkPaginatedResponse<BillingPaymentJSON>;
+    }).then(res => {
+      const { data: payments, total_count } =
+        (res as any)?.response as ClerkPaginatedResponse<BillingPaymentJSON>;
       return {
         total_count,
         data: payments.map(payment => new BillingPayment(payment)),
       };
     });
@@
-    })) as unknown as BillingPaymentJSON;
+    ))?.response as unknown as BillingPaymentJSON;
     return new BillingPayment(paymentAttempt);

Also applies to: 53-55, 104-109, 119-121

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts around lines
39-44 (and similarly update lines 53-55, 104-109, 119-121), the code treats the
fetch result inconsistently by reading payload directly from res instead of from
res?.response; update each affected method to read the payload from
res?.response (e.g., const { data: plans, total_count } = res?.response as
ClerkPaginatedResponse<BillingPlanJSON>) and adjust subsequent
mappings/constructors accordingly so all methods consistently use res?.response
as the actual payload.

Comment on lines 1 to 8
import type {
AddPaymentSourceParams,
BillingInitializedPaymentSourceJSON,
BillingPaymentSourceJSON,
ClerkPaginatedResponse,
CommerceInitializedPaymentSourceJSON,
CommercePaymentSourceJSON,
GetPaymentSourcesParams,
InitializePaymentSourceParams,
} from '@clerk/types';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add explicit return types and remove any casts in request bodies.

Public APIs should have explicit return types; avoid any in bodies by typing the destructured rest.

 import type {
   AddPaymentSourceParams,
   BillingInitializedPaymentSourceJSON,
   BillingPaymentSourceJSON,
   ClerkPaginatedResponse,
   GetPaymentSourcesParams,
   InitializePaymentSourceParams,
+  BillingPaymentSourceResource,
 } from '@clerk/types';
@@
-export const initializePaymentSource = async (params: InitializePaymentSourceParams) => {
-  const { orgId, ...rest } = params;
+export const initializePaymentSource = async (
+  params: InitializePaymentSourceParams,
+): Promise<BillingInitializedPaymentSource> => {
+  const { orgId, ...body }: InitializePaymentSourceParams & { orgId?: string } = 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,
+      body,
     })
   )?.response as unknown as BillingInitializedPaymentSourceJSON;
   return new BillingInitializedPaymentSource(json);
 };
@@
-export const addPaymentSource = async (params: AddPaymentSourceParams) => {
-  const { orgId, ...rest } = params;
+export const addPaymentSource = async (params: AddPaymentSourceParams): Promise<BillingPaymentSource> => {
+  const { orgId, ...body }: AddPaymentSourceParams & { orgId?: string } = params;
@@
   const json = (
     await BaseResource._fetch({
       path: orgId ? `/organizations/${orgId}/commerce/payment_sources` : `/me/commerce/payment_sources`,
       method: 'POST',
-      body: rest as any,
+      body,
     })
   )?.response as unknown as BillingPaymentSourceJSON;
   return new BillingPaymentSource(json);
 };
@@
-export const getPaymentSources = async (params: GetPaymentSourcesParams) => {
-  const { orgId, ...rest } = params;
+export const getPaymentSources = async (
+  params: GetPaymentSourcesParams,
+): Promise<ClerkPaginatedResponse<BillingPaymentSourceResource>> => {
+  const { orgId, ...rest } = params;
@@
-  }).then(res => {
+  }).then(res => {
     const { data: paymentSources, total_count } =
       res?.response as unknown as ClerkPaginatedResponse<BillingPaymentSourceJSON>;
     return {
       total_count,
-      data: paymentSources.map(paymentSource => new BillingPaymentSource(paymentSource)),
+      data: paymentSources.map(paymentSource => new BillingPaymentSource(paymentSource)),
     };
   });
 };

Also applies to: 13-25, 27-38, 40-55

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts around
lines 1-8, 13-25, 27-38 and 40-55, the exported functions are missing explicit
return types and construct request bodies using `any` casts; update each
function signature to include the correct explicit return type (e.g.,
ClerkPaginatedResponse<BillingPaymentSourceJSON>, BillingPaymentSourceJSON,
BillingInitializedPaymentSourceJSON, etc. based on the operation) and eliminate
`any` by properly typing the destructured rest/params used to build the request
body (declare a typed object or interface for the body or cast the destructured
variable to the specific param type like
AddPaymentSourceParams/InitializePaymentSourceParams before using it), then
ensure the request call uses the strongly typed body and the function returns
the typed response.

Comment on lines +17 to 30
export class BillingCheckout extends BaseResource implements BillingCheckoutResource {
id!: string;
externalClientSecret!: string;
externalGatewayId!: string;
paymentSource?: CommercePaymentSource;
plan!: CommercePlan;
planPeriod!: CommerceSubscriptionPlanPeriod;
paymentSource?: BillingPaymentSource;
plan!: BillingPlan;
planPeriod!: BillingSubscriptionPlanPeriod;
planPeriodStart!: number | undefined;
status!: 'needs_confirmation' | 'completed';
totals!: CommerceCheckoutTotals;
totals!: BillingCheckoutTotals;
isImmediatePlanChange!: boolean;
freeTrialEndsAt!: Date | null;
payer!: CommercePayerResource;
payer!: BillingPayerResource;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add JSDoc for public resource and its fields.

Class BillingCheckout and its fields (paymentSource, plan, planPeriod, totals, payer, etc.) are public surface—add JSDoc.

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/CommerceCheckout.ts around lines 17 to
30, the public class BillingCheckout and its public fields lack JSDoc comments;
add concise JSDoc blocks above the class and each exported/public field
(paymentSource, plan, planPeriod, planPeriodStart, status, totals,
isImmediatePlanChange, freeTrialEndsAt, payer, etc.) describing their purpose,
types/allowed values (e.g., status union), nullable/optional nature, and any
units or semantics (e.g., timestamps are epoch seconds), keeping descriptions
short and consistent with project style.

Comment on lines +14 to 22
export class BillingPaymentSource extends BaseResource implements BillingPaymentSourceResource {
id!: string;
last4!: string;
paymentMethod!: string;
cardType!: string;
isDefault!: boolean;
isRemovable!: boolean;
status!: CommercePaymentSourceStatus;
status!: BillingPaymentSourceStatus;
walletType: string | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add JSDoc for this public resource.

Per guidelines, public APIs need JSDoc (class summary and field docs: id, last4, paymentMethod, etc.).

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/CommercePaymentSource.ts around lines 14
to 22, the public BillingPaymentSource class and its fields lack JSDoc; add a
class-level JSDoc summary describing this resource (what it represents and when
it's used) and add JSDoc comments for each public field (id, last4,
paymentMethod, cardType, isDefault, isRemovable, status, walletType) describing
the value, type, and whether the field is optional or possible enum values
(e.g., status enum), keeping comments brief and following project JSDoc style.

Comment on lines +30 to 31
planPeriod: BillingSubscriptionPlanPeriod;
planId: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Public context prop now uses Billing plan period — OK; check downstream uses.
Run a sweep to catch lingering CommerceSubscriptionPlanPeriod or mismatched types.


🏁 Script executed:

#!/bin/bash
# Find old plan-period type and usages of UseCheckoutOptions.planPeriod
rg -nP "CommerceSubscriptionPlanPeriod|UseCheckoutOptions\s*[\}\w\W]*planPeriod" -C3

Length of output: 2860


Replace remaining CommerceSubscriptionPlanPeriod usages with BillingSubscriptionPlanPeriod

Found 4 matches in tests — update the import/usages so types align with the public context change.

  • packages/shared/src/react/hooks/tests/useCheckout.type.spec.ts — lines 6, 27, 36, 54
🤖 Prompt for AI Agents
In packages/shared/src/react/contexts.tsx around lines 30 to 31, the context
uses BillingSubscriptionPlanPeriod for planPeriod but tests still reference
CommerceSubscriptionPlanPeriod; update the four test occurrences in
packages/shared/src/react/hooks/__tests__/useCheckout.type.spec.ts (lines 6, 27,
36, 54) to import and use BillingSubscriptionPlanPeriod instead of
CommerceSubscriptionPlanPeriod, and search/replace any remaining
CommerceSubscriptionPlanPeriod type imports/usages in the test file to ensure
types align with the public context change.

Comment on lines +30 to 31
type CheckoutProperties = Omit<RemoveFunctions<BillingCheckoutResource>, 'pathRoot' | 'status'>;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix status duplication/type mismatch in CheckoutProperties

CheckoutProperties omits status, but the null-state object includes status: null and the destructured rest still carries status. This can cause excess-property issues and duplicate keys when composing checkout. Remove status from the null object and exclude it during destructuring.

 type CheckoutProperties = Omit<RemoveFunctions<BillingCheckoutResource>, 'pathRoot' | 'status'>;
@@
   const properties = useMemo<CheckoutProperties | ForceNull<CheckoutProperties>>(() => {
     if (!managerProperties.checkout) {
       return {
         id: null,
         externalClientSecret: null,
         externalGatewayId: null,
-        status: null,
         totals: null,
         isImmediatePlanChange: null,
         planPeriod: null,
         plan: null,
         paymentSource: null,
         freeTrialEndsAt: null,
         payer: null,
       };
     }
     const {
       // eslint-disable-next-line @typescript-eslint/unbound-method
       reload,
       confirm,
       pathRoot,
+      status: _status, // exclude to avoid duplication; status is provided from managerProperties below
       // All the above need to be removed from the properties
       ...rest
     } = managerProperties.checkout;
     return rest;
   }, [managerProperties.checkout]);

Also applies to: 103-128

🤖 Prompt for AI Agents
In packages/shared/src/react/hooks/useCheckout.ts around lines 30-31 and again
where the null-state object is created/used around lines 103-128, the
CheckoutProperties type omits 'status' but the null-state object still sets
status: null and destructuring leaves status in rest, causing duplicate
keys/extra-property type errors; remove the status property from the null-state
object and also exclude status during destructuring (e.g., omit it from rest) so
the composed checkout object does not include a duplicated or mismatched status
field.

Comment on lines 156 to 159
initializePaymentSource: (
params: Exclude<InitializePaymentSourceParams, 'orgId'>,
) => Promise<CommerceInitializedPaymentSourceResource>;
) => Promise<BillingInitializedPaymentSourceResource>;
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use Omit instead of Exclude to remove orgId from param types.

Exclude does not remove object keys; it filters union members. This keeps orgId instead of removing it.

Apply:

-  initializePaymentSource: (
-    params: Exclude<InitializePaymentSourceParams, 'orgId'>,
-  ) => Promise<BillingInitializedPaymentSourceResource>;
+  initializePaymentSource: (
+    params: Omit<InitializePaymentSourceParams, 'orgId'>,
+  ) => Promise<BillingInitializedPaymentSourceResource>;
...
-  addPaymentSource: (params: Exclude<AddPaymentSourceParams, 'orgId'>) => Promise<BillingPaymentSourceResource>;
+  addPaymentSource: (params: Omit<AddPaymentSourceParams, 'orgId'>) => Promise<BillingPaymentSourceResource>;
...
-  getPaymentSources: (
-    params: Exclude<GetPaymentSourcesParams, 'orgId'>,
-  ) => Promise<ClerkPaginatedResponse<BillingPaymentSourceResource>>;
+  getPaymentSources: (
+    params: Omit<GetPaymentSourcesParams, 'orgId'>,
+  ) => Promise<ClerkPaginatedResponse<BillingPaymentSourceResource>>;

Also applies to: 167-167, 176-179

🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 156-159 (and also at 167 and
176-179), the type manipulation uses Exclude to remove orgId from parameter
types but Exclude filters union members rather than omitting object keys;
replace Exclude<..., 'orgId'> with Omit<..., 'orgId'> for these function
parameter types so the orgId property is actually removed from the resulting
param type, updating all occurrences at the noted lines.

💡 Verification agent

🧩 Analysis chain

Repo-wide verification helper.

Check for other Exclude<..., 'orgId'>, missing BillingStatementGroup.id, and leftover @Commerce.

Also applies to: 167-167, 176-179, 752-765, 807-809, 1225-1231


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Find Exclude<..., 'orgId'> misuse:"
rg -nP "Exclude<[^>]+,\s*['\"]orgId['\"]" -g '!**/dist/**' -g '!**/build/**'

echo -e "\nFind BillingStatementGroup definitions/usages:"
rg -nP -C3 '(interface|class)\s+BillingStatementGroup\b' packages

echo -e "\nLeftover @COMMERCE tags:"
rg -n "@COMMERCE" -n

echo -e "\nCheck freeTrialEndsAt doc mentions of 'Unix timestamp':"
rg -nP -C2 'freeTrialEndsAt.*Unix timestamp' packages/types/src

Length of output: 183


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "PWD: $(pwd)"
echo "Git branch: $(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
echo "Top-level entries:"
ls -la | sed -n '1,200p' || true
echo "Tracked file count: $(git ls-files 2>/dev/null | wc -l || true)"

if command -v rg >/dev/null 2>&1; then
  echo "Using rg (ripgrep)"

  echo -e "\nFind Exclude<..., 'orgId'> misuse:"
  rg -nP --hidden --no-ignore-vcs "Exclude<[^>]+,\s*['\"]orgId['\"]" || echo "no matches"

  echo -e "\nFind BillingStatementGroup definitions/usages (interface|class|type) with context:"
  rg -nP -C3 --hidden --no-ignore-vcs "(interface|class|type)\s+BillingStatementGroup\b" || echo "no matches"
  echo -e "\nAll occurrences of BillingStatementGroup:"
  rg -n --hidden --no-ignore-vcs "BillingStatementGroup" || echo "no matches"

  echo -e "\nLeftover @COMMERCE tags:"
  rg -n --hidden --no-ignore-vcs "@COMMERCE" || echo "no matches"

  echo -e "\nCheck freeTrialEndsAt doc mentions of 'Unix timestamp':"
  rg -nP -C2 --hidden --no-ignore-vcs "freeTrialEndsAt.*Unix timestamp" || echo "no matches"
else
  echo "rg not found; falling back to git grep"

  echo -e "\nFind Exclude<..., 'orgId'> misuse:"
  git grep -n -E "Exclude<[^>]+,\s*['\"]orgId['\"]" || echo "no matches"

  echo -e "\nFind BillingStatementGroup definitions/usages (interface|class|type) with context:"
  git grep -n -E "(interface|class|type)\s+BillingStatementGroup\b" || echo "no matches"
  echo -e "\nAll occurrences of BillingStatementGroup:"
  git grep -n "BillingStatementGroup" || echo "no matches"

  echo -e "\nLeftover @COMMERCE tags:"
  git grep -n "@COMMERCE" || echo "no matches"

  echo -e "\nCheck freeTrialEndsAt doc mentions of 'Unix timestamp':"
  git grep -n -E "freeTrialEndsAt.*Unix timestamp" || echo "no matches"
fi

Length of output: 6599


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== commerce.ts (lines 140-190) ==="
sed -n '140,190p' packages/types/src/commerce.ts || true

echo -e "\n=== commerce.ts (lines 740-780) ==="
sed -n '740,780p' packages/types/src/commerce.ts || true

echo -e "\n=== json.ts (lines 720-820) ==="
sed -n '720,820p' packages/types/src/json.ts || true

echo -e "\n=== clerk-js CommerceStatement.ts (lines 1-120) ==="
sed -n '1,120p' packages/clerk-js/src/core/resources/CommerceStatement.ts || true

echo -e "\n=== Plans.tsx around TODOs (lines 1-240) ==="
sed -n '1,240p' packages/clerk-js/src/ui/contexts/components/Plans.tsx || true

echo -e "\n=== CommerceSubscription.ts around TODO (lines 1-120) ==="
sed -n '1,120p' packages/clerk-js/src/core/resources/CommerceSubscription.ts || true

echo -e "\n=== rspack.config.js around TODO (lines 1-140) ==="
sed -n '1,140p' packages/clerk-js/rspack.config.js || true

Length of output: 25897


Critical: add missing BillingStatementGroup.id; audit Exclude<'orgId'> uses; remove @Commerce TODOs

  • BillingStatementGroup is missing an id field in the types: add id: string to packages/types/src/json.ts (interface BillingStatementGroupJSON) and packages/types/src/commerce.ts (interface BillingStatementGroup). clerk-js class BillingStatementGroup (packages/clerk-js/src/core/resources/CommerceStatement.ts) expects data.id.
  • Exclude<..., 'orgId'> occurrences found in packages/types/src/commerce.ts for methods initializePaymentSource, addPaymentSource, getPaymentSources — confirm removal of orgId is intentional (or replace with clearer Omit<> usage).
  • Leftover @Commerce TODOs to clean up in: packages/types/src/json.ts, packages/types/src/commerce.ts, packages/clerk-js/src/ui/contexts/components/Plans.tsx, packages/clerk-js/src/core/resources/CommerceSubscription.ts, packages/clerk-js/rspack.config.js.
  • freeTrialEndsAt 'Unix timestamp' doc check: no matches found.
🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 156-159 and related types, add
the missing id: string to the BillingStatementGroup interface (and add the
corresponding id: string to packages/types/src/json.ts interface
BillingStatementGroupJSON) because clerk-js expects data.id; audit every
occurrence of Exclude<..., 'orgId'> in packages/types/src/commerce.ts
(initializePaymentSource, addPaymentSource, getPaymentSources) and replace with
Omit<..., 'orgId'> or explicitly document/confirm that orgId must be omitted to
make intentions clear; remove the leftover @COMMERCE TODO comments across
packages/types/src/json.ts, packages/types/src/commerce.ts,
packages/clerk-js/src/ui/contexts/components/Plans.tsx,
packages/clerk-js/src/core/resources/CommerceSubscription.ts, and
packages/clerk-js/rspack.config.js so the codebase no longer contains stale
TODOs; run type checks and unit tests to ensure the added id fields and
signature changes don’t break usages (notably
packages/clerk-js/src/core/resources/CommerceStatement.ts which reads data.id).

Comment on lines +651 to 652
subscriptionItem: BillingSubscriptionItemResource;
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Should subscriptionItem be optional for checkout payments?

For chargeType = 'checkout' there may be no subscription item.

Run to find unchecked usages:


🏁 Script executed:

#!/bin/bash
rg -nP -C3 '\bsubscriptionItem\b' packages --type ts --type tsx

Length of output: 27


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for 'subscriptionItem' in packages (.ts/.tsx files)..."
rg -nP -C3 '\bsubscriptionItem\b' packages -g '**/*.ts' -g '**/*.tsx' || true

echo
echo "Printing context around lines 630-670 in packages/types/src/commerce.ts if it exists..."
if [ -f packages/types/src/commerce.ts ]; then
  nl -ba packages/types/src/commerce.ts | sed -n '630,670p'
else
  echo "packages/types/src/commerce.ts not found"
fi

Length of output: 14857


Make subscriptionItem optional and guard parsing/usage

chargeType='checkout' can omit subscription_item; current types and parsing assume it's always present and may throw at runtime.

  • packages/types/src/commerce.ts (line ~651): change
    subscriptionItem: BillingSubscriptionItemResource;
    → subscriptionItem?: BillingSubscriptionItemResource;
  • packages/clerk-js/src/core/resources/CommercePayment.ts (declaration ~line 22, constructor ~line 42): make the property optional and guard the assignment:
    subscriptionItem?: BillingSubscriptionItemResource;
    this.subscriptionItem = data.subscription_item ? new BillingSubscriptionItem(data.subscription_item) : undefined;
  • Audit UI code that dereferences subscriptionItem without checks (e.g. packages/clerk-js/src/ui/components/Statements/StatementPage.tsx — item.subscriptionItem.plan.name / related uses) and add conditional rendering or null-checks. PaymentAttemptPage already handles undefined.
🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 651-652, change subscriptionItem:
BillingSubscriptionItemResource; to subscriptionItem?:
BillingSubscriptionItemResource; and in
packages/clerk-js/src/core/resources/CommercePayment.ts (declaration around line
22 and constructor around line 42) make the property optional
(subscriptionItem?: BillingSubscriptionItemResource;) and guard the assignment
so you only construct BillingSubscriptionItem when data.subscription_item is
present (assign undefined otherwise). Also update UI usages that directly
dereference subscriptionItem (e.g.
packages/clerk-js/src/ui/components/Statements/StatementPage.tsx where code
accesses item.subscriptionItem.plan.name) to add null/undefined checks or
conditional rendering before accessing plan or name; PaymentAttemptPage already
handles undefined so leave it unchanged.

Comment on lines +752 to 765
* The `BillingStatementGroup` type represents a group of payment items within a statement.
*
* @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to pin the SDK version and the clerk-js version to avoid breaking changes.
*/
export interface CommerceStatementGroup {
export interface BillingStatementGroup {
/**
* The date and time when this group of payment items was created or last updated.
*/
timestamp: Date;
/**
* An array of payment resources that belong to this group.
*/
items: CommercePaymentResource[];
items: BillingPaymentResource[];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add id to BillingStatementGroup to match runtime shape.

clerk-js BillingStatementGroup includes id; types here omit it.

 export interface BillingStatementGroup {
+  /**
+   * Stable identifier of the group.
+   */
+  id: string;
   /**
    * The date and time when this group of payment items was created or last updated.
    */
   timestamp: Date;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* The `BillingStatementGroup` type represents a group of payment items within a statement.
*
* @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to pin the SDK version and the clerk-js version to avoid breaking changes.
*/
export interface CommerceStatementGroup {
export interface BillingStatementGroup {
/**
* The date and time when this group of payment items was created or last updated.
*/
timestamp: Date;
/**
* An array of payment resources that belong to this group.
*/
items: CommercePaymentResource[];
items: BillingPaymentResource[];
}
* The `BillingStatementGroup` type represents a group of payment items within a statement.
*
* @experimental This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to pin the SDK version and the clerk-js version to avoid breaking changes.
*/
export interface BillingStatementGroup {
/**
* Stable identifier of the group.
*/
id: string;
/**
* The date and time when this group of payment items was created or last updated.
*/
timestamp: Date;
/**
* An array of payment resources that belong to this group.
*/
items: BillingPaymentResource[];
}
🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 752 to 765, the
BillingStatementGroup interface is missing the runtime id property; add an id:
string field to the interface (alongside timestamp and items) so the TypeScript
type matches the runtime shape returned by clerk-js.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/react/src/components/__tests__/PlanDetailsButton.test.tsx (3)

3-3: Remove redundant type import (will be unused after dropping the cast).

BillingPayerResourceType isn’t needed if you rely on the string literal type for forPayerType.

-import type { BillingPayerResourceType, BillingPlanResource, Theme } from '@clerk/types';
+import type { BillingPlanResource, Theme } from '@clerk/types';

56-56: Drop unnecessary cast on forPayerType.

The literal 'user' already narrows to the union; the cast is noise and can mask type drift.

-  forPayerType: 'user' as BillingPayerResourceType,
+  forPayerType: 'user',

31-65: Optional: Use satisfies to keep literals narrow and avoid widening.

This preserves literal types in the mock while still validating the shape against BillingPlanResource.

-const mockPlanResource: BillingPlanResource = {
+const mockPlanResource = {
   id: 'plan_123',
   name: 'Test Plan',
   fee: {
     amount: 1000,
     amountFormatted: '10.00',
     currencySymbol: '$',
     currency: 'USD',
   },
   annualMonthlyFee: {
     amount: 833,
     amountFormatted: '8.33',
     currencySymbol: '$',
     currency: 'USD',
   },
   annualFee: {
     amount: 10000,
     amountFormatted: '100.00',
     currencySymbol: '$',
     currency: 'USD',
   },
   description: 'Test Plan Description',
   hasBaseFee: true,
   isRecurring: true,
   isDefault: false,
-  forPayerType: 'user',
+  forPayerType: 'user',
   publiclyVisible: true,
   slug: 'test-plan',
   avatarUrl: 'https://example.com/avatar.png',
   freeTrialDays: 0,
   freeTrialEnabled: false,
   features: [],
   pathRoot: '',
   reload: vi.fn(),
-};
+} satisfies BillingPlanResource;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dd915af and a0a88ad.

📒 Files selected for processing (3)
  • .changeset/yummy-snails-work.md (1 hunks)
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx (3 hunks)
  • packages/react/src/isomorphicClerk.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/yummy-snails-work.md
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/react/src/isomorphicClerk.ts
  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/*.test.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.test.{jsx,tsx}: Use React Testing Library
Test component behavior, not implementation
Use proper test queries
Implement proper test isolation
Use proper test coverage
Test component interactions
Use proper test data
Implement proper test setup
Use proper test cleanup
Implement proper test assertions
Use proper test structure

Files:

  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/react/src/components/__tests__/PlanDetailsButton.test.tsx
🧬 Code graph analysis (2)
packages/react/src/isomorphicClerk.ts (1)
packages/types/src/commerce.ts (1)
  • BillingNamespace (20-100)
packages/react/src/components/__tests__/PlanDetailsButton.test.tsx (1)
packages/types/src/commerce.ts (2)
  • BillingPlanResource (209-351)
  • BillingPayerResourceType (110-110)
🔇 Additional comments (1)
packages/react/src/isomorphicClerk.ts (1)

19-19: Type rename import looks correct — confirm no lingering Commerce usages or add compat alias*

  • packages/types/src/commerce.ts:20 exports interface BillingNamespace.
  • No compat alias found (e.g. export type CommerceBillingNamespace = BillingNamespace).
  • rg reported "unrecognized file type: tsx" — the prior search may be incomplete; re-run a broad search (eg. rg -nP '\bCommerce[A-Z]\w+\b' -S) to verify no remaining Commerce* identifiers.
  • Action: either add the compat alias in packages/types/src/commerce.ts or confirm all Commerce* usages were migrated and removed.

Comment on lines 112 to 115
client: ClientResource | undefined;
billing: CommerceBillingNamespace | undefined;
billing: BillingNamespace | undefined;
apiKeys: APIKeysNamespace | undefined;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add JSDoc for public billing property (meets project guidelines and signals beta status)

Per guidelines, public APIs must have JSDoc. Recommend documenting the experimental nature here.

   client: ClientResource | undefined;
-  billing: BillingNamespace | undefined;
+  /**
+   * @experimental Billing is in public beta and its API may change without notice.
+   * Consider pinning clerk-js and SDK versions to avoid unexpected breakage.
+   */
+  billing: BillingNamespace | undefined;
   apiKeys: APIKeysNamespace | undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
client: ClientResource | undefined;
billing: CommerceBillingNamespace | undefined;
billing: BillingNamespace | undefined;
apiKeys: APIKeysNamespace | undefined;
};
client: ClientResource | undefined;
/**
* @experimental Billing is in public beta and its API may change without notice.
* Consider pinning clerk-js and SDK versions to avoid unexpected breakage.
*/
billing: BillingNamespace | undefined;
apiKeys: APIKeysNamespace | undefined;
};
🤖 Prompt for AI Agents
In packages/react/src/isomorphicClerk.ts around lines 112 to 115, the public
property "billing" lacks JSDoc; add a JSDoc comment above the billing
declaration that documents the property, marks it as public and
experimental/beta (e.g., "@public" and "@experimental" or "Beta" in the
description), and briefly describes its purpose/shape to meet project guidelines
for public APIs.

Comment on lines +725 to 727
get billing(): BillingNamespace | undefined {
return this.clerkjs?.billing;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add JSDoc for billing getter (public API) with @experimental note

Keeps runtime API docs consistent with @clerk/types and repo standards.

-  get billing(): BillingNamespace | undefined {
+  /**
+   * Billing namespace for client-side operations.
+   * @experimental The Billing feature is in public beta and may change.
+   */
+  get billing(): BillingNamespace | undefined {
     return this.clerkjs?.billing;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get billing(): BillingNamespace | undefined {
return this.clerkjs?.billing;
}
/**
* Billing namespace for client-side operations.
* @experimental The Billing feature is in public beta and may change.
*/
get billing(): BillingNamespace | undefined {
return this.clerkjs?.billing;
}
🤖 Prompt for AI Agents
In packages/react/src/isomorphicClerk.ts around lines 725 to 727, add a JSDoc
block above the billing getter describing the getter, its return type
(BillingNamespace | undefined), and mark it with an @experimental tag to match
@clerk/types and repo standards; keep the description concise (what it returns
and when it can be undefined) and include the @returns annotation, ensuring
formatting and wording are consistent with other public API JSDoc comments in
the repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants