Skip to content

Conversation

@alexisintech
Copy link
Member

@alexisintech alexisintech commented Aug 27, 2025

Description

Adds JSDoc comments to many commerce-related classes and types/interfaces.
Exports the Feature type from our backend resource

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
    • Backend SDK now publicly exposes Feature and re-exports standardized CommerceMoneyAmount.
    • Commerce models (plans, subscriptions, subscription items, checkout sessions, payment sources) expose additional IDs, richer billing/money fields, and payment-source operations (remove, makeDefault).
  • Documentation
    • Clarified commerce resource descriptions and timestamp wording, improved doc link handling, and added JSDoc for Feature.

@changeset-bot
Copy link

changeset-bot bot commented Aug 27, 2025

🦋 Changeset detected

Latest commit: 974fb9d

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

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

@vercel
Copy link

vercel bot commented Aug 27, 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 Aug 29, 2025 6:33pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

Walkthrough

Exports Feature from backend resources; replaces local CommerceMoneyAmount types with imports from @clerk/types; expands backend commerce resource shapes and JSON mappings (CommercePlan, CommerceSubscriptionItem, CommerceSubscription); adds payment-source operations and subscription cancel surface; adds a docs link rewrite for commerce-money-amount and a changeset.

Changes

Cohort / File(s) Summary
Release metadata
./.changeset/three-knives-play.md
Adds a changeset marking patch releases for @clerk/backend and @clerk/types with summary "export feature type from backend resource".
Docs tooling
.typedoc/custom-plugin.mjs
Adds LINK_REPLACEMENTS entry for commerce-money-amount to rewrite relative links to /docs/references/javascript/types/commerce-money-amount (anchors preserved).
Backend commerce resources
packages/backend/src/api/resources/CommercePlan.ts, packages/backend/src/api/resources/CommerceSubscription.ts, packages/backend/src/api/resources/CommerceSubscriptionItem.ts
Remove inline CommerceMoneyAmount definitions and import type { CommerceMoneyAmount } from '@clerk/types'; expand class public properties (monetary fields, plan details, timestamps, payer info, features); update constructors and fromJSON mappings; refine JSDoc; CommerceSubscription constructor now includes id and status.
Backend resource: Feature
packages/backend/src/api/resources/Feature.ts
Add class- and parameter-level JSDoc for Feature; runtime signature unchanged.
Backend exports
packages/backend/src/api/resources/index.ts, packages/backend/src/index.ts
Re-export Feature from API resources and add Feature to the package public exports (type surface extended).
Public commerce types
packages/types/src/commerce.ts
Extend public commerce types: add id and snapshot accessor to CommerceFeatureResource; add id/payer and planPeriodStart? to CommerceCheckoutResource; extend CommercePaymentSourceResource with id, card/payment fields, status, walletType and remove/makeDefault methods; expand CommerceSubscriptionResource with lifecycle/timestamps, nextPayment, amount/credit, cancel, and isFreeTrial.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as App/SDK Consumer
  participant SDK as Backend SDK (resources/types)
  participant API as Backend API

  rect rgba(220,255,220,0.12)
    note right of Dev: Remove payment source (new method)
    Dev->>SDK: paymentSource.remove(params?)
    SDK->>API: DELETE /payment_sources/:id (params)
    API-->>SDK: 200/204 + DeletedObjectResource
    SDK-->>Dev: Promise<DeletedObjectResource>
  end

  rect rgba(220,220,255,0.12)
    note right of Dev: Make default payment source (new method)
    Dev->>SDK: paymentSource.makeDefault(params?)
    SDK->>API: POST /payment_sources/:id/default (params)
    API-->>SDK: 204 No Content
    SDK-->>Dev: Promise<null>
  end

  rect rgba(255,240,220,0.12)
    note right of Dev: Cancel subscription (new method surface)
    Dev->>SDK: subscription.cancel(params?)
    SDK->>API: POST /subscriptions/:id/cancel (params)
    API-->>SDK: 200/204 + DeletedObjectResource
    SDK-->>Dev: Promise<DeletedObjectResource>
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hopped through types and docs so spry,
Coin shapes now shared beneath the sky,
A Feature stepped out with a tiny cry,
Payment tricks added — remove or make fly,
Rabbit nibbles on code and winks goodbye. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch aa/update-commerce-typedoc

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Aug 27, 2025

Open in StackBlitz

@clerk/agent-toolkit

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

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/dev-cli

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

@clerk/elements

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

@clerk/clerk-expo

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

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/clerk-react

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

@clerk/react-router

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

@clerk/remix

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/themes

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

@clerk/types

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

@clerk/upgrade

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

@clerk/vue

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

commit: 974fb9d

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: 4

Caution

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

⚠️ Outside diff range comments (1)
packages/types/src/commerce.ts (1)

1248-1300: Update doc comment for freeTrialEndsAt in CommerceCheckoutResource

The documentation currently describes freeTrialEndsAt as a Unix timestamp, but the type is Date | null. To accurately reflect the runtime shape and clarify when the value can be null, please update the doc comment.

• File: packages/types/src/commerce.ts
Lines: ~1296–1298

   /**
-  * Unix timestamp (milliseconds) when the free trial ends.
+  * The date when the free trial ends, or `null` if no trial is active.
   */
   freeTrialEndsAt: Date | null;
🧹 Nitpick comments (6)
.changeset/three-knives-play.md (2)

2-3: Semver: consider minor instead of patch for new public exports/types

Re-exporting Feature and widening the public type surface in @clerk/types are additive features. Recommend minor bumps to reflect API surface growth.

Proposed diff:

----
-'@clerk/backend': patch
-'@clerk/types': patch
+'@clerk/backend': minor
+'@clerk/types': minor
----

6-6: Broaden the changeset summary to cover all public surface additions

Mention the Feature export and the additional commerce-related type updates so the release notes are accurate.

-export feature type from backend resource
+Export `Feature` from backend resource and document commerce resources; add `CommerceMoneyAmount` docs and widen commerce types (`Checkout.id`, `PaymentSource.remove/makeDefault`, `Feature.__internal_toSnapshot`).
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (1)

31-38: Align nextPayment.amount type with CommerceMoneyAmount for consistency

CommerceSubscription.nextPayment.amount uses CommerceMoneyAmount but CommerceSubscriptionItem.nextPayment.amount is a number. Consider using CommerceMoneyAmount here for parity and to avoid currency/format ambiguity.

Proposed change:

-  readonly nextPayment: {
-    /**
-     * The amount of the next payment.
-     */
-    amount: number;
-    /**
-     * Unix timestamp (milliseconds) when the next payment is scheduled.
-     */
-    date: number;
-  } | null,
+  readonly nextPayment: {
+    /**
+     * The amount of the next payment.
+     */
+    amount: CommerceMoneyAmount;
+    /**
+     * Unix timestamp (milliseconds) when the next payment is scheduled.
+     */
+    date: number;
+  } | null,

And in fromJSON:

-      data.next_payment,
+      data.next_payment
+        ? {
+            amount: formatAmountJSON(data.next_payment.amount)!,
+            date: data.next_payment.date,
+          }
+        : null,

If the current number is intentional, please document units (e.g., minor units) to remove ambiguity.

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

8-27: Optional: mark constructor fields as explicitly public for public API clarity

House style often prefers explicit public on public APIs.

