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.3 kB ยท 72 lines
TypeScript
at incident-api
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273import { and, db as defaultDb, eq, gte, isNull } from "@openstatus/db";import { invitation, selectInvitationSchema, selectWorkspaceSchema,} from "@openstatus/db/src/schema";
import type { ServiceContext } from "../context";import { NotFoundError } from "../errors";import type { Invitation, Workspace } from "../types";import { GetInvitationByTokenInput, type ListInvitationsInput,} from "./schemas";
/** * List pending (unexpired, unaccepted) invitations for the caller's * workspace. */export async function listInvitations(args: { ctx: ServiceContext; input?: ListInvitationsInput;}): Promise<Invitation[]> { const { ctx } = args; const db = ctx.db ?? defaultDb;
const rows = await db.query.invitation.findMany({ where: and( eq(invitation.workspaceId, ctx.workspace.id), gte(invitation.expiresAt, new Date()), isNull(invitation.acceptedAt), ), });
return rows.map((r) => selectInvitationSchema.parse(r));}
export type InvitationWithWorkspace = Invitation & { workspace: Workspace };
/** * Resolve an invitation by token for a given accepting user's email. * Intentionally scoped by email to prevent token-sharing: a different user * cannot claim an invitation addressed to someone else. * * The email is a required, zod-validated field on the input schema โ the * transport layer (router) is responsible for short-circuiting with its * own auth error when the caller isn't authenticated. Throws * `NotFoundError` when no pending invite matches the token + email. */export async function getInvitationByToken(args: { ctx: ServiceContext; input: GetInvitationByTokenInput;}): Promise<InvitationWithWorkspace> { const input = GetInvitationByTokenInput.parse(args.input); const db = args.ctx.db ?? defaultDb;
const result = await db.query.invitation.findFirst({ where: and( eq(invitation.token, input.token), isNull(invitation.acceptedAt), gte(invitation.expiresAt, new Date()), eq(invitation.email, input.email), ), with: { workspace: true }, });
if (!result) throw new NotFoundError("invitation", input.token);
return selectInvitationSchema .extend({ workspace: selectWorkspaceSchema }) .parse(result);}