81 lines
1.9 KiB
TypeScript
81 lines
1.9 KiB
TypeScript
import type { Env } from "./env";
|
|
|
|
export type AuthEmailKind = "verify-email" | "reset-password" | "email-otp" | "magic-link";
|
|
|
|
export interface AuthEmailInput {
|
|
kind: AuthEmailKind;
|
|
to: string;
|
|
url?: string;
|
|
otp?: string;
|
|
}
|
|
|
|
export interface EmailMessage {
|
|
to: string;
|
|
subject: string;
|
|
text: string;
|
|
}
|
|
|
|
export function buildAuthEmail(input: AuthEmailInput): EmailMessage {
|
|
if (input.kind === "email-otp") {
|
|
return {
|
|
to: input.to,
|
|
subject: "Your sign-in code",
|
|
text: `Your sign-in code is ${input.otp ?? ""}.`,
|
|
};
|
|
}
|
|
|
|
if (input.kind === "reset-password") {
|
|
return {
|
|
to: input.to,
|
|
subject: "Reset your password",
|
|
text: `Use this link to reset your password: ${input.url ?? ""}`,
|
|
};
|
|
}
|
|
|
|
if (input.kind === "magic-link") {
|
|
return {
|
|
to: input.to,
|
|
subject: "Sign in to your account",
|
|
text: `Use this link to sign in: ${input.url ?? ""}`,
|
|
};
|
|
}
|
|
|
|
return {
|
|
to: input.to,
|
|
subject: "Verify your email",
|
|
text: `Use this link to verify your email: ${input.url ?? ""}`,
|
|
};
|
|
}
|
|
|
|
export async function sendEmail(env: Env, message: EmailMessage): Promise<void> {
|
|
if (!env.MAIL_PROVIDER) {
|
|
throw new Error("MAIL_PROVIDER is not configured");
|
|
}
|
|
|
|
if (env.MAIL_PROVIDER !== "resend") {
|
|
throw new Error(`Unsupported MAIL_PROVIDER: ${env.MAIL_PROVIDER}`);
|
|
}
|
|
|
|
if (!env.RESEND_API_KEY || !env.MAIL_FROM) {
|
|
throw new Error("RESEND_API_KEY and MAIL_FROM are required for resend");
|
|
}
|
|
|
|
const response = await fetch("https://api.resend.com/emails", {
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: `Bearer ${env.RESEND_API_KEY}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
from: env.MAIL_FROM,
|
|
to: message.to,
|
|
subject: message.subject,
|
|
text: message.text,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Email provider failed: ${response.status}`);
|
|
}
|
|
}
|