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.
6.2 kB Β· 146 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147import { and, count, db as defaultDb, eq, isNull } from "@openstatus/db";import { monitor, pageComponent } from "@openstatus/db/src/schema";import type { Limits } from "@openstatus/db/src/schema/plan/schema";import type { ImportSummary } from "@openstatus/importers";
import type { DB } from "../context";import type { ImportOptions } from "./schemas";
/** * Inspect an `ImportSummary` and push per-limit warning strings into * `summary.errors`. Shared by `preview` (to surface warnings upfront) and * `run` (re-emitted alongside the actual writes). Pure: no mutations to * the DB, only to the summary argument. * * `options` gates the per-phase warnings against the same include flags * `run` uses β without this, a user importing with `includeSubscribers: * false` on a plan that disables subscribers would see a misleading * "subscribers cannot be imported" warning even though the phase is * opted out anyway. Defaults mirror `ImportOptions` defaults * (status reports on, subscribers off, components on, monitors on). */export async function addLimitWarnings( summary: ImportSummary, config: { limits: Limits; workspaceId: number; pageId?: number; db?: DB; options?: Partial<ImportOptions>; },): Promise<void> { const db = config.db ?? defaultDb; const includeComponents = config.options?.includeComponents ?? true; const includeMonitors = config.options?.includeMonitors ?? true; const includeSubscribers = config.options?.includeSubscribers ?? false;
// 1. Page component count // // `page-components` is a **workspace-wide** plan cap β the // `page-component/update-order` service enforces it by counting // every component across every page, not just the target one. This // preview warning has to match that scope, otherwise imports into // an empty page with plenty of workspace-wide pressure would look // safe here and blow up at insert time. const componentsPhase = summary.phases.find((p) => p.phase === "components"); if ( includeComponents && componentsPhase && componentsPhase.resources.length > 0 ) { const maxComponents = config.limits["page-components"]; const [result] = await db .select({ count: count() }) .from(pageComponent) .where(eq(pageComponent.workspaceId, config.workspaceId)); const existingCount = result?.count ?? 0; const remaining = maxComponents - existingCount; if (remaining <= 0) { summary.errors.push( `Component limit reached (${maxComponents}). Upgrade your plan to import components.`, ); } else if (componentsPhase.resources.length > remaining) { // Worst-case warning: resource count includes items that will be // skipped as duplicates (phase writers dedupe by name + pageId at // insert time). Phrased as "up to N new" so the number is an // upper bound on quota consumption, not a guaranteed rejection // count. Exact new-vs-duplicate split requires a per-component // existence check we skip at preview time to keep the dry-run // fast. summary.errors.push( `Only ${remaining} new component${remaining === 1 ? "" : "s"} may be created due to plan limit (${maxComponents}); some of the ${componentsPhase.resources.length} in the import may already exist and be skipped.`, ); } }
// 2. Custom domain β warn that it'll be stripped, not blocked. if (!config.limits["custom-domain"]) { const pagePhase = summary.phases.find((p) => p.phase === "page"); const pageData = pagePhase?.resources[0]?.data as | { customDomain?: string } | undefined; if (pageData?.customDomain) { summary.errors.push( "Custom domain will be stripped during import. Upgrade your plan to use custom domains.", ); } }
// 3. Monitor count const monitorsPhase = summary.phases.find((p) => p.phase === "monitors"); if (includeMonitors && monitorsPhase && monitorsPhase.resources.length > 0) { const maxMonitors = config.limits.monitors; const [monitorCount] = await db .select({ count: count() }) .from(monitor) .where( and( eq(monitor.workspaceId, config.workspaceId), isNull(monitor.deletedAt), ), ); const remaining = maxMonitors - (monitorCount?.count ?? 0); if (remaining <= 0) { summary.errors.push( `Monitor limit reached (${maxMonitors}). Upgrade your plan to import monitors.`, ); } else if (monitorsPhase.resources.length > remaining) { // Same worst-case framing as the components warning β phase // writers dedupe by url + workspaceId at insert time, so the // resource count includes items that will be skipped. The exact // new-vs-existing split needs a per-monitor existence check we // skip at preview time. summary.errors.push( `Only ${remaining} new monitor${remaining === 1 ? "" : "s"} may be created due to plan limit (${maxMonitors}); some of the ${monitorsPhase.resources.length} in the import may already exist and be skipped.`, ); } }
// 4. Monitor periodicity clamping if (includeMonitors && monitorsPhase && monitorsPhase.resources.length > 0) { const allowedPeriodicity: string[] = config.limits.periodicity; const clamped = monitorsPhase.resources.filter((r) => { const data = r.data as { periodicity?: string } | undefined; return ( data?.periodicity && !allowedPeriodicity.includes(data.periodicity) ); }); if (clamped.length > 0) { summary.errors.push( `${clamped.length} monitor${clamped.length === 1 ? "'s" : "s'"} check frequency will be adjusted to fit your plan's allowed intervals.`, ); } }
// 5. Subscribers on plans that disable them if (includeSubscribers && !config.limits["status-subscribers"]) { const subscribersPhase = summary.phases.find( (p) => p.phase === "subscribers", ); if (subscribersPhase && subscribersPhase.resources.length > 0) { summary.errors.push( "Subscribers cannot be imported on your current plan. Upgrade to enable status page subscribers.", ); } }}