import { z } from 'zod'; import { getLogger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; type Account = Database['public']['Tables']['accounts']['Row']; export function createAccountWebhooksService() { return new AccountWebhooksService(); } class AccountWebhooksService { private readonly namespace = 'accounts.webhooks'; async handleAccountDeletedWebhook(account: Account) { const logger = await getLogger(); const ctx = { accountId: account.id, namespace: this.namespace, }; logger.info(ctx, 'Received account deleted webhook. Processing...'); if (account.is_personal_account) { logger.info(ctx, `Account is personal. We send an email to the user.`); await this.sendDeleteAccountEmail(account); } } private async sendDeleteAccountEmail(account: Account) { const userEmail = account.email; const userDisplayName = account.name ?? userEmail; const emailSettings = this.getEmailSettings(); if (userEmail) { await this.sendAccountDeletionEmail({ fromEmail: emailSettings.fromEmail, productName: emailSettings.productName, userDisplayName, userEmail, }); } } private async sendAccountDeletionEmail(params: { fromEmail: string; userEmail: string; userDisplayName: string; productName: string; }) { const { renderAccountDeleteEmail } = await import('@kit/email-templates'); const { getMailer } = await import('@kit/mailers'); const mailer = await getMailer(); const { html, subject } = await renderAccountDeleteEmail({ userDisplayName: params.userDisplayName, productName: params.productName, }); return mailer.sendEmail({ to: params.userEmail, from: params.fromEmail, subject, html, }); } private getEmailSettings() { const productName = process.env.NEXT_PUBLIC_PRODUCT_NAME; const fromEmail = process.env.EMAIL_SENDER; return z .object({ productName: z.string(), fromEmail: z.string({ required_error: 'EMAIL_SENDER is required', }).min(1), }) .parse({ productName, fromEmail, }); } }