Files
Checkmate/server/src/api/validation/settingsValidation.ts
T

69 lines
2.7 KiB
TypeScript
Raw Normal View History

2026-06-09 12:34:15 -07:00
import { CHECK_TTL_SENTINEL } from "@/domain/checks/check.type.js";
2026-09-14 10:26:09 +01:00
import { MAX_EGRESS_POLL_INTERVAL_SECONDS, MAX_EGRESS_TARGETS, MIN_EGRESS_POLL_INTERVAL_SECONDS } from "@/domain/egress/egress.type.js";
2026-03-02 18:03:10 +00:00
import { z } from "zod";
2026-03-01 17:35:00 +00:00
2026-09-14 10:26:09 +01:00
// A reliability target is a bare host/IP (ICMP ping), host:port (TCP connect) or an http(s) URL.
const egressTargetValidation = z
.string()
.trim()
.min(1)
.max(253)
.regex(/^(https?:\/\/\S+|[A-Za-z0-9.\-:[\]]+)$/, "Invalid egress target");
2026-03-01 17:35:00 +00:00
//****************************************
// Settings Validations
//****************************************
2026-03-02 18:03:10 +00:00
export const updateAppSettingsBodyValidation = z
.object({
checkTTL: z.number().int().min(1).max(CHECK_TTL_SENTINEL).optional(),
systemEmailPort: z.number().nullable().optional(),
pagespeedApiKey: z.string().nullable().optional(),
2026-03-12 09:13:35 -07:00
language: z.string().optional(),
timezone: z.string().optional(),
systemEmailHost: z.string().nullable().optional(),
systemEmailAddress: z.string().nullable().optional(),
systemEmailDisplayName: z
.string()
.max(100)
.transform((val) => (val.trim() === "" ? null : val.trim()))
.nullable()
.optional(),
systemEmailPassword: z.string().nullable().optional(),
systemEmailUser: z.string().nullable().optional(),
systemEmailConnectionHost: z.string().nullable().optional(),
systemEmailTLSServername: z.string().nullable().optional(),
2026-03-02 18:03:10 +00:00
showURL: z.boolean().optional(),
systemEmailSecure: z.boolean().optional(),
systemEmailPool: z.boolean().optional(),
systemEmailIgnoreTLS: z.boolean().optional(),
systemEmailRequireTLS: z.boolean().optional(),
systemEmailRejectUnauthorized: z.boolean().optional(),
globalThresholds: z
.object({
2026-03-12 09:35:33 -07:00
cpu: z.number().min(1).max(100).optional(),
memory: z.number().min(1).max(100).optional(),
disk: z.number().min(1).max(100).optional(),
temperature: z.number().min(1).max(150).optional(),
2026-03-02 18:03:10 +00:00
})
.optional(),
2026-08-20 11:16:07 -07:00
globalProxyEnabled: z.boolean().optional(),
globalProxyId: z.string().nullable().optional(),
2026-09-14 10:26:09 +01:00
egressCheckEnabled: z.boolean().optional(),
egressCheckTargets: z.array(egressTargetValidation).max(MAX_EGRESS_TARGETS).optional(), // empty list falls back to DEFAULT_EGRESS_TARGETS
egressPollIntervalSeconds: z.number().int().min(MIN_EGRESS_POLL_INTERVAL_SECONDS).max(MAX_EGRESS_POLL_INTERVAL_SECONDS).optional(),
egressNotifications: z.array(z.string().regex(/^[a-f\d]{24}$/i, "Invalid notification id")).optional(),
2026-03-02 18:03:10 +00:00
})
2026-08-20 11:16:07 -07:00
.strip()
.superRefine((body, ctx) => {
if (body.globalProxyEnabled === true && !body.globalProxyId) {
ctx.addIssue({
code: "custom",
path: ["globalProxyId"],
message: "A proxy must be selected to enable the global proxy",
});
}
});