Compare commits

...

1 Commits

Author SHA1 Message Date
Henry
6b323c463a feat(cloud): free trial notifications 2025-11-25 23:28:18 +00:00
3 changed files with 67 additions and 20 deletions

View File

@@ -1,3 +1,5 @@
import type { Subscription } from "@better-auth/stripe";
import type Stripe from "stripe";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { stripe } from "@better-auth/stripe";
import { ChatOrPushProviderEnum } from "@novu/api/models/components";
@@ -179,19 +181,17 @@ export const initAuth = (db: dbClient) => {
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
// Called when a trial starts
// @todo: send trial start email
// await sendTrialStartEmail(subscription.referenceId);
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }, request) => {
// Called when a trial ends
// @todo: send trial end email
// await sendTrialEndEmail(user.email);
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
// Called when a trial expires without conversion
// @todo: send trial expired email
// await sendTrialExpiredEmail(subscription.referenceId);
await triggerWorkflow(
db,
"trial-expired",
subscription,
);
},
},
},
@@ -203,19 +203,17 @@ export const initAuth = (db: dbClient) => {
freeTrial: {
days: 14,
onTrialStart: async (subscription) => {
// Called when a trial starts
// @todo: send trial start email
// await sendTrialStartEmail(subscription.referenceId);
await triggerWorkflow(db, "trial-start", subscription);
},
onTrialEnd: async ({ subscription }, request) => {
// Called when a trial ends
// @todo: send trial end email
// await sendTrialEndEmail(user.email);
onTrialEnd: async ({ subscription }) => {
await triggerWorkflow(db, "trial-end", subscription);
},
onTrialExpired: async (subscription) => {
// Called when a trial expires without conversion
// @todo: send trial expired email
// await sendTrialExpiredEmail(subscription.referenceId);
await triggerWorkflow(
db,
"trial-expired",
subscription,
);
},
},
},
@@ -474,3 +472,34 @@ export const initAuth = (db: dbClient) => {
},
});
};
async function triggerWorkflow(
db: dbClient,
workflowId: string,
subscription: Subscription,
cancellationDetails?: Stripe.Subscription.CancellationDetails | null,
) {
try {
if (!subscription.stripeCustomerId || !notificationClient) return;
const user = await userRepo.getByStripeCustomerId(
db,
subscription.stripeCustomerId,
);
if (!user || !notificationClient) return;
await notificationClient.trigger({
to: {
subscriberId: user.id,
},
payload: {
...subscription,
cancellationDetails,
},
workflowId,
});
} catch (error) {
console.error("Error triggering workflow", error);
}
}

View File

@@ -28,6 +28,15 @@ export const getById = async (db: dbClient, userId: string) => {
});
};
export const getByStripeCustomerId = async (
db: dbClient,
stripeCustomerId: string,
) => {
return await db.query.users.findFirst({
where: eq(users.stripeCustomerId, stripeCustomerId),
});
};
export const getByEmail = (db: dbClient, email: string) => {
return db.query.users.findFirst({
columns: {

View File

@@ -71,4 +71,13 @@ export const updateSubscriptionSeats = async (
return updatedSubscription;
};
export const getCancellationDetails = async (
stripeSubscriptionId: string,
): Promise<Stripe.Subscription.CancellationDetails | null> => {
const stripe = createStripeClient();
const stripeSubscription =
await stripe.subscriptions.retrieve(stripeSubscriptionId);
return stripeSubscription.cancellation_details ?? null;
};
export { createStripeClient };