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.
5.3 kB ยท 182 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183import { type Assertion, DnsRecordAssertion, HeaderAssertion, JsonBodyAssertion, StatusAssertion, TextBodyAssertion, serialize,} from "@openstatus/assertions";import { and, eq, inArray, isNull } from "@openstatus/db";import { monitor, monitorTag, notification, privateLocation,} from "@openstatus/db/src/schema";import { freeFlyRegions, monitorRegions,} from "@openstatus/db/src/schema/constants";import { regionDict } from "@openstatus/regions";
import type { DB } from "../context";import { ForbiddenError, NotFoundError } from "../errors";import type { Workspace } from "../types";
/** Load a monitor by id, scoped to the workspace and excluding soft-deleted. */export async function getMonitorInWorkspace(args: { tx: DB; id: number; workspaceId: number;}) { const { tx, id, workspaceId } = args; const row = await tx .select() .from(monitor) .where( and( eq(monitor.id, id), eq(monitor.workspaceId, workspaceId), isNull(monitor.deletedAt), ), ) .get(); if (!row) throw new NotFoundError("monitor", id); return row;}
/** Validate that tag ids exist and belong to the workspace. */export async function validateTagIds(args: { tx: DB; workspaceId: number; tagIds: ReadonlyArray<number>;}): Promise<number[]> { const { tx, workspaceId, tagIds } = args; if (tagIds.length === 0) return []; const ids = Array.from(new Set(tagIds)); const rows = await tx .select({ id: monitorTag.id }) .from(monitorTag) .where( and(inArray(monitorTag.id, ids), eq(monitorTag.workspaceId, workspaceId)), ) .all(); const valid = new Set(rows.map((r) => r.id)); for (const id of ids) { if (!valid.has(id)) throw new ForbiddenError(`Tag ${id} is not accessible.`); } return ids;}
/** Validate that notification ids exist and belong to the workspace. */export async function validateNotificationIds(args: { tx: DB; workspaceId: number; notificationIds: ReadonlyArray<number>;}): Promise<number[]> { const { tx, workspaceId, notificationIds } = args; if (notificationIds.length === 0) return []; const ids = Array.from(new Set(notificationIds)); const rows = await tx .select({ id: notification.id }) .from(notification) .where( and( inArray(notification.id, ids), eq(notification.workspaceId, workspaceId), ), ) .all(); const valid = new Set(rows.map((r) => r.id)); for (const id of ids) { if (!valid.has(id)) { throw new ForbiddenError(`Notification ${id} is not accessible.`); } } return ids;}
/** Validate that private location ids exist and belong to the workspace. */export async function validatePrivateLocationIds(args: { tx: DB; workspaceId: number; privateLocationIds: ReadonlyArray<number>;}): Promise<number[]> { const { tx, workspaceId, privateLocationIds } = args; if (privateLocationIds.length === 0) return []; const ids = Array.from(new Set(privateLocationIds)); const rows = await tx .select({ id: privateLocation.id }) .from(privateLocation) .where( and( inArray(privateLocation.id, ids), eq(privateLocation.workspaceId, workspaceId), ), ) .all(); const valid = new Set(rows.map((r) => r.id)); for (const id of ids) { if (!valid.has(id)) { throw new ForbiddenError(`Private location ${id} is not accessible.`); } } return ids;}
/** Translate UI `{key,value}[]` headers into the stored JSON string, or `null`. */export function headersToDbJson( headers: ReadonlyArray<{ key: string; value: string }> | undefined,): string | undefined { if (headers === undefined) return undefined; return JSON.stringify(headers);}
/** * Build an `Assertion[]` from a UI discriminated-union list and serialise to * the stored JSON string. `null` means "no assertions configured". */export function serialiseAssertions( list: ReadonlyArray<{ type: string } & Record<string, unknown>> | undefined,): string { const assertions: Assertion[] = []; for (const a of list ?? []) { if (a.type === "status") assertions.push(new StatusAssertion(a as never)); else if (a.type === "header") assertions.push(new HeaderAssertion(a as never)); else if (a.type === "textBody") assertions.push(new TextBodyAssertion(a as never)); else if (a.type === "jsonBody") assertions.push(new JsonBodyAssertion(a as never)); else if (a.type === "dnsRecord") assertions.push(new DnsRecordAssertion(a as never)); } return serialize(assertions);}
/** * Pick the default regions for a new monitor based on the workspace's plan. * Matches the old tRPC "randomly choose 4 free regions / 6 paid regions, * excluding deprecated" logic. */export function pickDefaultRegions(workspace: Workspace): { regions: string[]; periodicity: "30m" | "1m";} { const selectable = workspace.plan === "free" ? freeFlyRegions : monitorRegions; const count = workspace.plan === "free" ? 4 : 6; const regions = [...selectable] .filter((r) => { const deprecated = regionDict[r].deprecated; return !deprecated; }) .sort(() => 0.5 - Math.random()) .slice(0, count); return { regions, periodicity: workspace.plan === "free" ? "30m" : "1m", };}