-  constructor(
+  constructor(
     /**
      * The unique identifier for the feature.
      */
-    readonly id: string,
+    public readonly id: string,
     /**
      * The name of the feature.
      */
-    readonly name: string,
+    public readonly name: string,
     /**
      * The description of the feature.
      */
-    readonly description: string,
+    public readonly description: string,
     /**
      * The URL-friendly identifier of the feature.
      */
-    readonly slug: string,
+    public readonly slug: string,
     /**
      * The URL of the feature's avatar image.
      */
-    readonly avatarUrl: string,
+    public readonly avatarUrl: string,
   ) {}
packages/backend/src/api/resources/CommercePlan.ts (1)

90-98: Type the helper return and param explicitly.

Improves safety and keeps API aligned with CommerceMoneyAmount.

-  static fromJSON(data: CommercePlanJSON): CommercePlan {
-    const formatAmountJSON = (fee: CommercePlanJSON['fee']) => {
+  static fromJSON(data: CommercePlanJSON): CommercePlan {
+    const formatAmountJSON = (fee: CommercePlanJSON['fee']): CommerceMoneyAmount => {
       return {
         amount: fee.amount,
         amountFormatted: fee.amount_formatted,
         currency: fee.currency,
         currencySymbol: fee.currency_symbol,
       };
     };
packages/types/src/commerce.ts (1)

1129-1148: Clarify amountFormatted example.

Use a clearly formatted example to avoid ambiguity.

-   * The amount as a formatted string. For example, `10` for $10.00.
+   * The amount as a formatted string. For example, `10.00` for $10.00 (currency symbol may be omitted).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 87b1b44 and 767a166.

📒 Files selected for processing (9)
  • .changeset/three-knives-play.md (1 hunks)
  • .typedoc/custom-plugin.mjs (1 hunks)
  • packages/backend/src/api/resources/CommercePlan.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3 hunks)
  • packages/backend/src/api/resources/Feature.ts (1 hunks)
  • packages/backend/src/api/resources/index.ts (1 hunks)
  • packages/backend/src/index.ts (1 hunks)
  • packages/types/src/commerce.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
**/*.{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/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
packages/**/index.{js,ts}

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

Use tree-shaking friendly exports

Files:

  • packages/backend/src/api/resources/index.ts
  • packages/backend/src/index.ts
**/*.{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/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
**/*.{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/backend/src/api/resources/index.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/index.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/types/src/commerce.ts
**/index.ts

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

Use index.ts files for clean imports but avoid deep barrel exports

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/backend/src/api/resources/index.ts
  • packages/backend/src/index.ts
.changeset/**

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

Automated releases must use Changesets.

Files:

  • .changeset/three-knives-play.md
🧬 Code graph analysis (3)
packages/backend/src/api/resources/Feature.ts (1)
packages/backend/src/index.ts (1)
  • Feature (122-122)
packages/backend/src/api/resources/CommercePlan.ts (1)
packages/types/src/commerce.ts (1)
  • CommerceMoneyAmount (1131-1148)
packages/types/src/commerce.ts (4)
packages/types/src/resource.ts (1)
  • ClerkResource (8-21)
packages/types/src/snapshots.ts (1)
  • CommerceFeatureJSONSnapshot (194-194)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (39-58)
packages/backend/src/api/resources/CommercePlan.ts (1)
  • CommerceMoneyAmount (8-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
.typedoc/custom-plugin.mjs (1)

58-58: It looks like searching the repo didn’t reveal any MD/MDX files referencing “commerce-money-amount,” and we need to inspect the plugin’s heavy lifting. Since the docs content lives elsewhere (not in this plugin package), we can’t confirm end-to-end purely from here. Please manually verify that after generating the MDX, any commerce-money-amount.mdx links are indeed rewritten to /docs/references/javascript/types/commerce-money-amount (including any anchors).

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

24-24: Timestamp wording improvements LGTM

Clear, consistent “Unix timestamp (milliseconds)” phrasing across fields. No changes requested.

Also applies to: 53-55, 57-59, 61-63, 65-67, 69-71, 73-75


7-8: Replace TODO with the real Backend API docs URL
Avoid shipping a broken reference. In packages/backend/src/api/resources/CommerceSubscriptionItem.ts (lines 7–8), update the JSDoc link from (TODO) to the published Clerk Backend API overview page URL.

  • Locate the exact Backend API overview URL in the Clerk documentation (e.g. on docs.clerk.com)
  • Replace the (TODO) placeholder with that URL (keeping target='_blank')
packages/backend/src/api/resources/Feature.ts (1)

3-5: JSDoc added — clear and helpful

Concise class description reads well. No issues.

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

23-29: Timestamp phrasing LGTM

Wording now clearly indicates “when ... was created/last updated” in milliseconds.


6-7: Replace Backend API docs placeholder in JSDoc
The TODO in the [Backend API](TODO) link needs to be swapped out for the real CommerceSubscription Backend API docs URL (e.g. https://docs.clerk.com/reference/backend-api/resources/commerce-subscription){target: '_blank'}. This same placeholder appears in SubscriptionItem—please update both to point at the official docs.

packages/types/src/commerce.ts (4)

7-11: LGTM: Optional orgId doc is clear.


1181-1185: LGTM: Statement totals aliasing.

ESLint suppression is appropriate here.


415-443: CommerceFeatureResource implementation confirmed
The CommerceFeatureResource interface’s new __internal_toSnapshot member is implemented in the runtime and referenced in tests, so there’s no drift or missing implementation.

• packages/clerk-js/src/core/resources/CommerceFeature.ts:
export class CommerceFeature … implements CommerceFeatureResource
• defines public __internal_toSnapshot(): CommerceFeatureJSONSnapshot

• UI tests in clerk-js (e.g. SubscriptionDetails.test.tsx, PlanDetails.test.tsx, PricingTable.test.tsx) mock __internal_toSnapshot on feature objects to drive component tests.

No further action required.


540-590: Runtime implementations verified for remove and makeDefault

The CommercePaymentSource class includes the required methods matching the interface:

  • public async remove(params?: RemovePaymentSourceParams) (lines 46–58)
  • public async makeDefault(params?: MakeDefaultPaymentSourceParams) (lines 60–63)

No further changes are needed.

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

63-64: LGTM: Re-exporting Feature is consistent with existing resource barrel.

No circular ref risk introduced by this addition alone.

packages/backend/src/index.ts (1)

121-123: LGTM: Publicly exporting Feature type.

Matches the resource barrel and the changeset intent.

Comment on lines 146 to 151
/**
* @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" />
* ```
* The billing period for the plan.
*
* @inline
*/
export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';
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

LGTM: Period enum doc.

Consider confirming naming consistency: 'annual' here vs any 'year'/'yearly' elsewhere.


🏁 Script executed:

#!/bin/bash
# Check for alternate period literals that could drift from 'annual'|'month'
rg -nP -C1 "(?<quote>'|\")(?:(year|yearly))\k<quote>" --type=ts

Length of output: 713


Standardize subscription period literals across the codebase

There’s a mismatch between the type CommerceSubscriptionPlanPeriod ('month' | 'annual') and usages elsewhere that expect a 'year' literal. If left unaddressed, this will lead to missing translation keys (e.g. commerce.year vs commerce.annual) or logic errors. Please align these values consistently:

• In packages/types/src/commerce.ts

export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';

Either rename the second member to 'year'

• In packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (line 548)

{t(localizationKeys(`commerce.${subscription.planPeriod === 'month' ? 'month' : 'year'}`))}

…or update this to branch on 'annual' and load commerce.annual.

• In packages/shared/src/react/commerce.tsx (line 258)

recurringPaymentIntervalUnit: checkout.planPeriod === 'annual' ? 'year' : 'month',

Mirror whatever literal you choose for the type.

Please pick one naming convention—either use 'year' throughout (and rename the type) or use 'annual' throughout (and update the UI/mapping)—so that runtime checks, translations, and types all agree.

🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 146-151, the union for
CommerceSubscriptionPlanPeriod currently uses 'month' | 'annual' which conflicts
with usages expecting 'year'; change the second literal to 'year' (so the type
is 'month' | 'year') and then update all dependent code to use 'year'
consistently: in
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx adjust the
branch/translation key to use 'year' instead of 'annual', and in
packages/shared/src/react/commerce.tsx update the recurringPaymentIntervalUnit
mapping to check for 'year' (and any other places that check for 'annual') so
types, runtime checks, and localization keys align.

Copy link
Member

@panteliselef panteliselef left a comment

Choose a reason for hiding this comment

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

We should keep @experimental for almost all types and their properties. Any of them can be removed/replaced/renamed at any point.

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: 0

Caution

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

⚠️ Outside diff range comments (1)
packages/backend/src/api/resources/CommercePlan.ts (1)

30-31: Coalesce nullable description to undefined to match field type.

Avoid assigning null to readonly description: string | undefined.

-    readonly description: string | undefined,
+    readonly description: string | undefined,
@@
-      data.description,
+      data.description ?? undefined,

Also applies to: 82-84

♻️ Duplicate comments (3)
packages/backend/src/api/resources/CommerceSubscription.ts (1)

5-7: Docs: remove TODO link and restore @experimental tag.

Avoid publishing "(TODO)" links; keep the experimental notice as requested in prior review.

 /**
- * The `CommerceSubscription` object is similar to the [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) object as it holds information about a subscription, as well as methods for managing it. However, the `CommerceSubscription` object is different in that it is used in the [Backend API](TODO){{ target: '_blank' }} and is not directly accessible from the Frontend API.
+ * The `CommerceSubscription` object is similar to the [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) object as it holds information about a subscription, as well as methods for managing it. However, the `CommerceSubscription` object is different in that it is used in the Backend API and is not directly accessible from the Frontend API.
+ * @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 to avoid breaking changes.
 */
packages/backend/src/api/resources/CommercePlan.ts (1)

6-8: Docs: remove TODO link and keep @experimental.

Aligns with earlier guidance to retain the experimental tag and avoid placeholder links.

- * The `CommercePlan` object is similar to the [`CommercePlanResource`](/docs/references/javascript/types/commerce-plan-resource) object as it holds information about a plan, as well as methods for managing it. However, the `CommercePlan` object is different in that it is used in the [Backend API](TODO){{ target: '_blank' }} and is not directly accessible from the Frontend API.
- * @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 to avoid breaking changes.
+ * The `CommercePlan` object is similar to the [`CommercePlanResource`](/docs/references/javascript/types/commerce-plan-resource) object as it holds information about a plan, as well as methods for managing it. However, the `CommercePlan` object is different in that it is used in the Backend API and is not directly accessible from the Frontend API.
+ * @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 to avoid breaking changes.
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (1)

6-8: Docs: remove TODO link and add @experimental.

Keep docs clean and retain experimental notice.

- * The `CommerceSubscriptionItem` object is similar to the [`CommerceSubscriptionItemResource`](/docs/references/javascript/types/commerce-subscription-item-resource) object as it holds information about a subscription item, as well as methods for managing it. However, the `CommerceSubscriptionItem` object is different in that it is used in the [Backend API](TODO){{ target: '_blank' }} and is not directly accessible from the Frontend API.
+ * The `CommerceSubscriptionItem` object is similar to the [`CommerceSubscriptionItemResource`](/docs/references/javascript/types/commerce-subscription-item-resource) object as it holds information about a subscription item, as well as methods for managing it. However, the `CommerceSubscriptionItem` object is different in that it is used in the Backend API and is not directly accessible from the Frontend API.
+ * @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 to avoid breaking changes.
🧹 Nitpick comments (6)
packages/backend/src/api/resources/CommerceSubscription.ts (1)

52-63: DRY up money mapping across resources.

The money-shape mapping is duplicated across files. Extract a shared helper to keep formats in sync.

-  const nextPayment = data.next_payment
-    ? {
-        date: data.next_payment.date,
-        amount: {
-          amount: data.next_payment.amount.amount,
-          amountFormatted: data.next_payment.amount.amount_formatted,
-          currency: data.next_payment.amount.currency,
-          currencySymbol: data.next_payment.amount.currency_symbol,
-        },
-      }
-    : null;
+  const nextPayment = data.next_payment
+    ? { date: data.next_payment.date, amount: mapMoneyJSON(data.next_payment.amount)! }
+    : null;

Additional file (new):

// packages/backend/src/api/resources/_internal/mapMoney.ts
import type { CommerceMoneyAmountJSON, CommerceMoneyAmount } from '@clerk/types';

export function mapMoneyJSON(
  amount: CommerceMoneyAmountJSON | null | undefined,
): CommerceMoneyAmount | null | undefined {
  if (!amount) return amount;
  return {
    amount: amount.amount,
    amountFormatted: amount.amount_formatted,
    currency: amount.currency,
    currencySymbol: amount.currency_symbol,
  };
}

And import where needed:

import { mapMoneyJSON } from './_internal/mapMoney';
packages/backend/src/api/resources/CommercePlan.ts (3)

1-3: Use type-only import and satisfy sorter.

CommerceMoneyAmount is type-only here; switch to import type and run autofix to satisfy both rules.

-import { CommerceMoneyAmount } from '@clerk/types';
+import type { CommerceMoneyAmount } from '@clerk/types';

Then:

pnpm lint --fix --filter @clerk/backend

60-63: Tie forPayerType to the JSON source type to prevent drift.

-    readonly forPayerType: 'org' | 'user',
+    readonly forPayerType: CommercePlanJSON['for_payer_type'],

69-77: Optional: reuse shared money mapping helper.

Match the helper suggested for other resources to avoid copy/paste.

-  const formatAmountJSON = (fee: CommercePlanJSON['fee']) => {
-    return {
-      amount: fee.amount,
-      amountFormatted: fee.amount_formatted,
-      currency: fee.currency,
-      currencySymbol: fee.currency_symbol,
-    };
-  };
+  const formatAmountJSON = mapMoneyJSON;

And import:

import { mapMoneyJSON } from './_internal/mapMoney';
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (2)

20-23: Bind planPeriod to the JSON type.

Prevents divergence if the backend adds values.

-    readonly planPeriod: 'month' | 'annual',
+    readonly planPeriod: CommerceSubscriptionItemJSON['plan_period'],

90-104: Optional: reuse shared money mapping helper.

You already have formatAmountJSON; consider importing a common helper as suggested for other files.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 36906be and 4c745fc.

📒 Files selected for processing (4)
  • packages/backend/src/api/resources/CommercePlan.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3 hunks)
  • packages/types/src/commerce.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/types/src/commerce.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
🪛 ESLint
packages/backend/src/api/resources/CommercePlan.ts

[error] 1-3: Run autofix to sort these imports!

(simple-import-sort/imports)


[error] 1-1: All imports in the declaration are only used as types. Use import type.

(@typescript-eslint/consistent-type-imports)

packages/backend/src/api/resources/CommerceSubscriptionItem.ts

[error] 1-4: Run autofix to sort these imports!

(simple-import-sort/imports)

packages/backend/src/api/resources/CommerceSubscription.ts

[error] 1-3: Run autofix to sort these imports!

(simple-import-sort/imports)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (5)
packages/backend/src/api/resources/CommerceSubscription.ts (2)

23-29: LGTM: clearer timestamp docs.

The reworded createdAt/updatedAt descriptions are clearer and consistent.


1-3: Import order needs sorting in CommerceSubscription.ts

I attempted to run the suggested autofix command but the lint script failed due to a missing zx dependency. Please ensure your workspace dependencies are installed (e.g. pnpm install at the repo root), then rerun the lint autofix and confirm the imports are sorted:

pnpm install
pnpm lint --fix --filter @clerk/backend

• File: packages/backend/src/api/resources/CommerceSubscription.ts
Lines: 1–3 — sort the three import statements according to simple-import-sort rules.
• Verify imports from external packages come before internal (sibling) imports, and that within each group they are alphabetically ordered.

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

30-39: Confirm nextPayment shape vs Subscription resource.

Here nextPayment.amount is a number, while CommerceSubscription.nextPayment.amount is CommerceMoneyAmount. Verify API parity or document why they differ.

Also applies to: 90-112


24-75: LGTM: timestamp field docs are consistent.

Also applies to: 53-63, 65-75


1-4: Fix import order and verify lint tooling

The imports should be reordered so that non-type imports come first, followed by all type-only imports. For example:

-import type { CommerceMoneyAmountJSON, CommerceMoneyAmount } from '@clerk/types';

-import { CommercePlan } from './CommercePlan';
-import type { CommerceSubscriptionItemJSON } from './JSON';
+import { CommercePlan } from './CommercePlan';

+import type { CommerceMoneyAmountJSON, CommerceMoneyAmount } from '@clerk/types';
+import type { CommerceSubscriptionItemJSON } from './JSON';

• After adjusting the imports, run ESLint’s autofix. If you continue to use

pnpm lint --fix --filter @clerk/backend

you’ll first need to resolve the ERR_MODULE_NOT_FOUND: zx error in scripts/lint.mjs (for instance, by adding zx as a dev dependency or updating the script).
• As an alternative, you can bypass the broken lint script and run ESLint directly:

npx eslint packages/backend/src/api/resources/CommerceSubscriptionItem.ts --fix

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: 1

♻️ Duplicate comments (3)
packages/types/src/commerce.ts (2)

827-839: Confirm omission of id on CommerceStatementGroup.

Runtime class CommerceStatementGroup in clerk-js has id, but this type omits it. If FAPI truly doesn't return id, consider adding a note explaining the intentional difference, or add id?: string to avoid friction when sharing types across packages.

Run to see where the runtime expects id:

#!/bin/bash
rg -nP -C2 "(class\s+CommerceStatementGroup\b|\.id\b)" packages/clerk-js

146-151: Unify plan period literal: 'annual' vs 'year'.

This still uses 'annual' while other parts of the codebase (UI, mappings) branch on 'year'. Pick one and make it consistent repo-wide to avoid logic/translation drift. Suggest switching the type to 'year' here and updating dependents (or vice versa).

Run to locate mismatches:

#!/bin/bash
rg -nP -C2 "(annual|year(?!ly))" --type=ts --type=tsx

Suggested change (if standardizing on 'year'):

-export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';
+export type CommerceSubscriptionPlanPeriod = 'month' | 'year';
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (1)

23-23: Plan period literal alignment.

This uses 'month' | 'annual'. Please align with the chosen convention in packages/types (see related comment).

🧹 Nitpick comments (6)
packages/types/src/commerce.ts (3)

1304-1307: Doc-type mismatch for freeTrialEndsAt.

JSDoc says "Unix timestamp (milliseconds)" but the type is Date | null. Align the description.

-  /**
-   * Unix timestamp (milliseconds) of when the free trial ends.
-   */
+  /**
+   * Date when the free trial ends, or `null` if not applicable.
+   */
   freeTrialEndsAt: Date | null;

577-580: Prefer optional property over string | undefined.

Use walletType?: string for clarity and to match common TS style across the repo.

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

124-135: Clarify and document the intentional mapping between ForPayerType and CommercePayerResourceType

The divergence between

  • CommercePayerResourceType = 'org' | 'user' (the JSON/DB literal)
  • ForPayerType = 'organization' | 'user' (the external API/UI literal)

is already wired up at the boundaries (e.g. in CommerceBilling.ts:

payer_type: forParam === 'organization' ? 'org' : 'user'

and in UI components mapping back 'org''organization'). To avoid confusion and surface this intent to consumers of the types package, add JSDoc to both type aliases:

– In packages/types/src/commerce.ts above export type CommercePayerResourceType

 /**
+ * @internal
+ * JSON API resource literal for a payer: 
+ * use 'org' for organizations and 'user' for individuals.
  */
 export type CommercePayerResourceType = 'org' | 'user';

– And above export type ForPayerType

 /**
+ * @experimental
+ * Public-facing literal for specifying a payer: 
+ * maps to `CommercePayerResourceType` ('organization' → 'org') in API calls.
  * This API is in beta and may change—pin your SDK versions to avoid breaking changes.
  */
 export type ForPayerType = 'organization' | 'user';

This makes the boundary mapping explicit in the types package, preventing subtle bugs.

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

31-40: Clarify units for nextPayment.amount.

Other money fields use CommerceMoneyAmount, but nextPayment.amount is a number. Document that it's in minor units (e.g., cents) to avoid misinterpretation.

     readonly nextPayment: {
       /**
-       * The amount of the next payment.
+       * The amount of the next payment in the smallest currency unit (e.g., cents).
        */
       amount: number;

91-106: Consider hoisting formatAmountJSON to a shared helper.

This helper likely exists in similar resources. Centralizing avoids duplication and keeps JSON-to-type mapping consistent.

I can extract a small formatMoneyAmountJSON util under packages/backend/src/api/utils/ and update call sites if you want.

.changeset/three-knives-play.md (1)

6-7: Tighten wording for clarity.

Minor grammar/style tweak.

-- Export `Feature` type from backend resource.
-- Re-export canonical `CommerceMoneyAmount` type from `@clerk/types`.
+- Export the `Feature` type from backend resources.
+- Re-export the canonical `CommerceMoneyAmount` type from `@clerk/types`.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 4c745fc and c9f4326.

📒 Files selected for processing (5)
  • .changeset/three-knives-play.md (1 hunks)
  • packages/backend/src/api/resources/CommercePlan.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3 hunks)
  • packages/types/src/commerce.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/types/src/commerce.ts
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
.changeset/**

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

Automated releases must use Changesets.

Files:

  • .changeset/three-knives-play.md
🧬 Code graph analysis (1)
packages/types/src/commerce.ts (3)
packages/types/src/resource.ts (1)
  • ClerkResource (8-21)
packages/types/src/snapshots.ts (1)
  • CommerceFeatureJSONSnapshot (194-194)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (39-58)
🪛 LanguageTool
.changeset/three-knives-play.md

[grammar] ~6-~6: There might be a mistake here.
Context: ...es': patch --- - Export Feature type from backend resource. - Re-export canonical...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...rt Feature type from backend resource. - Re-export canonical `CommerceMoneyAmount...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (7)
packages/types/src/commerce.ts (4)

415-445: LGTM: Clear feature docs and internal snapshot hook.

Docs are precise; __internal_toSnapshot is hidden. Good addition.


170-193: Payment source methods API looks good.

Type surfaces and pagination use WithOptionalOrgType correctly.


1132-1152: LGTM: Canonical CommerceMoneyAmount docs.

Accurately documents minor units and formatted amounts.


1154-1185: LGTM: Checkout totals.

Clear field semantics; consistent with money type.

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

6-9: Fill in the Backend API doc link before merge.

Replace the (TODO) link with the actual Backend API docs URL.

Would you like me to propose the final URL once the docs build preview is available?


107-126: LGTM: JSON mapping.

Field mappings match JSON keys; CommercePlan.fromJSON is correctly used.


1-1: All exports verified – no action needed

The interface CommerceMoneyAmountJSON is publicly exported in packages/types/src/json.ts and is re-exported through the package’s entry point, so importing it from @clerk/types will succeed.

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: 1

Caution

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

⚠️ Outside diff range comments (1)
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (1)

21-23: Avoid hard-coded union for planPeriod; bind to JSON source-of-truth.

Using the JSON-declared type prevents drift if the backend introduces new values.

-    readonly planPeriod: 'month' | 'annual',
+    readonly planPeriod: CommerceSubscriptionItemJSON['plan_period'],

Also applies to: 110-110

🧹 Nitpick comments (4)
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (4)

1-3: Prefer type-only import for the plan type, keep value import for runtime.

Use a separate type-only import to avoid pulling types into runtime bundles while still using the value for fromJSON.

 import type { CommerceMoneyAmount, CommerceMoneyAmountJSON } from '@clerk/types';
 
-import { CommercePlan } from './CommercePlan';
+import type { CommercePlan as CommercePlanType } from './CommercePlan';
+import { CommercePlan } from './CommercePlan';

And update the property annotation below:

-    readonly plan: CommercePlan,
+    readonly plan: CommercePlanType,

44-44: Consistent optionals: align amount with other optional money fields.

Minor: consider making amount optional (like lifetimePaid?) instead of | undefined for consistency. Defer if this is a public API stability concern.

-    readonly amount: CommerceMoneyAmount | null | undefined,
+    readonly amount?: CommerceMoneyAmount | null,

Also applies to: 88-88


92-106: Deduplicate formatAmountJSON across resources.

This helper likely exists elsewhere (or will soon). Extract to a shared util to ensure consistent mapping and reduce duplication.


114-114: Fail fast if required nested resource is missing.

If data.plan is unexpectedly absent, throw a typed error for easier debugging instead of crashing deeper.

   static fromJSON(data: CommerceSubscriptionItemJSON): CommerceSubscriptionItem {
+    if (!data.plan) {
+      throw new TypeError('Missing required "plan" in CommerceSubscriptionItemJSON');
+    }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 c9f4326 and 7800b1e.

⛔ Files ignored due to path filters (1)
  • .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • packages/backend/src/api/resources/CommercePlan.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/backend/src/api/resources/CommercePlan.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/backend/src/api/resources/CommerceSubscriptionItem.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/backend/src/api/resources/CommerceSubscriptionItem.ts
**/*.{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/backend/src/api/resources/CommerceSubscriptionItem.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3)

7-9: Good: kept the @experimental tag with clear context.

Retaining this tag aligns with prior feedback and sets expectations for consumers.


25-25: Good: unified “Unix timestamp (milliseconds)” wording across time fields.

Consistent time unit doc reduces consumer confusion.

Also applies to: 54-54, 58-58, 62-62, 66-66, 70-70, 74-74


7-9: No changes required — the link to /docs/reference/backend-api/tag/commerce/get/commerce/subscription_items is correct, and the docs generator supports the {{ target: '_blank' }} inline prop for markdown links.

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: 0

Caution

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

⚠️ Outside diff range comments (1)
packages/backend/src/api/resources/CommercePlan.ts (1)

81-95: Harden fromJSON against nullable fields and optional arrays.

  • description may be null in JSON; coalesce to undefined to match the constructor type.
  • features should default to an empty array to avoid .map on undefined.

Apply:

-      data.description,
+      data.description ?? undefined,
@@
-      data.features.map(feature => Feature.fromJSON(feature)),
+      (data.features ?? []).map(feature => Feature.fromJSON(feature)),
♻️ Duplicate comments (1)
packages/backend/src/api/resources/CommerceSubscription.ts (1)

9-9: Thanks for retaining the @experimental tag.

Matches the prior review requirement to keep this around.

🧹 Nitpick comments (6)
packages/backend/src/api/resources/CommercePlan.ts (3)

68-68: Tighten immutability of features array.

Expose as a readonly array to prevent accidental mutation by SDK consumers.

Apply:

-    readonly features: Feature[],
+    readonly features: readonly Feature[],

52-60: Docs nit: avoid UI-component coupling in backend type docs.

Optional: rephrase to describe visibility without naming a specific component, or add “e.g.” to reduce coupling.

Possible tweak:

-     * Whether the plan is displayed in the `<PriceTable/>` component.
+     * Whether the plan is publicly visible (e.g., in pricing tables).

Also applies to: 46-48


71-79: Tighten formatAmountJSON signature Change the parameter to fee: NonNullable<CommercePlanJSON['fee']> and annotate its return as : CommerceMoneyAmount—no runtime null check needed since fee, annual_fee and annual_monthly_fee are always present in CommercePlanJSON.

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

26-26: Unify timestamp phrasing (explicit UTC + epoch).

Minor doc polish for consistency across fields.

- * Unix timestamp (milliseconds) of when the subscription was created.
+ * Unix timestamp in milliseconds since Unix epoch (UTC) when the subscription was created.
@@
- * Unix timestamp (milliseconds) of when the subscription was last updated.
+ * Unix timestamp in milliseconds since Unix epoch (UTC) when the subscription was last updated.
@@
- * Unix timestamp (milliseconds) of when the subscription became active.
+ * Unix timestamp in milliseconds since Unix epoch (UTC) when the subscription became active.
@@
- * Unix timestamp (milliseconds) of when the subscription became past due.
+ * Unix timestamp in milliseconds since Unix epoch (UTC) when the subscription became past due.

Also applies to: 30-30, 34-34, 38-38


44-44: Prefer ReadonlyArray for immutability of collection properties.

Aligns with the guideline to prefer immutable data structures.

-    readonly subscriptionItems: CommerceSubscriptionItem[],
+    public readonly subscriptionItems: ReadonlyArray<CommerceSubscriptionItem>,

12-53: Add explicit public modifiers to constructor parameter properties – TypeScript’s parameter properties default to public, but our style guide prefers explicit modifiers for public APIs. No external instantiations of this backend class were found outside its own file, so this change is safe to apply.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 f161bf1 and 0020436.

📒 Files selected for processing (3)
  • packages/backend/src/api/resources/CommercePlan.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (2 hunks)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/backend/src/api/resources/CommerceSubscriptionItem.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
**/*.{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/backend/src/api/resources/CommercePlan.ts
  • packages/backend/src/api/resources/CommerceSubscription.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (6)
packages/backend/src/api/resources/CommercePlan.ts (4)

1-1: Good move: rely on canonical CommerceMoneyAmount from @clerk/types.

Eliminates duplication and drift across packages.


9-9: Thanks for keeping @experimental.

Aligns with prior guidance; sets correct expectations for consumers.


18-20: JSDoc clarity: productId wording is clear.

No further changes needed here.


7-9: Docs: confirm backend API link and remove unsupported template markup
I couldn’t locate /docs/reference/backend-api/tag/commerce/get/commerce/plans or any {{ target: '_blank' }} in the generated docs—please verify that the URL is correct in your docs pipeline and drop the {{ target: '_blank' }} if it isn’t supported.

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

7-8: Use stable BAPI Redoc URL and add @see tag

Replace the absolute Clerk.com link with the stable Redoc link to the GET /organizations/{organization_id}/billing/subscription endpoint, and add an @see tag. For example:

- * The `CommerceSubscription` object is similar to the [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) object as it holds information about a subscription, as well as methods for managing it. However, the `CommerceSubscription` object is different in that it is used in the [Backend API](https://clerk.com/docs/reference/backend-api/tag/billing/get/organizations/%7Borganization_id%7D/billing/subscription) and is not directly accessible from the Frontend API.
+ * The `CommerceSubscription` object is similar to the [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) object as it holds information about a subscription and methods for managing it. However, `CommerceSubscription` is used in the [Backend API](https://clerk-bapi.redoc.ly/tag/Organizations/paths/~1organizations~1%7Borganization_id%7D~1billing~1subscription/get) and is not directly accessible from the Frontend API.
+ * @see {@link https://clerk-bapi.redoc.ly/tag/Organizations/paths/~1organizations~1%7Borganization_id%7D~1billing~1subscription/get | GET /organizations/{organization_id}/billing/subscription}

1-1: Confirm CommerceMoneyAmount field parity

  • @clerk/types is already declared in packages/backend/package.json.
  • Verify that the exported CommerceMoneyAmount type includes the fields you’re mapping (amountFormatted, currencySymbol) and no others.

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

Caution

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

⚠️ Outside diff range comments (1)
packages/types/src/commerce.ts (1)

170-193: Use Omit, not Exclude, to drop 'orgId' from object types

Exclude works on union members, not object keys. As written, it doesn’t remove orgId and weakens type-safety for these APIs.

Apply:

   initializePaymentSource: (
-    params: Exclude<InitializePaymentSourceParams, 'orgId'>,
+    params: Omit<InitializePaymentSourceParams, 'orgId'>,
   ) => Promise<CommerceInitializedPaymentSourceResource>;
@@
-  addPaymentSource: (params: Exclude<AddPaymentSourceParams, 'orgId'>) => Promise<CommercePaymentSourceResource>;
+  addPaymentSource: (params: Omit<AddPaymentSourceParams, 'orgId'>) => Promise<CommercePaymentSourceResource>;
@@
-  getPaymentSources: (
-    params: Exclude<GetPaymentSourcesParams, 'orgId'>,
+  getPaymentSources: (
+    params: Omit<GetPaymentSourcesParams, 'orgId'>,
   ) => Promise<ClerkPaginatedResponse<CommercePaymentSourceResource>>;
♻️ Duplicate comments (2)
packages/types/src/commerce.ts (2)

146-151: Unify period literal: 'annual' vs 'year'

This union still uses 'annual'. Other call sites (UI/logic/translations) often branch on 'year'. Pick one and use it everywhere to avoid type/logic drift.

Apply in-file fix (if you standardize on 'year'):

-export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';
+export type CommerceSubscriptionPlanPeriod = 'month' | 'year';

Then update downstream branches/keys accordingly. Run to find stragglers:

#!/bin/bash
rg -nP -C2 "\b(annual|year)\b" --type=ts --type=tsx

1228-1259: ConfirmCheckoutParams allows {} and contradicts docs; require exactly one branch and gateway where needed

Current union uses optional fields, so an empty object type-checks. Also gateway is optional despite docs saying required with token/test card.

Apply:

-export type ConfirmCheckoutParams = WithOptionalOrgType<
-  | {
-      /**
-       * The ID of a saved payment source to use for this checkout.
-       */
-      paymentSourceId?: string;
-    }
-  | {
-      /**
-       * A token representing payment details, usually from a payment form. **Requires** `gateway` to be provided.
-       */
-      paymentToken?: string;
-      /**
-       * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
-       */
-      gateway?: PaymentGateway;
-    }
-  | {
-      /**
-       * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
-       */
-      gateway?: PaymentGateway;
-      /**
-       * If true, uses a test card for the checkout. **Requires** `gateway` to be provided.
-       */
-      useTestCard?: boolean;
-    }
->;
+export type ConfirmCheckoutParams = WithOptionalOrgType<
+  | {
+      /** The ID of a saved payment source to use for this checkout. */
+      paymentSourceId: string;
+    }
+  | {
+      /** A token representing payment details, usually from a payment form. */
+      paymentToken: string;
+      /** Required when using `paymentToken`. */
+      gateway: PaymentGateway;
+    }
+  | {
+      /** Use a test card for the checkout. */
+      useTestCard: true;
+      /** Required when `useTestCard` is provided. */
+      gateway: PaymentGateway;
+    }
+>;
🧹 Nitpick comments (3)
packages/types/src/commerce.ts (3)

251-261: Align payer type naming (org vs organization)

GetPlansParams accepts 'organization' while CommercePlanResource.forPayerType uses 'org'. This inconsistency leaks into consumer code and filters.

Minimal compatibility tweak:

-export type ForPayerType = 'organization' | 'user';
+export type ForPayerType = 'organization' | 'org' | 'user';

If FAPI only accepts 'organization', keep the type as-is but ensure UI/resource fields use the same literal (or normalize centrally).


32-41: Normalize param typing to WithOptionalOrgType for consistency

This method hand-inlines orgId, unlike the rest that use WithOptionalOrgType.

Apply:

-  getPaymentAttempt: (params: { id: string; orgId?: string }) => Promise<CommercePaymentResource>;
+  getPaymentAttempt: (params: WithOptionalOrgType<{ id: string }>) => Promise<CommercePaymentResource>;

575-580: Prefer optional property over 'string | undefined'

For consistency with the rest of the file, make walletType optional.

Apply:

-  walletType: string | undefined;
+  walletType?: string;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 0020436 and 1e1834a.

📒 Files selected for processing (1)
  • packages/types/src/commerce.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/types/src/commerce.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
🧬 Code graph analysis (1)
packages/types/src/commerce.ts (3)
packages/types/src/resource.ts (1)
  • ClerkResource (8-21)
packages/types/src/snapshots.ts (1)
  • CommerceFeatureJSONSnapshot (194-194)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (39-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
packages/types/src/commerce.ts (2)

415-445: LGTM: Clearer Feature docs + explicit id and snapshot method

Docs are clear and the public surface matches intent. Keeping @experimental is also correct.


542-594: LGTM: Payment source surface looks coherent

Adding id, status, defaults, and mutators (remove/makeDefault) aligns with expected UX flows. Good JSDoc.

Comment on lines 1262 to 1315
* The `CommerceCheckoutResource` type represents information about a checkout session.
*
* @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 CommerceCheckoutResource extends ClerkResource {
/**
* The unique identifier for the checkout session.
*/
id: string;
/**
* @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" />
* ```
* A client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side.
*/
externalClientSecret: string;
/**
* @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" />
* ```
* The identifier for the external payment gateway used for this checkout session.
*/
externalGatewayId: string;
/**
* @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" />
* ```
* The payment source being used for the checkout, such as a credit card or bank account.
*/
paymentSource?: CommercePaymentSourceResource;
/**
* @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" />
* ```
* The subscription plan details for the checkout.
*/
plan: CommercePlanResource;
/**
* @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" />
* ```
* The billing period for the plan.
*/
planPeriod: CommerceSubscriptionPlanPeriod;
/**
* @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" />
* ```
* Unix timestamp (milliseconds) of when the current period starts.
*/
planPeriodStart?: number;
/**
* @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" />
* ```
* The current status of the checkout session.
*/
status: 'needs_confirmation' | 'completed';
/**
* @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" />
* ```
* The total costs, taxes, and other pricing details for the checkout.
*/
totals: CommerceCheckoutTotals;
/**
* @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" />
* ```
* A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm)
*/
confirm: (params: ConfirmCheckoutParams) => Promise<CommerceCheckoutResource>;
/**
* @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" />
* ```
* Whether the plan change will take effect immediately after checkout.
*/
isImmediatePlanChange: boolean;
/**
* @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" />
* ```
* Unix timestamp (milliseconds) of when the free trial ends.
*/
freeTrialEndsAt: Date | null;
}
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

Time fields: fix Date vs Unix ms inconsistency

planPeriodStart is number (ms) but other timestamps are Date. freeTrialEndsAt JSDoc says Unix ms but type is Date. Standardize on Date for resource types and convert at the edge.

Apply:

-  /**
-   * Unix timestamp (milliseconds) of when the current period starts.
-   */
-  planPeriodStart?: number;
+  /**
+   * The date when the current period starts.
+   */
+  planPeriodStart?: Date;
@@
-  /**
-   * Unix timestamp (milliseconds) of when the free trial ends.
-   */
-  freeTrialEndsAt: Date | null;
+  /**
+   * The date when the free trial ends.
+   */
+  freeTrialEndsAt: Date | null;

If FAPI returns ms, keep the runtime conversion (JSON -> Date) consistent with other resources and document it once centrally.

📝 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 `CommerceCheckoutResource` type represents information about a checkout session.
*
* @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 CommerceCheckoutResource extends ClerkResource {
/**
* The unique identifier for the checkout session.
*/
id: string;
/**
* @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" />
* ```
* A client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side.
*/
externalClientSecret: string;
/**
* @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" />
* ```
* The identifier for the external payment gateway used for this checkout session.
*/
externalGatewayId: string;
/**
* @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" />
* ```
* The payment source being used for the checkout, such as a credit card or bank account.
*/
paymentSource?: CommercePaymentSourceResource;
/**
* @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" />
* ```
* The subscription plan details for the checkout.
*/
plan: CommercePlanResource;
/**
* @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" />
* ```
* The billing period for the plan.
*/
planPeriod: CommerceSubscriptionPlanPeriod;
/**
* @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" />
* ```
* Unix timestamp (milliseconds) of when the current period starts.
*/
planPeriodStart?: number;
/**
* @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" />
* ```
* The current status of the checkout session.
*/
status: 'needs_confirmation' | 'completed';
/**
* @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" />
* ```
* The total costs, taxes, and other pricing details for the checkout.
*/
totals: CommerceCheckoutTotals;
/**
* @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" />
* ```
* A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm)
*/
confirm: (params: ConfirmCheckoutParams) => Promise<CommerceCheckoutResource>;
/**
* @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" />
* ```
* Whether the plan change will take effect immediately after checkout.
*/
isImmediatePlanChange: boolean;
/**
* @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" />
* ```
* Unix timestamp (milliseconds) of when the free trial ends.
*/
freeTrialEndsAt: Date | null;
}
export interface CommerceCheckoutResource extends ClerkResource {
/**
* The unique identifier for the checkout session.
*/
id: string;
/**
* A client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side.
*/
externalClientSecret: string;
/**
* The identifier for the external payment gateway used for this checkout session.
*/
externalGatewayId: string;
/**
* The payment source being used for the checkout, such as a credit card or bank account.
*/
paymentSource?: CommercePaymentSourceResource;
/**
* The subscription plan details for the checkout.
*/
plan: CommercePlanResource;
/**
* The billing period for the plan.
*/
planPeriod: CommerceSubscriptionPlanPeriod;
- /**
- * Unix timestamp (milliseconds) of when the current period starts.
- */
/**
* The date when the current period starts.
*/
planPeriodStart?: Date;
/**
* The current status of the checkout session.
*/
status: 'needs_confirmation' | 'completed';
/**
* The total costs, taxes, and other pricing details for the checkout.
*/
totals: CommerceCheckoutTotals;
/**
* A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm)
*/
confirm: (params: ConfirmCheckoutParams) => Promise<CommerceCheckoutResource>;
/**
* Whether the plan change will take effect immediately after checkout.
*/
isImmediatePlanChange: boolean;
- /**
- * Unix timestamp (milliseconds) of when the free trial ends.
- */
/**
* The date when the free trial ends.
*/
freeTrialEndsAt: Date | null;
}
🤖 Prompt for AI Agents
packages/types/src/commerce.ts around lines 1262 to 1315: the timestamp fields
are inconsistent—planPeriodStart is typed as a Unix-ms number while
freeTrialEndsAt JSDoc says Unix ms but the type is Date; standardize both
resource fields to use Date (and nullable where appropriate) and update their
JSDoc to indicate they are Date objects (UTC), not raw ms; keep conversion from
FAPI (ms -> Date) at the runtime/edge layer rather than here and add a
single-line JSDoc note pointing to the central conversion behavior.

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: 1

♻️ Duplicate comments (3)
packages/types/src/commerce.ts (3)

146-151: Standardize plan period literal: 'annual' vs 'year'

This still conflicts with usages expecting 'year'. Align now to avoid downstream condition/translation drift.

Apply:

-export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';
+export type CommerceSubscriptionPlanPeriod = 'month' | 'year';

Run to find remaining sites that assume either spelling:

#!/bin/bash
rg -nP -C2 "\b(annual|year|yearly)\b" --type=ts --type=tsx packages

1234-1238: Encode param constraints in the type (require gateway and enforce exclusivity)

  • Docs say gateway is required when using paymentToken or useTestCard, but type allows omission.
  • Make each branch’s discriminant required; otherwise TS will accept objects containing multiple options at once.

Apply minimal fix:

   | {
       /**
        * The ID of a saved payment source to use for this checkout.
        */
-      paymentSourceId?: string;
+      paymentSourceId: string;
     }
   | {
       /**
        * A token representing payment details, usually from a payment form. **Requires** `gateway` to be provided.
        */
       paymentToken?: string;
       /**
        * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
        */
-      gateway?: PaymentGateway;
+      gateway: PaymentGateway;
     }
   | {
       /**
        * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
        */
-      gateway?: PaymentGateway;
+      gateway: PaymentGateway;
       /**
        * If true, uses a test card for the checkout. **Requires** `gateway` to be provided.
        */
-      useTestCard?: boolean;
+      useTestCard: true;
     }

Optional but better: wrap the union with WithOptionalOrgType<...> to allow orgId consistently on all branches.

Also applies to: 1245-1248, 1251-1254


1291-1294: Fix Date vs Unix ms inconsistency in checkout timestamps

Resource fields should surface Dates; keep ms conversion at the edge. JSDoc for freeTrialEndsAt also contradicts its type.

Apply:

-  /**
-   * Unix timestamp (milliseconds) of when the current period starts.
-   */
-  planPeriodStart?: number;
+  /**
+   * The date when the current period starts.
+   */
+  planPeriodStart?: Date;
@@
-  /**
-   * Unix timestamp (milliseconds) of when the free trial ends.
-   */
-  freeTrialEndsAt: Date | null;
+  /**
+   * The date when the free trial ends.
+   */
+  freeTrialEndsAt: Date | null;

Also applies to: 1311-1314

🧹 Nitpick comments (1)
packages/types/src/commerce.ts (1)

543-594: Tighten optionality and unions on payment source fields

  • Prefer optional property to string | undefined for walletType; it renders better in TypeDoc and matches codebase style.
  • Consider future follow-up to narrow paymentMethod/cardType/walletType to unions if the value space is known (e.g., 'card' | 'bank_account'; 'visa' | 'mastercard'; 'apple_pay' | 'google_pay'), but that's optional for this PR.

Apply:

-  walletType: string | undefined;
+  walletType?: string;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 1e1834a and 5c62f9f.

⛔ Files ignored due to path filters (1)
  • .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • packages/types/src/commerce.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/types/src/commerce.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
🧬 Code graph analysis (1)
packages/types/src/commerce.ts (3)
packages/types/src/resource.ts (1)
  • ClerkResource (8-21)
packages/types/src/snapshots.ts (1)
  • CommerceFeatureJSONSnapshot (194-194)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (39-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (6)
packages/types/src/commerce.ts (6)

7-11: LGTM: Helpful JSDoc on WithOptionalOrgType.orgId

Clear param docs; matches pattern used elsewhere.


415-445: LGTM: Feature resource shape and hidden snapshot hook

Good addition of explicit id and @hidden snapshot method; matches export goals.


448-451: LGTM: Narrow, explicit payment source status union

Works well for API docs and DX.


1228-1231: LGTM: Clear exclusivity note for confirm() params

The “only one of …” guidance is great for DX.


1135-1156: LGTM: MoneyAmount docs are clear and actionable

Good examples and consistent field naming.


1159-1188: LGTM: Checkout totals surface area

Fields are cohesive and map cleanly to MoneyAmount.

Comment on lines 827 to 841
/**
* @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" />
* ```
* The `CommerceStatementGroup` 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 {
/**
* @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" />
* ```
* The date and time when this group of payment items was created or last updated.
*/
timestamp: Date;
/**
* @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" />
* ```
* An array of payment resources that belong to this group.
*/
items: CommercePaymentResource[];
}
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

Statement group id mismatch between runtime and types

Runtime class consumes data.id and exposes id: string, but the type omits it. If FAPI truly does not return an id, we either need (a) a synthetic, documented id in the runtime or (b) to remove/adjust the runtime reliance. Leaving this divergent guarantees undefined at runtime or type unsafety.

If we decide to model the runtime shape in types, apply:

 export interface CommerceStatementGroup {
+  /**
+   * Unique identifier for this group (matches runtime class). If FAPI does not provide one,
+   * use a stable synthetic id and document the derivation.
+   */
+  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: CommercePaymentResource[];
 }

To verify current runtime expectation:


🏁 Script executed:

#!/bin/bash
rg -nC2 "class\s+CommerceStatementGroup|data\.id\b" packages

Length of output: 46220


Add missing id property to CommerceStatementGroup type

 export interface CommerceStatementGroup {
+  /**
+   * Unique identifier for this group (matches runtime class `id`).
+   * If FAPI doesn’t supply one, derive a stable synthetic ID and document it.
+   */
+  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: CommercePaymentResource[];
 }
📝 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
/**
* @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" />
* ```
* The `CommerceStatementGroup` 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 {
/**
* @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" />
* ```
* The date and time when this group of payment items was created or last updated.
*/
timestamp: Date;
/**
* @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" />
* ```
* An array of payment resources that belong to this group.
*/
items: CommercePaymentResource[];
}
/**
* The `CommerceStatementGroup` 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 {
/**
* Unique identifier for this group (matches runtime class `id`).
* If FAPI doesn’t supply one, derive a stable synthetic ID in the runtime layer and document it here.
*/
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: CommercePaymentResource[];
}
🤖 Prompt for AI Agents
In packages/types/src/commerce.ts around lines 827 to 841, the
CommerceStatementGroup type is missing an id property; add a required id: string
field to the interface (with a brief JSDoc comment like "A unique identifier for
this statement group") so consumers can reference groups by id, and place it
alongside timestamp and items in the exported interface.

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: 0

Caution

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

⚠️ Outside diff range comments (2)
packages/types/src/commerce.ts (2)

1213-1275: Fix Date vs Unix-ms inconsistency on checkout timestamps.

Most timestamps are Date, but planPeriodStart is number and freeTrialEndsAt JSDoc says Unix ms while type is Date. Standardize both as Date and update JSDoc.

 export interface CommerceCheckoutResource extends ClerkResource {
@@
-  /**
-   * Unix timestamp (milliseconds) of when the current period starts.
-   */
-  planPeriodStart?: number;
+  /**
+   * The date when the current billing period starts.
+   */
+  planPeriodStart?: Date;
@@
-  /**
-   * Unix timestamp (milliseconds) of when the free trial ends.
-   */
-  freeTrialEndsAt: Date | null;
+  /**
+   * The date when the free trial ends.
+   */
+  freeTrialEndsAt: Date | null;

845-847: Make paymentSourceId nullable across the API surface.

  • In packages/types/src/commerce.ts, change
    //TODO(@COMMERCE): should this be nullable ?
    paymentSourceId: string;
    to
    /**
     * The payment source used for this subscription item, if any.
     */
    paymentSourceId: string | null;
  • In packages/clerk-js/src/core/resources/CommerceSubscription.ts, update the class property to
    paymentSourceId!: string | null;
    so its type matches incoming data.payment_source_id and avoids runtime type errors.
♻️ Duplicate comments (3)
packages/types/src/commerce.ts (3)

147-151: Standardize period literal: use 'year' instead of 'annual' (matches UI logic).

There are known usages checking for 'year'. Keep literals consistent to avoid branching bugs and missing i18n keys.

-export type CommerceSubscriptionPlanPeriod = 'month' | 'annual';
+export type CommerceSubscriptionPlanPeriod = 'month' | 'year';

To verify drift across the repo:

#!/bin/bash
rg -nP -C2 "\b(annual|year)\b" --type=ts --type=tsx

1180-1210: Enforce XOR and gateway requirement in confirm() params.

Type allows empty objects and multiple fields simultaneously; JSDoc requires exactly one, and gateway when token/test-card is used. Encode constraints in the type.

-export type ConfirmCheckoutParams =
-  | {
-      /**
-       * The ID of a saved payment source to use for this checkout.
-       */
-      paymentSourceId?: string;
-    }
-  | {
-      /**
-       * A token representing payment details, usually from a payment form. **Requires** `gateway` to be provided.
-       */
-      paymentToken?: string;
-      /**
-       * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
-       */
-      gateway?: PaymentGateway;
-    }
-  | {
-      /**
-       * The payment gateway to use. For example, `'stripe'` or `'paypal'`. **Required** if `paymentToken` or `useTestCard` is provided.
-       */
-      gateway?: PaymentGateway;
-      /**
-       * If true, uses a test card for the checkout. **Requires** `gateway` to be provided.
-       */
-      useTestCard?: boolean;
-    };
+export type ConfirmCheckoutParams =
+  // Use a saved payment source
+  | {
+      paymentSourceId: string;
+      paymentToken?: never;
+      useTestCard?: never;
+      gateway?: never;
+    }
+  // Use a payment token with an explicit gateway
+  | {
+      paymentToken: string;
+      gateway: PaymentGateway;
+      paymentSourceId?: never;
+      useTestCard?: never;
+    }
+  // Use a test card with an explicit gateway
+  | {
+      useTestCard: true;
+      gateway: PaymentGateway;
+      paymentSourceId?: never;
+      paymentToken?: never;
+    };

779-793: Add missing id: string to CommerceStatementGroup type
Runtime maps data.id onto CommerceStatementGroup.id, but the interface omits it, causing a type/runtime mismatch.

 export interface CommerceStatementGroup {
+  /**
+   * Unique identifier for this group, matching the runtime `data.id`.
+   */
+  id: string;
   /**
    * The date and time when this group of payment items was created or last updated.
    */
🧹 Nitpick comments (4)
packages/types/src/commerce.ts (4)

124-135: Unify payer literal names: 'org' vs 'organization'.

CommercePayerResourceType = 'org' | 'user' but ForPayerType = 'organization' | 'user'. This drift can leak into APIs and filters. Pick one and use consistently (prefer 'organization' for external params, and mirror the same literals in resources), or add a single source type and aliases with explicit conversions in runtime.

Apply if you choose to standardize on 'organization':

-export type CommercePayerResourceType = 'org' | 'user';
+export type CommercePayerResourceType = 'organization' | 'user';

495-546: Tighten types and return shapes for payment source; minor ergonomics.

  • Prefer optional field over string | undefined for walletType.
  • Consider Promise<void> instead of Promise<null> for makeDefault (idiomatic and tree-shake friendly). If API must return null, keep as-is.
  • Optionally narrow paymentMethod and cardType to known unions while allowing string fallback later.
 export interface CommercePaymentSourceResource extends ClerkResource {
@@
-  walletType: string | undefined;
+  walletType?: string;
@@
-  makeDefault: (params?: MakeDefaultPaymentSourceParams) => Promise<null>;
+  makeDefault: (params?: MakeDefaultPaymentSourceParams) => Promise<void>;
 }

482-493: Prefer explicit empty-object params over unknown.

WithOptionalOrgType<unknown> collapses to just { orgId?: string }. Use {} for readability in generated docs and type hints.

-export type RemovePaymentSourceParams = WithOptionalOrgType<unknown>;
+export type RemovePaymentSourceParams = WithOptionalOrgType<{}>;
@@
-export type MakeDefaultPaymentSourceParams = WithOptionalOrgType<unknown>;
+export type MakeDefaultPaymentSourceParams = WithOptionalOrgType<{}>;

1087-1108: Clarify money amount invariants (locale/format).

Document whether amountFormatted is locale-agnostic (e.g., dot decimal, no grouping) and whether currencySymbol is ASCII vs localized. Otherwise consumers may double-localize or mis-render.

   /**
-   * The amount as a formatted string. For example, `10.00` for $10.00.
+   * The amount as a normalized, non-localized decimal string (dot as decimal separator, no grouping).
+   * For example, "10.00". Prefer localizing in the UI layer using `amount` + `currency`.
   */
   amountFormatted: string;
@@
   /**
-   * The symbol for the currency. For example, `$`.
+   * The canonical currency symbol (ASCII). UI layers may substitute locale-specific symbols.
   */
   currencySymbol: string;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 5c62f9f and 974fb9d.

⛔ Files ignored due to path filters (1)
  • .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • packages/types/src/commerce.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
packages/**/*.{ts,tsx}

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

TypeScript is required for all packages

Files:

  • packages/types/src/commerce.ts
packages/**/*.{ts,tsx,d.ts}

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

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
**/*.{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/types/src/commerce.ts
🧬 Code graph analysis (1)
packages/types/src/commerce.ts (3)
packages/types/src/resource.ts (1)
  • ClerkResource (8-21)
packages/types/src/snapshots.ts (1)
  • CommerceFeatureJSONSnapshot (194-194)
packages/clerk-js/src/core/resources/CommerceStatement.ts (1)
  • CommerceStatementGroup (39-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (5)
packages/types/src/commerce.ts (5)

7-9: LGTM: Clear JSDoc for org scoping.

Doc clarifies the optional org scoping cleanly.


367-397: LGTM: Feature resource JSDoc and snapshot hook.

Good public fields and hidden snapshot method docs. Matches the intent to expose Feature.


399-404: LGTM: PaymentSource status union is crisp.

Status values are clear and documented inline.


1110-1141: LGTM: Checkout totals surface.

Fields are well-defined and align with statement totals reuse.


1143-1148: LGTM: Statement totals omit totalDueNow.

Makes sense for historical statements.

@panteliselef panteliselef merged commit 65b12ee into main Aug 29, 2025
39 checks passed
@panteliselef panteliselef deleted the aa/update-commerce-typedoc branch August 29, 2025 18:42
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.

3 participants