This commit replaces the use of Logger with getLogger in various parts of the code to handle logging. The Logger has been replaced with getLogger, which assists in getting logs in an asynchronous manner. In addition to this, it updates the next version in pnpm-lock.yaml from next@14.2.0-canary.61 to next@14.2.0-canary.62 and various other dependencies. Also made minor annotations and comments to the function 'isBrowser' and 'formatCurrency' in the 'utils.ts' file.
115 lines
2.9 KiB
TypeScript
115 lines
2.9 KiB
TypeScript
import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
|
import { z } from 'zod';
|
|
|
|
import { getLogger } from '@kit/shared/logger';
|
|
import { Database } from '@kit/supabase/database';
|
|
|
|
type Invitation = Database['public']['Tables']['invitations']['Row'];
|
|
|
|
const invitePath = process.env.INVITATION_PAGE_PATH;
|
|
const siteURL = process.env.NEXT_PUBLIC_SITE_URL;
|
|
const productName = process.env.NEXT_PUBLIC_PRODUCT_NAME ?? '';
|
|
const emailSender = process.env.EMAIL_SENDER;
|
|
|
|
const env = z
|
|
.object({
|
|
invitePath: z.string().min(1),
|
|
siteURL: z.string().min(1),
|
|
productName: z.string(),
|
|
emailSender: z.string().email(),
|
|
})
|
|
.parse({
|
|
invitePath,
|
|
siteURL,
|
|
productName,
|
|
emailSender,
|
|
});
|
|
|
|
export class AccountInvitationsWebhookService {
|
|
private namespace = 'accounts.invitations.webhook';
|
|
|
|
constructor(private readonly client: SupabaseClient<Database>) {}
|
|
|
|
async handleInvitationWebhook(invitation: Invitation) {
|
|
return this.dispatchInvitationEmail(invitation);
|
|
}
|
|
|
|
private async dispatchInvitationEmail(invitation: Invitation) {
|
|
const inviter = await this.client
|
|
.from('accounts')
|
|
.select('email, name')
|
|
.eq('id', invitation.invited_by)
|
|
.single();
|
|
|
|
if (inviter.error) {
|
|
throw inviter.error;
|
|
}
|
|
|
|
const team = await this.client
|
|
.from('accounts')
|
|
.select('name')
|
|
.eq('id', invitation.account_id)
|
|
.single();
|
|
|
|
if (team.error) {
|
|
throw team.error;
|
|
}
|
|
|
|
const logger = await getLogger();
|
|
|
|
try {
|
|
const { renderInviteEmail } = await import('@kit/email-templates');
|
|
const { getMailer } = await import('@kit/mailers');
|
|
const mailer = await getMailer();
|
|
|
|
const html = renderInviteEmail({
|
|
link: this.getInvitationLink(invitation.invite_token),
|
|
invitedUserEmail: invitation.email,
|
|
inviter: inviter.data.name ?? inviter.data.email ?? '',
|
|
productName: env.productName,
|
|
teamName: team.data.name,
|
|
});
|
|
|
|
await mailer
|
|
.sendEmail({
|
|
from: env.emailSender,
|
|
to: invitation.email,
|
|
subject: 'You have been invited to join a team',
|
|
html,
|
|
})
|
|
.then(() => {
|
|
logger.info('Invitation email sent', {
|
|
email: invitation.email,
|
|
account: invitation.account_id,
|
|
name: this.namespace,
|
|
});
|
|
})
|
|
.catch((error) => {
|
|
logger.warn(
|
|
{ error, name: this.namespace },
|
|
'Failed to send invitation email',
|
|
);
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
};
|
|
} catch (error) {
|
|
logger.warn(
|
|
{ error, name: this.namespace },
|
|
'Failed to invite user to team',
|
|
);
|
|
|
|
return {
|
|
error,
|
|
success: false,
|
|
};
|
|
}
|
|
}
|
|
|
|
private getInvitationLink(token: string) {
|
|
return new URL(env.invitePath, env.siteURL).href + `?invite_token=${token}`;
|
|
}
|
|
}
|