feat(cloud): enable seat based pricing (#161)

* feat: setup subscriptions

* feat: prompt user to create subscription if inactive

* feat: update subscription when increasing/decreasing workspace members

* feat: rework upgrade

* chore: remove pricing notice

* chore: add translations

* chore: update proration comment
This commit is contained in:
Henry
2025-09-02 22:36:09 +01:00
committed by GitHub
parent e3d7ace8bd
commit 06c268bed1
33 changed files with 7483 additions and 4352 deletions

View File

@@ -10,11 +10,65 @@ const createStripeClient = () => {
}
const stripe = new Stripe(stripeSecretKey, {
apiVersion: "2025-05-28.basil",
httpClient: Stripe.createFetchHttpClient(),
apiVersion: "2025-08-27.basil",
});
return stripe;
};
export const updateSubscriptionSeats = async (
stripeSubscriptionId: string,
seatIncrement = 1,
): Promise<Stripe.Subscription> => {
const stripe = createStripeClient();
// First, retrieve the current subscription to get the subscription items
const subscription = await stripe.subscriptions.retrieve(
stripeSubscriptionId,
{
expand: ["items"],
},
);
if (!subscription.items.data.length) {
throw new Error(
`No subscription items found for subscription ${stripeSubscriptionId}`,
);
}
// Get the first subscription item
const subscriptionItem = subscription.items.data[0];
if (!subscriptionItem) {
throw new Error(
`No subscription item found for subscription ${stripeSubscriptionId}`,
);
}
const currentQuantity = subscriptionItem.quantity ?? 1;
const newQuantity = currentQuantity + seatIncrement;
// Ensure we don't go below 1 seat
if (newQuantity < 1) {
throw new Error(
`Cannot reduce seats below 1. Current: ${currentQuantity}, Requested change: ${seatIncrement}`,
);
}
// Update the subscription with the new quantity and immediate invoicing
const updatedSubscription = await stripe.subscriptions.update(
stripeSubscriptionId,
{
items: [
{
id: subscriptionItem.id,
quantity: newQuantity,
},
],
proration_behavior: "always_invoice", // Invoice immediately
},
);
return updatedSubscription;
};
export { createStripeClient };