Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
2.5 kB ยท 90 lines
TypeScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091import { EmailClient } from "@openstatus/emails";import { z } from "zod";
import type { PageUpdate, Subscription } from "../types";
let emailClient: EmailClient | null = null;
function getEmailClient(): EmailClient { if (!emailClient) { if (!process.env.RESEND_API_KEY) { throw new Error( "RESEND_API_KEY environment variable is required for email notifications", ); } emailClient = new EmailClient({ apiKey: process.env.RESEND_API_KEY, }); } return emailClient;}
export async function validateEmailConfig(config: unknown) { const email = z.email().safeParse(config); return { valid: email.success, error: email.error?.message };}
// Stable per status-report update / maintenance so Resend dedupes the email// retry path. Status reports key off the specific update; maintenance has no// update row, so fall back to its id + status.function idempotencyKeyFor(pageUpdate: PageUpdate): string { return pageUpdate.updateId != null ? `status-report-update:${pageUpdate.updateId}` : `page-update:${pageUpdate.id}:${pageUpdate.status}`;}
function hasEmailAndToken( sub: Subscription,): sub is Subscription & { email: string; token: string } { return ( sub.email !== undefined && sub.email !== null && sub.token !== undefined && sub.token !== null );}
export async function sendEmailVerification( subscription: Subscription, verifyUrl: string,) { if (!subscription.email) { throw new Error("Email is required for email channel"); }
const client = getEmailClient(); await client.sendPageSubscription({ to: subscription.email, link: verifyUrl, page: subscription.pageName, });}
export async function sendEmailNotifications( subscriptions: Subscription[], pageUpdate: PageUpdate,) { if (subscriptions.length === 0) return;
const validSubscriptions = subscriptions.filter(hasEmailAndToken); if (validSubscriptions.length === 0) return;
const firstSub = validSubscriptions[0];
const client = getEmailClient(); await client.sendStatusReportUpdate({ subscribers: validSubscriptions.map((sub) => ({ email: sub.email, token: sub.token, })), pageTitle: firstSub.pageName, pageSlug: firstSub.pageSlug, customDomain: firstSub.customDomain, reportTitle: pageUpdate.title, status: pageUpdate.status, message: pageUpdate.message, date: pageUpdate.date, pageComponents: pageUpdate.pageComponents, idempotencyKey: idempotencyKeyFor(pageUpdate), });}