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.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122import { and, eq } from "@openstatus/db";import { type Incident, incident, monitorIncidentTable, statusReport,} from "@openstatus/db/src/schema";
import { emitAudit } from "../audit";import { requireScope } from "../auth";import { type DB, type ServiceContext, tryGetActorUserId, withTransaction,} from "../context";import { NotFoundError } from "../errors";import { appendIncidentEvent, assertMember } from "./internal";import { assertStatusReportLinkable } from "./link-status-report";import { DeclareIncidentInput } from "./schemas";
async function sourceStartedAt( tx: DB, workspaceId: number, source: DeclareIncidentInput["source"],): Promise<Date | null> { if (!source) return null; if (source.type === "monitor_incident") { const row = await tx .select({ startedAt: monitorIncidentTable.startedAt }) .from(monitorIncidentTable) .where( and( eq(monitorIncidentTable.id, source.id), eq(monitorIncidentTable.workspaceId, workspaceId), ), ) .get(); if (!row) throw new NotFoundError("monitor_incident", source.id); return row.startedAt; } const row = await tx .select({ createdAt: statusReport.createdAt }) .from(statusReport) .where( and( eq(statusReport.id, source.id), eq(statusReport.workspaceId, workspaceId), ), ) .get(); if (!row) throw new NotFoundError("status_report", source.id); return row.createdAt;}
export async function declareIncident(args: { ctx: ServiceContext; input: DeclareIncidentInput;}): Promise<Incident> { const { ctx } = args; requireScope(ctx, "write"); const input = DeclareIncidentInput.parse(args.input);
return withTransaction(ctx, async (tx) => { if (input.commanderId != null) { await assertMember(tx, ctx.workspace.id, input.commanderId); } if (input.statusReportId !== undefined) { await assertStatusReportLinkable(tx, ctx.workspace.id, { statusReportId: input.statusReportId, }); }
const declaredAt = new Date(); const startedAt = input.startedAt ?? (await sourceStartedAt(tx, ctx.workspace.id, input.source)) ?? declaredAt;
const record = await tx .insert(incident) .values({ workspaceId: ctx.workspace.id, title: input.title, severity: input.severity, summary: input.summary ?? null, commanderId: input.commanderId ?? null, declaredBy: tryGetActorUserId(ctx.actor), declaredAt, startedAt, statusReportId: input.statusReportId ?? null, }) .returning() .get();
await emitAudit(tx, ctx, { action: "incident.create", entityType: "incident", entityId: record.id, after: record, ...(input.source ? { metadata: { source: input.source.type, ref: input.source.id } } : {}), });
await appendIncidentEvent(tx, ctx, { incidentId: record.id, type: "declared", message: `Declared as ${input.severity}: ${input.title}`, createdAt: declaredAt, }); if (input.statusReportId !== undefined) { await appendIncidentEvent(tx, ctx, { incidentId: record.id, type: "status_report_linked", message: `Linked status report #${input.statusReportId}`, }); } return record; });}