Skip to content

feat(clerk-js,localizations,shared,ui): Add support for rendering discounts on subscription items - #9316

Open
dstaley wants to merge 2 commits into
mainfrom
ds.feat/billing-discounts
Open

feat(clerk-js,localizations,shared,ui): Add support for rendering discounts on subscription items#9316
dstaley wants to merge 2 commits into
mainfrom
ds.feat/billing-discounts

Conversation

@dstaley

@dstaley dstaley commented Aug 3, 2026

Copy link
Copy Markdown
Member

Description

This PR adds support for rendering discounts on subscription items.

image

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:

@dstaley
dstaley requested a review from a team August 3, 2026 18:26
@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 73f5daf

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

This PR includes changesets to release 23 packages
Name Type
@clerk/clerk-js Patch
@clerk/localizations Patch
@clerk/shared Patch
@clerk/ui Patch
@clerk/chrome-extension Patch
@clerk/electron Patch
@clerk/expo Patch
@clerk/react Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/headless Patch
@clerk/hono Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/vue Patch
@clerk/swingset 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

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview Aug 3, 2026 8:15pm
swingset Ready Ready Preview Aug 3, 2026 8:15pm

Request Review

@pkg-pr-new

pkg-pr-new Bot commented Aug 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

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

@clerk/backend

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

@clerk/chrome-extension

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

@clerk/clerk-js

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

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9316

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9316

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9316

@clerk/expo

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

@clerk/expo-google-signin

npm i https://pkg.pr.new/@clerk/expo-google-signin@9316

@clerk/expo-passkeys

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

@clerk/express

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

@clerk/fastify

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

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9316

@clerk/localizations

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

@clerk/nextjs

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

@clerk/nuxt

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

@clerk/react

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

@clerk/react-router

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

@clerk/shared

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

@clerk/tanstack-react-start

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

@clerk/testing

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

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9316

@clerk/upgrade

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

@clerk/vue

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

commit: 73f5daf

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-08-03T20:17:02.631Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 1
🔴 Breaking changes 0
🟡 Non-breaking changes 1
🟢 Additions 55

🤖 This report was reviewed by claude-sonnet-4-6.


@clerk/shared

Current version: 4.25.10
Recommended bump: MINOR → 4.26.0

Subpath ./types

🟡 Non-breaking Changes (1)

