Files
cloudflare-domain-manager/packages/shared/src/integration-vps-tracker.ts
T
DenozordecandCursor b9bea44dce
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
feat(health): добавить Globalping и мультивыбор источников проб
Несколько источников проб сразу и правило агрегации на сервисе вместо XOR Local/Cloudflare.

Co-authored-by: Cursor <[email protected]>
2026-08-19 18:32:18 +07:00

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>;