diff --git a/server/src/api/validation/checkValidation.ts b/server/src/api/validation/checkValidation.ts index db0978357..d041c9e8f 100644 --- a/server/src/api/validation/checkValidation.ts +++ b/server/src/api/validation/checkValidation.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { booleanCoercion } from "./shared.js"; import { GeoContinents } from "@/domain/geo-checks/geo-check.type.js"; import { MonitorTypes } from "@/domain/monitors/monitor.types.js"; +import { CheckFilters, DateRanges, SortOrders } from "@/types/query.js"; //**************************************** // Check Validations @@ -13,10 +14,10 @@ export const getChecksParamValidation = z.object({ export const getChecksQueryValidation = z.object({ type: z.enum(MonitorTypes).optional(), - sortOrder: z.enum(["asc", "desc"]), + sortOrder: z.enum(SortOrders), limit: z.coerce.number().optional(), - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]), - filter: z.enum(["all", "up", "down", "resolve"]).optional(), + dateRange: z.enum(DateRanges), + filter: z.enum(CheckFilters).optional(), ack: booleanCoercion.optional(), page: z.coerce.number(), rowsPerPage: z.coerce.number(), @@ -25,10 +26,10 @@ export const getChecksQueryValidation = z.object({ }); export const getTeamChecksQueryValidation = z.object({ - sortOrder: z.enum(["asc", "desc"]), + sortOrder: z.enum(SortOrders), limit: z.coerce.number().optional(), - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]), - filter: z.enum(["all", "up", "down", "resolve"]).optional(), + dateRange: z.enum(DateRanges), + filter: z.enum(CheckFilters).optional(), ack: booleanCoercion.optional(), page: z.coerce.number(), rowsPerPage: z.coerce.number(), @@ -39,5 +40,5 @@ export const deleteChecksParamValidation = z.object({ }); export const getChecksSummaryByTeamIdQueryValidation = z.object({ - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(), + dateRange: z.enum(DateRanges).optional(), }); diff --git a/server/src/api/validation/incidentValidation.ts b/server/src/api/validation/incidentValidation.ts index 2047eefa5..322eaa2d3 100644 --- a/server/src/api/validation/incidentValidation.ts +++ b/server/src/api/validation/incidentValidation.ts @@ -1,18 +1,20 @@ import { z } from "zod"; import { booleanCoercion } from "./shared.js"; +import { DateRanges, SortOrders } from "@/types/query.js"; +import { IncidentResolutionTypes } from "@/domain/incidents/incident.type.js"; //**************************************** // Incident Validations //**************************************** export const getIncidentsByTeamQueryValidation = z.object({ - sortOrder: z.enum(["asc", "desc"]), - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).default("all"), + sortOrder: z.enum(SortOrders), + dateRange: z.enum(DateRanges).default("all"), page: z.coerce.number().int().min(0), rowsPerPage: z.coerce.number().int().min(1), status: booleanCoercion.optional(), monitorId: z.string().optional(), - resolutionType: z.enum(["manual", "automatic"]).optional(), + resolutionType: z.enum(IncidentResolutionTypes).optional(), }); export const getIncidentSummaryQueryValidation = z.object({ diff --git a/server/src/api/validation/maintenanceWindowValidation.ts b/server/src/api/validation/maintenanceWindowValidation.ts index 2ee22bc19..c054d5b5d 100644 --- a/server/src/api/validation/maintenanceWindowValidation.ts +++ b/server/src/api/validation/maintenanceWindowValidation.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { booleanCoercion } from "./shared.js"; import { DurationUnits } from "@/domain/maintenance-windows/maintenance-window.type.js"; +import { SortOrders } from "@/types/query.js"; const dateToString = z.coerce.date().transform((d) => d.toISOString()); @@ -49,7 +50,7 @@ export const getMaintenanceWindowsByTeamIdQueryValidation = z.object({ page: z.coerce.number().optional(), rowsPerPage: z.coerce.number().optional(), field: z.string().optional(), - order: z.enum(["asc", "desc"]).optional(), + order: z.enum(SortOrders).optional(), }); export const getMaintenanceWindowsByMonitorIdParamValidation = z.object({ diff --git a/server/src/api/validation/monitorValidation.ts b/server/src/api/validation/monitorValidation.ts index e8bae9261..1ed9dca84 100644 --- a/server/src/api/validation/monitorValidation.ts +++ b/server/src/api/validation/monitorValidation.ts @@ -11,6 +11,7 @@ import { MonitorTypes, PageSpeedStrategies, } from "@/domain/monitors/monitor.types.js"; +import { DateRanges, SortOrders } from "@/types/query.js"; const httpStatusCode = z.number().refine((code) => HttpStatusCodeSet.has(code), { message: "Must be a valid HTTP status code" }); @@ -20,9 +21,9 @@ export const getMonitorByIdParamValidation = z.object({ export const getMonitorByIdQueryValidation = z.object({ status: booleanCoercion.optional(), - sortOrder: z.enum(["asc", "desc"]).optional(), + sortOrder: z.enum(SortOrders).optional(), limit: z.coerce.number().optional(), - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(), + dateRange: z.enum(DateRanges).optional(), numToDisplay: z.coerce.number().optional(), normalize: booleanCoercion.optional(), continent: z.union([z.enum(GeoContinents), z.array(z.enum(GeoContinents))]).optional(), @@ -42,7 +43,7 @@ export const getMonitorsWithChecksQueryValidation = z.object({ rowsPerPage: z.coerce.number().int().min(1).max(100).optional(), filter: z.union([z.string(), z.literal("")]).optional(), field: z.string().optional(), - order: z.enum(["asc", "desc"]).optional(), + order: z.enum(SortOrders).optional(), type: z.union([z.enum(MonitorTypes), z.array(z.enum(MonitorTypes))]).optional(), tags: z.union([z.string(), z.array(z.string())]).optional(), explain: booleanCoercion.optional(), @@ -195,7 +196,7 @@ export const getUptimeDetailsByIdParamValidation = z.object({ }); export const getUptimeDetailsByIdQueryValidation = z.object({ - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]), + dateRange: z.enum(DateRanges), normalize: booleanCoercion.optional(), }); @@ -206,7 +207,7 @@ const importedMonitorSchema = z teamId: z.string().optional(), name: z.string().min(1, "Name is required"), description: z.union([z.string(), z.literal("")]).optional(), - status: z.enum(["up", "down", "paused", "initializing", "maintenance", "breached"]).default("initializing"), + status: z.enum(MonitorStatuses).default("initializing"), statusWindow: z.array(z.boolean()).default([]), statusWindowSize: z.number().min(1).max(20).default(5), statusWindowThreshold: z.number().min(1).max(100).default(60), @@ -263,7 +264,7 @@ export const getHardwareDetailsByIdParamValidation = z.object({ }); export const getHardwareDetailsByIdQueryValidation = z.object({ - dateRange: z.enum(["recent", "hour", "day", "week", "month", "all"]).optional(), + dateRange: z.enum(DateRanges).optional(), }); // Canonical monitor shape returned by /monitors endpoints. Keep aligned with diff --git a/server/src/api/validation/statusPageValidation.ts b/server/src/api/validation/statusPageValidation.ts index a650129cd..ee2b7376c 100644 --- a/server/src/api/validation/statusPageValidation.ts +++ b/server/src/api/validation/statusPageValidation.ts @@ -3,6 +3,7 @@ import { booleanCoercion, dnsHostnameRegex } from "./shared.js"; import { StatusPageTypes, StatusPageThemes, StatusPageThemeModes } from "@/domain/status-pages/status-page.type.js"; import { normalizeStatusPageDomain } from "@/utils/statusPageDomain.js"; import { cssReferencesExternalResource } from "@/utils/customCss.js"; +import { ImageMimeTypes } from "@/types/upload.js"; //**************************************** // Status Page Validations @@ -67,7 +68,7 @@ export const imageValidation = z fieldname: z.string().min(1, "Field name is required"), originalname: z.string().min(1, "Original name is required"), encoding: z.string().min(1, "Encoding is required"), - mimetype: z.enum(["image/jpeg", "image/png", "image/jpg"], { + mimetype: z.enum(ImageMimeTypes, { message: "File must be a valid image (jpeg, jpg, or png)", }), size: z.number().max(3145728, "File size must be less than 3MB"), diff --git a/server/src/domain/incidents/incident.type.ts b/server/src/domain/incidents/incident.type.ts index 6b076ff83..2b45e72c4 100644 --- a/server/src/domain/incidents/incident.type.ts +++ b/server/src/domain/incidents/incident.type.ts @@ -1,7 +1,7 @@ // export type IncidentResolutionType = "automatic" | "manual" | null; -export const IncidentResolutionTypes = ["automatic", "manual", null] as const; -export type IncidentResolutionType = (typeof IncidentResolutionTypes)[number]; +export const IncidentResolutionTypes = ["automatic", "manual"] as const; +export type IncidentResolutionType = (typeof IncidentResolutionTypes)[number] | null; export interface Incident { id: string; diff --git a/server/src/types/query.ts b/server/src/types/query.ts new file mode 100644 index 000000000..9809517ee --- /dev/null +++ b/server/src/types/query.ts @@ -0,0 +1,8 @@ +export const DateRanges = ["recent", "hour", "day", "week", "month", "all"] as const; +export type DateRange = (typeof DateRanges)[number]; + +export const SortOrders = ["asc", "desc"] as const; +export type SortOrder = (typeof SortOrders)[number]; + +export const CheckFilters = ["all", "up", "down", "resolve"] as const; +export type CheckFilter = (typeof CheckFilters)[number];