Skip to content

feat(clerk-js, types): Update billing resources with trial properties #6492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/sour-lemons-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/clerk-js': minor
'@clerk/types': minor
---

Update billing resources with trial properties.
5 changes: 5 additions & 0 deletions packages/clerk-js/src/core/resources/CommerceSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class CommerceSubscription extends BaseResource implements CommerceSubscr
date: Date;
} | null = null;
subscriptionItems!: CommerceSubscriptionItemResource[];
eligibleForFreeTrial?: boolean;

constructor(data: CommerceSubscriptionJSON) {
super();
Expand All @@ -51,6 +52,7 @@ export class CommerceSubscription extends BaseResource implements CommerceSubscr
}
: null;
this.subscriptionItems = (data.subscription_items || []).map(item => new CommerceSubscriptionItem(item));
this.eligibleForFreeTrial = data.eligible_for_free_trial;
return this;
}
}
Expand All @@ -71,6 +73,7 @@ export class CommerceSubscriptionItem extends BaseResource implements CommerceSu
credit?: {
amount: CommerceMoney;
};
isFreeTrial = false;

constructor(data: CommerceSubscriptionItemJSON) {
super();
Expand All @@ -97,6 +100,8 @@ export class CommerceSubscriptionItem extends BaseResource implements CommerceSu

this.amount = data.amount ? commerceMoneyFromJSON(data.amount) : undefined;
this.credit = data.credit && data.credit.amount ? { amount: commerceMoneyFromJSON(data.credit.amount) } : undefined;

this.isFreeTrial = this.withDefault(data.is_free_trial, false);
return this;
}

Expand Down
19 changes: 19 additions & 0 deletions packages/types/src/commerce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,15 @@ export interface CommerceSubscriptionItemResource extends ClerkResource {
* ```
*/
cancel: (params: CancelSubscriptionParams) => Promise<DeletedObjectResource>;
/**
* @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" />
* ```
*/
isFreeTrial: boolean;
}

/**
Expand Down Expand Up @@ -1203,6 +1212,16 @@ export interface CommerceSubscriptionResource extends ClerkResource {
* ```
*/
updatedAt: Date | null;

/**
* @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" />
* ```
*/
eligibleForFreeTrial?: boolean;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ export interface CommerceSubscriptionItemJSON extends ClerkResourceJSON {
period_end: number | null;
canceled_at: number | null;
past_due_at: number | null;
is_free_trial: boolean;
}
Comment on lines +786 to 787
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

Required JSON field may break backward-compat; ensure safe runtime default.

is_free_trial is required here. If older API responses omit it, runtime code will assign undefined over the initial default. Prefer keeping it required only if the backend guarantees presence across all records. Otherwise either:

  • keep it required but default safely during deserialization, or
  • make it optional in the JSON type.

Follow-up fix (in runtime mapping) to preserve a safe default:

Apply in packages/clerk-js/src/core/resources/CommerceSubscription.ts:

-    this.isFreeTrial = data.is_free_trial;
+    this.isFreeTrial = data.is_free_trial ?? false;

🏁 Script executed:

#!/bin/bash
# Locate CommerceSubscription.ts
echo "CommerceSubscription.ts files:"
rg -l "CommerceSubscription" -g "*.ts"

# Inspect JSON mapping references in clerk-js
echo -e "\nMapping of is_free_trial in clerk-js runtime:"
rg -n "is_free_trial" -C2 packages/clerk-js/src

echo -e "\nAssignment to isFreeTrial in clerk-js runtime:"
rg -n "isFreeTrial" -C2 packages/clerk-js/src

Length of output: 2519


Ensure safe default for isFreeTrial when deserializing JSON

To prevent legacy responses from clearing the default, update the runtime mapping in packages/clerk-js/src/core/resources/CommerceSubscription.ts:

  • At line 110 (inside the constructor), change
    - this.isFreeTrial = data.is_free_trial;
    + this.isFreeTrial = data.is_free_trial ?? false;

Optional: if the backend cannot guarantee is_free_trial is always present, also update the JSON type in packages/types/src/json.ts:

- interface CommerceSubscriptionItemJSON {
-   is_free_trial: boolean;
+ interface CommerceSubscriptionItemJSON {
+   /** Indicates whether this subscription item started with a free trial */
+   is_free_trial?: boolean;

This preserves backward compatibility while clarifying the field’s semantics.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/types/src/json.ts at lines 783-784, ensure the isFreeTrial field has
a safe default when deserializing JSON by updating the runtime mapping in
packages/clerk-js/src/core/resources/CommerceSubscription.ts around line 110
inside the constructor. Modify the mapping to provide a default value for
is_free_trial if it is missing, and optionally update the JSON type definition
here to reflect that is_free_trial may be optional or have a default, preserving
backward compatibility and clarifying the field's semantics.


/**
Expand Down Expand Up @@ -812,6 +813,7 @@ export interface CommerceSubscriptionJSON extends ClerkResourceJSON {
updated_at: number | null;
past_due_at: number | null;
subscription_items: CommerceSubscriptionItemJSON[] | null;
eligible_for_free_trial?: boolean;
}

/**
Expand Down
Loading