Openstatus
www.openstatus.dev
1import { createInsertSchema, createSelectSchema } from "drizzle-zod";
2import { z } from "zod";
3
4import * as assertions from "@openstatus/assertions";
5
6import { monitorPeriodicitySchema, monitorRegionSchema } from "../constants";
7import { monitorJobTypes, monitorMethods, monitorStatus } from "./constants";
8import { monitor, monitorsToPages } from "./monitor";
9
10export const monitorMethodsSchema = z.enum(monitorMethods);
11export const monitorStatusSchema = z.enum(monitorStatus);
12export const monitorJobTypesSchema = z.enum(monitorJobTypes);
13
14// TODO: shared function
15// biome-ignore lint/correctness/noUnusedVariables: <explanation>
16function stringToArrayProcess<T>(_string: T) {}
17
18const regionsToArraySchema = z.preprocess((val) => {
19 if (String(val).length > 0) {
20 return String(val).split(",");
21 }
22 return [];
23}, z.array(monitorRegionSchema));
24
25const bodyToStringSchema = z.preprocess((val) => {
26 return String(val);
27}, z.string());
28
29const headersToArraySchema = z.preprocess(
30 (val) => {
31 // early return in case the header is already an array
32 if (Array.isArray(val)) {
33 return val;
34 }
35 if (typeof val === "string" && String(val).length > 0) {
36 return JSON.parse(String(val));
37 }
38 return [];
39 },
40 z.array(z.object({ key: z.string(), value: z.string() })).prefault([]),
41);
42
43export const selectMonitorSchema = createSelectSchema(monitor, {
44 periodicity: monitorPeriodicitySchema.prefault("10m"),
45 status: monitorStatusSchema.prefault("active"),
46 jobType: monitorJobTypesSchema.prefault("http"),
47 timeout: z.number().prefault(45),
48 followRedirects: z.boolean().prefault(true),
49 retry: z.number().prefault(3),
50 regions: regionsToArraySchema.prefault([]),
51}).extend({
52 headers: headersToArraySchema.prefault([]),
53 otelHeaders: headersToArraySchema.prefault([]),
54 body: bodyToStringSchema.prefault(""),
55 // for tcp monitors the method is not needed
56 method: monitorMethodsSchema.prefault("GET"),
57});
58
59const headersSchema = z
60 .array(z.object({ key: z.string(), value: z.string() }))
61 .optional();
62
63export const insertMonitorSchema = createInsertSchema(monitor, {
64 name: z
65 .string()
66 .min(1, "Name must be at least 1 character long")
67 .max(255, "Name must be at most 255 characters long"),
68 periodicity: monitorPeriodicitySchema.prefault("10m"),
69 status: monitorStatusSchema.prefault("active"),
70 regions: z.array(monitorRegionSchema).prefault([]).optional(),
71 headers: headersSchema.prefault([]),
72 otelHeaders: headersSchema.prefault([]),
73}).extend({
74 method: monitorMethodsSchema.prefault("GET"),
75 notifications: z.array(z.number()).optional().prefault([]),
76 pages: z.array(z.number()).optional().prefault([]),
77 body: z.string().prefault("").optional(),
78 tags: z.array(z.number()).optional().prefault([]),
79 statusAssertions: z.array(assertions.statusAssertion).optional(),
80 headerAssertions: z.array(assertions.headerAssertion).optional(),
81 textBodyAssertions: z.array(assertions.textBodyAssertion).optional(),
82 timeout: z.coerce.number().gte(0).lte(60000).prefault(45000),
83 degradedAfter: z.coerce.number().gte(0).lte(60000).nullish(),
84});
85
86export const selectMonitorToPageSchema = createSelectSchema(monitorsToPages);
87
88export type InsertMonitor = z.infer<typeof insertMonitorSchema>;
89export type Monitor = z.infer<typeof selectMonitorSchema>;
90export type MonitorToPage = z.infer<typeof selectMonitorToPageSchema>;
91export type MonitorStatus = z.infer<typeof monitorStatusSchema>;
92export type MonitorPeriodicity = z.infer<typeof monitorPeriodicitySchema>;
93export type MonitorMethod = z.infer<typeof monitorMethodsSchema>;
94export type MonitorRegion = z.infer<typeof monitorRegionSchema>;
95export type MonitorJobType = z.infer<typeof monitorJobTypesSchema>;