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.
4.0 kB ยท 150 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151import { and, eq, inArray, isNull, sql } from "@openstatus/db";import { monitor, page } from "@openstatus/db/src/schema";import { type pageAccessTypes, subdomainSafeList,} from "@openstatus/db/src/schema/pages/constants";
import type { DB } from "../context";import { ConflictError, ForbiddenError, LimitExceededError, NotFoundError, ValidationError,} from "../errors";import type { Workspace } from "../types";
/** Load a page by id, scoped to the workspace. Throws on miss. */export async function getPageInWorkspace(args: { tx: DB; id: number; workspaceId: number;}) { const { tx, id, workspaceId } = args; const row = await tx .select() .from(page) .where(and(eq(page.id, id), eq(page.workspaceId, workspaceId))) .get(); if (!row) throw new NotFoundError("page", id); return row;}
/** * Assert a slug is free โ rejects reserved subdomains and already-taken * slugs. Optionally exempts a page id (for updates where the current slug * shouldn't trip the check). */export async function assertSlugAvailable(args: { tx: DB; slug: string; excludePageId?: number;}): Promise<void> { const { tx, slug, excludePageId } = args; if (subdomainSafeList.includes(slug)) { throw new ConflictError( "This slug is already taken. Please choose another one.", ); } const rows = await tx .select({ id: page.id }) .from(page) .where(sql`lower(${page.slug}) = ${slug}`) .all(); const conflicts = excludePageId ? rows.filter((r) => r.id !== excludePageId) : rows; if (conflicts.length > 0) { throw new ConflictError( "This slug is already taken. Please choose another one.", ); }}
/** Validate monitor ids against the workspace's active (non-soft-deleted) set. */export async function validateMonitorIdsActive(args: { tx: DB; workspaceId: number; monitorIds: ReadonlyArray<number>;}): Promise< Array<{ id: number; name: string; externalName: string | null; workspaceId: number | null; }>> { const { tx, workspaceId, monitorIds } = args; if (monitorIds.length === 0) return []; const ids = Array.from(new Set(monitorIds)); const rows = await tx .select({ id: monitor.id, name: monitor.name, externalName: monitor.externalName, workspaceId: monitor.workspaceId, }) .from(monitor) .where( and( inArray(monitor.id, ids), eq(monitor.workspaceId, workspaceId), eq(monitor.active, true), isNull(monitor.deletedAt), ), ) .all(); if (rows.length !== ids.length) { throw new ForbiddenError( "You don't have access to all the monitors or some monitors are inactive.", ); } return rows;}
/** * Plan gate for the access-type options on create / update. Mirrors the * existing tRPC gates. */export function assertAccessTypeAllowed( workspace: Workspace, args: { accessType: (typeof pageAccessTypes)[number]; passwordProtected?: boolean | null; allowedIpRanges?: ReadonlyArray<string> | null; allowIndex?: boolean; },): void { const limits = workspace.limits;
if ( limits["password-protection"] === false && (args.accessType === "password" || args.passwordProtected === true) ) { throw new LimitExceededError("password-protection", 0); } if ( limits["email-domain-protection"] === false && args.accessType === "email-domain" ) { throw new LimitExceededError("email-domain-protection", 0); } if ( limits["ip-restriction"] === false && args.accessType === "ip-restriction" ) { throw new LimitExceededError("ip-restriction", 0); } if ( args.accessType === "ip-restriction" && (!args.allowedIpRanges || args.allowedIpRanges.length === 0) ) { throw new ValidationError( "At least one IP range is required for IP restriction.", ); } if (args.allowIndex === false && limits["no-index"] === false) { throw new LimitExceededError("no-index", 0); }}