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.
3.4 kB ยท 111 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112import { and, eq, isNull } from "@openstatus/db";import { monitor, pageComponent } from "@openstatus/db/src/schema";
import { emitAudit } from "../audit";import { requireScope } from "../auth";import { type ServiceContext, withTransaction } from "../context";import { ConflictError, ForbiddenError } from "../errors";import { assertWithinLimit } from "../limits";import { assertGroupOnPage, assertPageInWorkspace } from "./internal";import { CreatePageComponentInput } from "./schemas";
/** * Add a single component to a status page. Monitor components inherit the * monitor's name when the caller doesn't supply one. */export async function createPageComponent(args: { ctx: ServiceContext; input: CreatePageComponentInput;}) { const { ctx } = args; requireScope(ctx, "write"); const input = CreatePageComponentInput.parse(args.input);
return withTransaction(ctx, async (tx) => { await assertPageInWorkspace({ tx, pageId: input.pageId, workspaceId: ctx.workspace.id, });
let name = input.name; if (input.type === "monitor") { // Soft-deleted monitors are excluded โ a tombstoned monitor's id // shouldn't be attachable to a fresh component. const row = await tx .select({ id: monitor.id, name: monitor.name }) .from(monitor) .where( and( // safe: the schema's refine guarantees monitorId on this branch eq(monitor.id, input.monitorId as number), eq(monitor.workspaceId, ctx.workspace.id), isNull(monitor.deletedAt), ), ) .get(); if (!row) throw new ForbiddenError("Invalid monitor IDs."); name = name ?? row.name;
// `(pageId, monitorId)` is UNIQUE โ pre-check so a duplicate reads as a // conflict rather than a raw driver constraint failure. const duplicate = await tx .select({ id: pageComponent.id }) .from(pageComponent) .where( and( eq(pageComponent.pageId, input.pageId), eq(pageComponent.monitorId, row.id), ), ) .get(); if (duplicate) { throw new ConflictError( "This monitor is already a component on this page.", ); } }
if (input.groupId != null) { await assertGroupOnPage({ tx, groupId: input.groupId, pageId: input.pageId, workspaceId: ctx.workspace.id, }); }
// Validation before quota, as in `notification/create`: a bad monitor id // or a re-added component must report what's actually wrong rather than // "limit reached", and neither one would consume a slot anyway. await assertWithinLimit({ tx, workspaceId: ctx.workspace.id, limit: "page-components", });
const created = await tx .insert(pageComponent) .values({ workspaceId: ctx.workspace.id, pageId: input.pageId, type: input.type, monitorId: input.type === "monitor" ? input.monitorId : null, name: name ?? "", description: input.description ?? null, order: input.order, groupId: input.groupId ?? null, }) .returning() .get();
await emitAudit(tx, ctx, { action: "page_component.create", entityType: "page_component", entityId: created.id, after: created, });
return created; });}