This commit is contained in:
2026-01-07 20:19:26 -05:00
parent 244c8b6fb5
commit f056cf05d3
21 changed files with 2407 additions and 168 deletions

View File

@@ -1,9 +1,76 @@
import { SignJWT } from "jose";
import { env } from "~/env/server";
import { AUTH_CONFIG } from "~/config";
import { AUTH_CONFIG, NETWORK_CONFIG } from "~/config";
import {
fetchWithTimeout,
checkResponse,
fetchWithRetry
} from "~/server/fetch-utils";
export const LINEAGE_JWT_EXPIRY = AUTH_CONFIG.LINEAGE_JWT_EXPIRY;
/**
* Generic email sending function
* @param to - Recipient email address
* @param subject - Email subject
* @param htmlContent - HTML content of the email
* @returns Success status
*/
export default async function sendEmail(
to: string,
subject: string,
htmlContent: string
): Promise<{ success: boolean; messageId?: string; message?: string }> {
const apiKey = env.SENDINBLUE_KEY;
const apiUrl = "https://api.sendinblue.com/v3/smtp/email";
const emailPayload = {
sender: {
name: "freno.me",
email: "no_reply@freno.me"
},
to: [{ email: to }],
htmlContent,
subject
};
try {
const response = await fetchWithRetry(
async () => {
const res = await fetchWithTimeout(apiUrl, {
method: "POST",
headers: {
accept: "application/json",
"api-key": apiKey,
"content-type": "application/json"
},
body: JSON.stringify(emailPayload),
timeout: NETWORK_CONFIG.EMAIL_API_TIMEOUT_MS
});
await checkResponse(res);
return res;
},
{
maxRetries: NETWORK_CONFIG.MAX_RETRIES,
retryDelay: NETWORK_CONFIG.RETRY_DELAY_MS
}
);
const json = (await response.json()) as { messageId?: string };
if (json.messageId) {
return { success: true, messageId: json.messageId };
}
return { success: false, message: "No messageId in response" };
} catch (error) {
console.error("Email sending error:", error);
return {
success: false,
message: error instanceof Error ? error.message : "Email service error"
};
}
}
export async function sendEmailVerification(userEmail: string): Promise<{
success: boolean;
messageId?: string;