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.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146import { and, eq } from "@openstatus/db";import { invitation, pageSubscriber, selectWorkspaceSchema,} from "@openstatus/db/src/schema";import { EmailClient } from "@openstatus/emails";import { getChannel } from "@openstatus/subscriptions";import { TRPCError } from "@trpc/server";import { z } from "zod";
import { env } from "../../env";import { createTRPCRouter, protectedProcedure, publicProcedure,} from "../../trpc";
const emailClient = new EmailClient({ apiKey: env.RESEND_API_KEY });
export const emailRouter = createTRPCRouter({ /** * PUBLIC: Send verification email for a new page subscription * Called after upsert to trigger the verification flow */ sendPageSubscriptionVerification: publicProcedure .input( z.object({ id: z.number().int().positive(), token: z.uuid(), }), ) .mutation(async (opts) => { const subscriber = await opts.ctx.db.query.pageSubscriber.findFirst({ where: and( eq(pageSubscriber.id, opts.input.id), eq(pageSubscriber.token, opts.input.token), ), with: { page: { with: { workspace: true, }, }, }, });
if (!subscriber) { throw new TRPCError({ code: "NOT_FOUND", message: "Subscriber not found", }); }
const workspace = selectWorkspaceSchema.safeParse( subscriber.page?.workspace, );
if (!workspace.success) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Invalid workspace", }); }
if (!workspace.data.limits["status-subscribers"]) { return; }
if (!subscriber.email) { throw new TRPCError({ code: "BAD_REQUEST", message: "No email associated with this subscription", }); }
if (subscriber.acceptedAt) { throw new TRPCError({ code: "BAD_REQUEST", message: "Subscription already verified", }); }
if (!subscriber.token) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Subscription has no verification token", }); }
const verifyUrl = subscriber.page.customDomain ? `https://${subscriber.page.customDomain}/verify/${subscriber.token}` : `https://${subscriber.page.slug}.openstatus.dev/verify/${subscriber.token}`;
const channel = getChannel("email"); if (!channel) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Email channel not found", }); }
await channel.sendVerification?.( { id: subscriber.id, pageId: subscriber.pageId, pageName: subscriber.page.title, pageSlug: subscriber.page.slug, customDomain: subscriber.page.customDomain, componentIds: [], channelType: "email", email: subscriber.email, token: subscriber.token, acceptedAt: subscriber.acceptedAt ?? undefined, }, verifyUrl, );
return { success: true }; }),
sendTeamInvitation: protectedProcedure .input(z.object({ id: z.number() })) .mutation(async (opts) => { const limits = opts.ctx.workspace.limits;
if (limits.members === "Unlimited" || limits.members > 1) { const _invitation = await opts.ctx.db.query.invitation.findFirst({ where: and( eq(invitation.id, opts.input.id), eq(invitation.workspaceId, opts.ctx.workspace.id), ), });
if (!_invitation) return;
await emailClient.sendTeamInvitation({ to: _invitation.email, token: _invitation.token, invitedBy: `${opts.ctx.user.email}`, workspaceName: opts.ctx.workspace.name || "openstatus", }); } }),});