CD / update-wiki (push) Successful in 8s
quality / commitlint (push) Skipped
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
quality / web (push) Successful in 54s
quality / api (push) Successful in 46s
CD / quality (push) Successful in 1m49s
CD / publish (push) Successful in 1m40s
Несколько источников проб сразу и правило агрегации на сервисе вместо XOR Local/Cloudflare. Co-authored-by: Cursor <[email protected]>
72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
import { z } from "zod";
|
|
|
|
export const cfdmBindingSyncItemSchema = z.object({
|
|
bindingId: z.number().int().positive(),
|
|
serviceId: z.number().int().positive(),
|
|
serviceName: z.string().min(1),
|
|
serviceSlug: z.string().min(1),
|
|
fqdn: z.string().min(1),
|
|
zoneName: z.string().min(1),
|
|
hostname: z.string(),
|
|
ips: z.array(z.string()),
|
|
/** CNAME-цель (FQDN), если binding — CNAME; для матчинга в VPS Tracker. */
|
|
cnameTarget: z.string().optional(),
|
|
deleted: z.boolean().optional(),
|
|
});
|
|
|
|
export const cfdmSyncBindingsBodySchema = z.object({
|
|
bindings: z.array(cfdmBindingSyncItemSchema),
|
|
/** Полная пересинхронизация: удалить CFDM-домены, которых нет в payload. */
|
|
fullSync: z.boolean().optional(),
|
|
}).refine((data) => data.fullSync === true || data.bindings.length >= 1, {
|
|
message: "bindings обязателен, если fullSync не задан",
|
|
path: ["bindings"],
|
|
});
|
|
|
|
export type CfdmBindingSyncItem = z.infer<typeof cfdmBindingSyncItemSchema>;
|
|
|
|
export const appSettingsPatchSchema = z.object({
|
|
vpsTrackerUrl: z.string().url().or(z.literal("")).optional(),
|
|
vpsTrackerIntegrationToken: z.string().optional(),
|
|
vpsTrackerSyncEnabled: z.boolean().optional(),
|
|
showQuickActions: z.boolean().optional(),
|
|
healthCheckCron: z.string().trim().min(1).max(64).optional(),
|
|
healthDegradedFailures: z.number().int().min(1).max(20).optional(),
|
|
healthDownFailures: z.number().int().min(1).max(50).optional(),
|
|
healthLatencyWarnMs: z.number().int().min(50).max(60_000).optional(),
|
|
healthSuccessRecoveries: z.number().int().min(1).max(20).optional(),
|
|
healthWorkerUrl: z.string().url().or(z.literal("")).optional(),
|
|
healthWorkerToken: z.string().optional(),
|
|
globalpingToken: z.string().optional(),
|
|
globalpingLocations: z.string().trim().max(200).optional(),
|
|
globalpingLimit: z.number().int().min(1).max(10).optional(),
|
|
}).superRefine((data, ctx) => {
|
|
if (
|
|
data.healthDegradedFailures != null &&
|
|
data.healthDownFailures != null &&
|
|
data.healthDownFailures < data.healthDegradedFailures
|
|
) {
|
|
ctx.addIssue({
|
|
code: "custom",
|
|
message: "ошибок до down не меньше, чем до degraded",
|
|
path: ["healthDownFailures"],
|
|
});
|
|
}
|
|
});
|
|
|
|
export type AppSettingsPatch = z.infer<typeof appSettingsPatchSchema>;
|
|
|
|
export const vpsTrackerEventSchema = z.object({
|
|
event: z.enum(["vps_down", "vps_up"]),
|
|
vps: z.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
ip: z.string().optional(),
|
|
label: z.string().optional(),
|
|
}),
|
|
),
|
|
timestamp: z.string().datetime().optional(),
|
|
});
|
|
|
|
export type VpsTrackerEvent = z.infer<typeof vpsTrackerEventSchema>;
|