Modified: __internal_LocalizationResource
// ... 105 unchanged lines elided ...
    membershipRole__guestMember: LocalizationValue;
    billing: {
      month: LocalizationValue;
+     months: LocalizationValue;
      monthAbbreviation: LocalizationValue;
      monthPerUnit: LocalizationValue<'unitName'>;
      year: LocalizationValue;
+     years: LocalizationValue;
      yearAbbreviation: LocalizationValue;
      yearPerUnit: LocalizationValue<'unitName'>;
      free: LocalizationValue;
      getStarted: LocalizationValue;
      manage: LocalizationValue;
      manageSubscription: LocalizationValue;
      cancelSubscription: LocalizationValue;
      keepSubscription: LocalizationValue;
      reSubscribe: LocalizationValue;
      seats: LocalizationValue;
      seatsWithLimit: LocalizationValue<'limit'>;
      seatBreakdownSingular: LocalizationValue<'rate'>;
      seatBreakdownPlural: LocalizationValue<'chargeable' | 'rate'>;
      seatBreakdownIncludedSingular: LocalizationValue<'totalSeats' | 'included' | 'rate'>;
      seatBreakdownIncludedPlural: LocalizationValue<'totalSeats' | 'included' | 'chargeable' | 'rate'>;
      subscribe: LocalizationValue;
      startFreeTrial: LocalizationValue;
      startFreeTrial__days: LocalizationValue<'days'>;
      switchPlan: LocalizationValue;
      switchToMonthly: LocalizationValue;
      switchToAnnual: LocalizationValue;
      switchToMonthlyWithPrice: LocalizationValue<'price'>;
      switchToAnnualWithAnnualPrice: LocalizationValue<'price'>;
      billedAnnually: LocalizationValue;
      billedMonthly: LocalizationValue;
      billedMonthlyOnly: LocalizationValue;
      billedAnnuallyOnly: LocalizationValue;
      cancelFreeTrial: LocalizationValue<'plan'>;
      cancelFreeTrialTitle: LocalizationValue<'plan'>;
      cancelFreeTrialAccessUntil: LocalizationValue<'plan' | 'date'>;
      keepFreeTrial: LocalizationValue;
      alwaysFree: LocalizationValue;
      accountFunds: LocalizationValue;
      defaultFreePlanActive: LocalizationValue;
+     discountAmount: LocalizationValue<'amount'>;
+     discountCyclesRemaining: LocalizationValue<'cycles' | 'period'>;
+     discountDuration: LocalizationValue<'amount' | 'cycles' | 'period'>;
      viewFeatures: LocalizationValue;
      seeAllFeatures: LocalizationValue;
      viewPayment: LocalizationValue;
// ... 1914 unchanged lines elided ...

Static analyzer: Breaking change in type alias __internal_LocalizationResource: Type changed: {locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…{locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…

🤖 AI review (reclassified as non-breaking) (72%): The before and after snippets are structurally identical except for 5 additional lines elided in the after version (1987 vs 1982 lines), indicating new optional/required fields were added. __internal_LocalizationResource is only consumed via LocalizationResource which extends DeepPartial<DeepLocalizationWithoutObjects<__internal_LocalizationResource>>, making all fields optional in the consumer-facing type; adding new fields to an output/wrapped type that consumers only read (not construct directly against the raw internal type) is non-breaking. The internal type name prefix __internal_ also signals it is not intended for direct consumer construction.

🟢 Additions (55)

Click to expand 55 changes
Added: BillingAppliedDiscount
+ interface BillingAppliedDiscount

Added interface BillingAppliedDiscount

Added: BillingAppliedDiscount.amount
+ amount: BillingMoneyAmount;

Added property BillingAppliedDiscount.amount

Added: BillingAppliedDiscount.amountOff
+ amountOff?: BillingMoneyAmount;

Added property BillingAppliedDiscount.amountOff

Added: BillingAppliedDiscount.cyclesRemaining
+ cyclesRemaining: number | null;

Added property BillingAppliedDiscount.cyclesRemaining

Added: BillingAppliedDiscount.discountId
+ discountId: string;

Added property BillingAppliedDiscount.discountId

Added: BillingAppliedDiscount.effect
+ effect: 'percentage' | 'fixed_amount';

Added property BillingAppliedDiscount.effect

Added: BillingAppliedDiscount.name
+ name: string;

Added property BillingAppliedDiscount.name

Added: BillingAppliedDiscount.percentOff
+ percentOff?: number;

Added property BillingAppliedDiscount.percentOff

Added: BillingAppliedDiscount.promoCode
+ promoCode?: string;

Added property BillingAppliedDiscount.promoCode

Added: BillingAppliedDiscountJSON
+ interface BillingAppliedDiscountJSON

Added interface BillingAppliedDiscountJSON

Added: BillingAppliedDiscountJSON.amount_off
+ amount_off?: BillingMoneyAmountJSON;

Added property BillingAppliedDiscountJSON.amount_off

Added: BillingAppliedDiscountJSON.amount
+ amount: BillingMoneyAmountJSON;

Added property BillingAppliedDiscountJSON.amount

Added: BillingAppliedDiscountJSON.cycles_remaining
+ cycles_remaining: number | null;

Added property BillingAppliedDiscountJSON.cycles_remaining

Added: BillingAppliedDiscountJSON.discount_id
+ discount_id: string;

Added property BillingAppliedDiscountJSON.discount_id

Added: BillingAppliedDiscountJSON.effect
+ effect: 'percentage' | 'fixed_amount';

Added property BillingAppliedDiscountJSON.effect

Added: BillingAppliedDiscountJSON.name
+ name: string;

Added property BillingAppliedDiscountJSON.name

Added: BillingAppliedDiscountJSON.percent_off
+ percent_off?: number;

Added property BillingAppliedDiscountJSON.percent_off

Added: BillingAppliedDiscountJSON.promo_code
+ promo_code?: string;

Added property BillingAppliedDiscountJSON.promo_code

Added: BillingDiscountRedemption
+ interface BillingDiscountRedemption

Added interface BillingDiscountRedemption

Added: BillingDiscountRedemption.amount
+ amount?: BillingMoneyAmount;

Added property BillingDiscountRedemption.amount

Added: BillingDiscountRedemption.amountOff
+ amountOff?: BillingMoneyAmount;

Added property BillingDiscountRedemption.amountOff

Added: BillingDiscountRedemption.cyclesApplied
+ cyclesApplied: number;

Added property BillingDiscountRedemption.cyclesApplied

Added: BillingDiscountRedemption.cyclesRemaining
+ cyclesRemaining: number | null;

Added property BillingDiscountRedemption.cyclesRemaining

Added: BillingDiscountRedemption.discountId
+ discountId: string;

Added property BillingDiscountRedemption.discountId

Added: BillingDiscountRedemption.effect
+ effect?: 'percentage' | 'fixed_amount';

Added property BillingDiscountRedemption.effect

Added: BillingDiscountRedemption.id
+ id: string;

Added property BillingDiscountRedemption.id

Added: BillingDiscountRedemption.name
+ name: string;

Added property BillingDiscountRedemption.name

Added: BillingDiscountRedemption.percentOff
+ percentOff?: number;

Added property BillingDiscountRedemption.percentOff

Added: BillingDiscountRedemption.promoCode
+ promoCode?: string;

Added property BillingDiscountRedemption.promoCode

Added: BillingDiscountRedemption.redeemedAt
+ redeemedAt: Date;

Added property BillingDiscountRedemption.redeemedAt

Added: BillingDiscountRedemption.redeemedBy
+ redeemedBy: string | null;

Added property BillingDiscountRedemption.redeemedBy

Added: BillingDiscountRedemption.source
+ source: 'promotion' | 'manual' | 'promo_code';

Added property BillingDiscountRedemption.source

Added: BillingDiscountRedemption.status
+ status?: 'active' | 'exhausted' | 'removed';

Added property BillingDiscountRedemption.status

Added: BillingDiscountRedemption.subscriptionItemId
+ subscriptionItemId: string;

Added property BillingDiscountRedemption.subscriptionItemId

Added: BillingDiscountRedemptionJSON
+ interface BillingDiscountRedemptionJSON extends ClerkResourceJSON

Added interface BillingDiscountRedemptionJSON

Added: BillingDiscountRedemptionJSON.amount_off
+ amount_off?: BillingMoneyAmountJSON;

Added property BillingDiscountRedemptionJSON.amount_off

Added: BillingDiscountRedemptionJSON.amount
+ amount?: BillingMoneyAmountJSON;

Added property BillingDiscountRedemptionJSON.amount

Added: BillingDiscountRedemptionJSON.cycles_applied
+ cycles_applied: number;

Added property BillingDiscountRedemptionJSON.cycles_applied

Added: BillingDiscountRedemptionJSON.cycles_remaining
+ cycles_remaining: number | null;

Added property BillingDiscountRedemptionJSON.cycles_remaining

Added: BillingDiscountRedemptionJSON.discount_id
+ discount_id: string;

Added property BillingDiscountRedemptionJSON.discount_id

Added: BillingDiscountRedemptionJSON.effect
+ effect?: 'percentage' | 'fixed_amount';

Added property BillingDiscountRedemptionJSON.effect

Added: BillingDiscountRedemptionJSON.id
+ id: string;

Added property BillingDiscountRedemptionJSON.id

Added: BillingDiscountRedemptionJSON.name
+ name: string;

Added property BillingDiscountRedemptionJSON.name

Added: BillingDiscountRedemptionJSON.object
+ object: 'commerce_discount_redemption';

Added property BillingDiscountRedemptionJSON.object

Added: BillingDiscountRedemptionJSON.percent_off
+ percent_off?: number;

Added property BillingDiscountRedemptionJSON.percent_off

Added: BillingDiscountRedemptionJSON.promo_code
+ promo_code?: string;

Added property BillingDiscountRedemptionJSON.promo_code

Added: BillingDiscountRedemptionJSON.redeemed_at
+ redeemed_at: number;

Added property BillingDiscountRedemptionJSON.redeemed_at

Added: BillingDiscountRedemptionJSON.redeemed_by
+ redeemed_by: string | null;

Added property BillingDiscountRedemptionJSON.redeemed_by

Added: BillingDiscountRedemptionJSON.source
+ source: 'promotion' | 'manual' | 'promo_code';

Added property BillingDiscountRedemptionJSON.source

Added: BillingDiscountRedemptionJSON.status
+ status?: 'active' | 'exhausted' | 'removed';

Added property BillingDiscountRedemptionJSON.status

Added: BillingDiscountRedemptionJSON.subscription_item_id
+ subscription_item_id: string;

Added property BillingDiscountRedemptionJSON.subscription_item_id

Added: BillingDiscounts.discount
+ discount?: BillingAppliedDiscount;

Added property BillingDiscounts.discount

Added: BillingDiscountsJSON.discount
+ discount?: BillingAppliedDiscountJSON;

Added property BillingDiscountsJSON.discount

Added: BillingSubscriptionItemJSON.applied_discount
+ applied_discount?: BillingDiscountRedemptionJSON;

Added property BillingSubscriptionItemJSON.applied_discount

Added: BillingSubscriptionItemResource.appliedDiscount
+ appliedDiscount?: BillingDiscountRedemption;

Added property BillingSubscriptionItemResource.appliedDiscount


Report generated by Break Check

Last ran on 73f5daf.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 01de9796-2e5d-4b5c-864e-4861df23741c

📥 Commits

Reviewing files that changed from the base of the PR and between 6af04e8 and 73f5daf.

📒 Files selected for processing (58)
  • .changeset/green-dolphins-discount.md
  • packages/clerk-js/bundlewatch.config.json
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/utils/__tests__/billing.test.ts
  • packages/clerk-js/src/utils/billing.ts
  • packages/localizations/src/ar-SA.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/bn-IN.ts
  • packages/localizations/src/ca-ES.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/de-DE.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/en-GB.ts
  • packages/localizations/src/en-US.ts
  • packages/localizations/src/es-CR.ts
  • packages/localizations/src/es-ES.ts
  • packages/localizations/src/es-MX.ts
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/fa-IR.ts
  • packages/localizations/src/fi-FI.ts
  • packages/localizations/src/fr-FR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/hr-HR.ts
  • packages/localizations/src/hu-HU.ts
  • packages/localizations/src/id-ID.ts
  • packages/localizations/src/is-IS.ts
  • packages/localizations/src/it-IT.ts
  • packages/localizations/src/ja-JP.ts
  • packages/localizations/src/kk-KZ.ts
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/mn-MN.ts
  • packages/localizations/src/ms-MY.ts
  • packages/localizations/src/nb-NO.ts
  • packages/localizations/src/nl-BE.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/pl-PL.ts
  • packages/localizations/src/pt-BR.ts
  • packages/localizations/src/pt-PT.ts
  • packages/localizations/src/ro-RO.ts
  • packages/localizations/src/ru-RU.ts
  • packages/localizations/src/sk-SK.ts
  • packages/localizations/src/sr-RS.ts
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/ta-IN.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/th-TH.ts
  • packages/localizations/src/tr-TR.ts
  • packages/localizations/src/uk-UA.ts
  • packages/localizations/src/vi-VN.ts
  • packages/localizations/src/zh-CN.ts
  • packages/localizations/src/zh-TW.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
  • packages/shared/src/types/localization.ts
  • packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)
  • clerk/cli (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (58)
  • packages/localizations/src/sr-RS.ts
  • packages/shared/src/types/localization.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/shared/src/types/json.ts
  • packages/localizations/src/zh-TW.ts
  • packages/localizations/src/fr-FR.ts
  • packages/localizations/src/fa-IR.ts
  • packages/localizations/src/id-ID.ts
  • packages/clerk-js/bundlewatch.config.json
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/hr-HR.ts
  • packages/localizations/src/en-GB.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/de-DE.ts
  • packages/localizations/src/is-IS.ts
  • packages/clerk-js/src/utils/tests/billing.test.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/zh-CN.ts
  • packages/localizations/src/ja-JP.ts
  • packages/clerk-js/src/utils/billing.ts
  • packages/localizations/src/en-US.ts
  • packages/localizations/src/sk-SK.ts
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/pt-PT.ts
  • packages/localizations/src/ta-IN.ts
  • packages/localizations/src/fi-FI.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/es-MX.ts
  • packages/localizations/src/hu-HU.ts
  • packages/localizations/src/ro-RO.ts
  • .changeset/green-dolphins-discount.md
  • packages/localizations/src/ru-RU.ts
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/it-IT.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/vi-VN.ts
  • packages/localizations/src/kk-KZ.ts
  • packages/localizations/src/ca-ES.ts
  • packages/localizations/src/bn-IN.ts
  • packages/localizations/src/uk-UA.ts
  • packages/localizations/src/es-ES.ts
  • packages/localizations/src/es-CR.ts
  • packages/localizations/src/he-IL.ts
  • packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/tr-TR.ts
  • packages/localizations/src/ar-SA.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/pl-PL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/ms-MY.ts
  • packages/localizations/src/nb-NO.ts
  • packages/localizations/src/nl-BE.ts
  • packages/shared/src/types/billing.ts
  • packages/localizations/src/pt-BR.ts
  • packages/localizations/src/th-TH.ts
  • packages/localizations/src/mn-MN.ts

📝 Walkthrough

Walkthrough

Added billing discount contracts and JSON conversion. Subscription items now expose applied discount redemptions. The subscription overview renders active discount details and localized amounts. Billing localization keys were added across supported resources. Tests cover fixed discounts, percentage discounts, and redemption mapping. A patch changeset and bundle size limit update were added.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • clerk/javascript#9256: Both PRs update packages/clerk-js/bundlewatch.config.json to adjust Bundlewatch size limits.

Suggested reviewers: mauricioabreu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: rendering discounts on subscription items across the listed packages.
Description check ✅ Passed The description directly explains that the pull request adds discount rendering support for subscription items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Linked repositories: Couldn't analyze clerk/clerk-android - clone failed: Clone operation failed: Cloning into '/home/jailuser/git'...
From https://github.com/clerk/clerk-android

Errors logged to '/home/jailuser/git/.git/lfs/logs/20260803T202050.40595017.log'.
Use git lfs logs last to view the log.
error: external filter 'git-lfs filter-process' failed
fatal: config/bin/detekt-cli: smudge filter lfs failed
Downloading config/bin/detekt-cli (71 MB)
Error downloading object: config/bin/detekt-cli (2655f48): Smudge error: Error downloading config/bin/detekt-cli (2655f48c7c303a5f9bf920a33229408b8571bb1d29e4e57cf7be3e151bceecb1): LFS: Client error: https://github-cloud.githubusercontent.com/alambic/media/877189286/26/55/2655f48c7c303a5f9bf920a33229408b8571bb1d29e4e57cf7be3e151bceecb1?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIA5BA2674WPWWEFGQ5%2F20260803%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260803T202210Z&X-Amz-Expires=3600&X-Amz-Signature=626ce9dfb138a851d3cfa15ef911104702811c95dee76911b4e8f03172e18dd5&X-Amz-SignedHeaders=host&actor_id=136622811&key_id=0&repo_id=980409545&token=1

Errors logged to '/home/jailuser/git/.git/lfs/logs/20260803T202210.199794141.log'.
Use git lfs logs last to view the log.
error: external filter 'git-lfs filter-process' failed
fatal: config/bin/detekt-cli: smudge filter lfs failed


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

1032-1069: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add per-field JSDoc to the new discount interfaces.

BillingAppliedDiscount and BillingDiscountRedemption only carry an interface-level @experimental comment. Every other interface in this file, including BillingSubscriptionItemResource and BillingDiscounts, documents each property individually. Add a short doc comment to each field (amount, discountId, effect, percentOff, amountOff, promoCode, cyclesRemaining, source, status, redeemedAt, redeemedBy, etc.) so consumers of this new public, experimental API understand the field semantics without cross-referencing the JSON layer.

As per coding guidelines, "All public APIs must be documented with JSDoc" and "TypeScript is required for all packages... Maintain comprehensive JSDoc comments for public APIs."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/types/billing.ts` around lines 1032 - 1069, Add
individual JSDoc comments for every property in the public interfaces
BillingAppliedDiscount and BillingDiscountRedemption, including identifiers,
monetary fields, discount effects, cycle counters, source/status values,
redemption timestamps, and redeemer information. Keep the existing
interface-level experimental documentation and ensure each comment clearly
describes the field’s semantics without relying on JSON-layer definitions.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/localizations/src/en-US.ts`:
- Around line 125-126: Update the discount localization usage associated with
SubscriptionDiscountRow so a single cycle uses the singular billing.month or
billing.year label, while multiple cycles retain billing.months or
billing.years. Ensure both discountCyclesRemaining and discountDuration render
grammatically correct singular and plural wording.

In `@packages/ui/src/components/Subscriptions/SubscriptionsList.tsx`:
- Around line 258-302: Update the period-label logic near discountTitle so
singular keys are selected when each relevant cycle count equals 1, reusing the
existing billing.month/year keys and plural keys otherwise. Replace the shared
period value in discountDuration with a label based on totalCycles and in
discountCyclesRemaining with a label based on appliedDiscount.cyclesRemaining,
using the existing getPeriodLabel helper if available.

---

Nitpick comments:
In `@packages/shared/src/types/billing.ts`:
- Around line 1032-1069: Add individual JSDoc comments for every property in the
public interfaces BillingAppliedDiscount and BillingDiscountRedemption,
including identifiers, monetary fields, discount effects, cycle counters,
source/status values, redemption timestamps, and redeemer information. Keep the
existing interface-level experimental documentation and ensure each comment
clearly describes the field’s semantics without relying on JSON-layer
definitions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b94bfa3-1098-4c76-ae70-37dedd04e586

📥 Commits

Reviewing files that changed from the base of the PR and between 8b420c2 and 5a98c57.

📒 Files selected for processing (57)
  • .changeset/green-dolphins-discount.md
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/utils/__tests__/billing.test.ts
  • packages/clerk-js/src/utils/billing.ts
  • packages/localizations/src/ar-SA.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/bn-IN.ts
  • packages/localizations/src/ca-ES.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/de-DE.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/en-GB.ts
  • packages/localizations/src/en-US.ts
  • packages/localizations/src/es-CR.ts
  • packages/localizations/src/es-ES.ts
  • packages/localizations/src/es-MX.ts
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/fa-IR.ts
  • packages/localizations/src/fi-FI.ts
  • packages/localizations/src/fr-FR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/hr-HR.ts
  • packages/localizations/src/hu-HU.ts
  • packages/localizations/src/id-ID.ts
  • packages/localizations/src/is-IS.ts
  • packages/localizations/src/it-IT.ts
  • packages/localizations/src/ja-JP.ts
  • packages/localizations/src/kk-KZ.ts
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/mn-MN.ts
  • packages/localizations/src/ms-MY.ts
  • packages/localizations/src/nb-NO.ts
  • packages/localizations/src/nl-BE.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/pl-PL.ts
  • packages/localizations/src/pt-BR.ts
  • packages/localizations/src/pt-PT.ts
  • packages/localizations/src/ro-RO.ts
  • packages/localizations/src/ru-RU.ts
  • packages/localizations/src/sk-SK.ts
  • packages/localizations/src/sr-RS.ts
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/ta-IN.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/th-TH.ts
  • packages/localizations/src/tr-TR.ts
  • packages/localizations/src/uk-UA.ts
  • packages/localizations/src/vi-VN.ts
  • packages/localizations/src/zh-CN.ts
  • packages/localizations/src/zh-TW.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
  • packages/shared/src/types/localization.ts
  • packages/ui/src/components/Subscriptions/SubscriptionsList.tsx
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)
  • clerk/cli (auto-detected)

Comment on lines +125 to +126
discountCyclesRemaining: '{{cycles}} {{period}} remaining',
discountDuration: '({{amount}} off first {{cycles}} {{period}})',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix singular discount wording.

SubscriptionDiscountRow always passes the plural billing.months or billing.years label. When cycles is 1, the UI renders first 1 years and 1 years remaining. Select billing.month or billing.year for one cycle, or add singular/plural-aware localization variants.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/localizations/src/en-US.ts` around lines 125 - 126, Update the
discount localization usage associated with SubscriptionDiscountRow so a single
cycle uses the singular billing.month or billing.year label, while multiple
cycles retain billing.months or billing.years. Ensure both
discountCyclesRemaining and discountDuration render grammatically correct
singular and plural wording.

Comment on lines +258 to +302
const totalCycles =
appliedDiscount.cyclesRemaining === null ? null : appliedDiscount.cyclesApplied + appliedDiscount.cyclesRemaining;
const period = t(
subscriptionItem.planPeriod === 'annual' ? localizationKeys('billing.years') : localizationKeys('billing.months'),
).toLocaleLowerCase();

const discountAmount =
appliedDiscount.effect === 'percentage' && appliedDiscount.percentOff !== undefined
? `${appliedDiscount.percentOff}%`
: appliedDiscount.amountOff
? $(appliedDiscount.amountOff)
: '';
const discountTitle = `${appliedDiscount.name} ${t(
totalCycles === null
? localizationKeys('billing.discountAmount', { amount: discountAmount })
: localizationKeys('billing.discountDuration', {
amount: discountAmount,
cycles: totalCycles,
period,
}),
)}`;

return (
<Tr
sx={t =>
subscriptionItem.status === 'upcoming'
? {
background: common.mutedBackground(t),
}
: {}
}
>
<Td sx={{ verticalAlign: 'top' }}>
<Col gap={1}>
<Text variant='subtitle'>{discountTitle}</Text>
{appliedDiscount.cyclesRemaining !== null ? (
<Text
variant='subtitle'
colorScheme='secondary'
localizationKey={localizationKeys('billing.discountCyclesRemaining', {
cycles: appliedDiscount.cyclesRemaining,
period,
})}
/>
) : null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix incorrect singular/plural period text ("1 years").

period always resolves to the plural billing.years or billing.months string, regardless of the actual count. discountTitle (lines 270-278) and the remaining-cycles caption (lines 293-302) both interpolate this always-plural period into the count-based message. For a count of 1, this produces incorrect text such as "25% off first 1 years" and "1 years remaining", exactly as shown in the PR's own screenshot.

Select the singular form when the relevant count equals 1. The singular keys billing.month and billing.year are already used elsewhere in this file (see the fee-suffix logic near line 400).

✏️ Proposed fix for singular/plural period selection
-  const totalCycles =
-    appliedDiscount.cyclesRemaining === null ? null : appliedDiscount.cyclesApplied + appliedDiscount.cyclesRemaining;
-  const period = t(
-    subscriptionItem.planPeriod === 'annual' ? localizationKeys('billing.years') : localizationKeys('billing.months'),
-  ).toLocaleLowerCase();
+  const totalCycles =
+    appliedDiscount.cyclesRemaining === null ? null : appliedDiscount.cyclesApplied + appliedDiscount.cyclesRemaining;
+  const getPeriodLabel = (count: number) => {
+    const isAnnual = subscriptionItem.planPeriod === 'annual';
+    const key = count === 1 ? (isAnnual ? 'billing.year' : 'billing.month') : isAnnual ? 'billing.years' : 'billing.months';
+    return t(localizationKeys(key)).toLocaleLowerCase();
+  };

Then use getPeriodLabel(totalCycles ?? 0) for the discountDuration call and getPeriodLabel(appliedDiscount.cyclesRemaining ?? 0) for the discountCyclesRemaining call, in place of the single shared period variable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/components/Subscriptions/SubscriptionsList.tsx` around lines
258 - 302, Update the period-label logic near discountTitle so singular keys are
selected when each relevant cycle count equals 1, reusing the existing
billing.month/year keys and plural keys otherwise. Replace the shared period
value in discountDuration with a label based on totalCycles and in
discountCyclesRemaining with a label based on appliedDiscount.cyclesRemaining,
using the existing getPeriodLabel helper if available.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants