Files
cloudflare-domain-manager/packages/shared/dist/index.js
T
DenozordecandCursor 96783386e0
Build, Test, and Push CFDM Docker Image / test (push) Failing after 3m36s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Has been skipped
Build, Test, and Push CFDM Docker Image / update-wiki (push) Has been skipped
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped
feat: интеграция с VPS Tracker
Исходящий sync bindings после updateConfig, настройки в app_settings, страница Интеграции, приём событий vps_down для DNS failover.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 16:45:17 +07:00

611 lines
21 KiB
JavaScript

// src/constants.ts
var SYNC_SYNCED = "synced";
var SYNC_PENDING_PUSH = "pending_push";
var SYNC_PENDING_DELETE = "pending_delete";
var SYNC_CONFLICT = "conflict";
var SYNC_ERROR = "error";
var CERT_OK = "ok";
var CERT_WARNING = "warning";
var CERT_EXPIRED = "expired";
var CERT_ERROR = "error";
var CERT_UNKNOWN = "unknown";
var CERT_MONITOR_AUTO = "auto";
var CERT_MONITOR_REQUIRED = "required";
var CERT_MONITOR_SKIPPED = "skipped";
var CERT_MONITORING_VALUES = [
CERT_MONITOR_AUTO,
CERT_MONITOR_REQUIRED,
CERT_MONITOR_SKIPPED
];
// src/validators.ts
var NAME_RE = /^(@|\*|[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?(\.[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?)*)$/;
var IPV4_RE = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
var IPV6_RE = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
var ALLOWED_TYPES = ["A", "AAAA", "CNAME", "TXT", "MX", "NS", "SRV", "CAA"];
var ValidationError = class extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
};
function validateDnsRecord(recordType, name, content, ttl, proxied) {
const rt = recordType.toUpperCase();
if (!ALLOWED_TYPES.includes(rt)) {
throw new ValidationError(`unsupported record type: ${recordType}`);
}
if (!NAME_RE.test(name)) {
throw new ValidationError(`invalid record name: ${name}`);
}
if (ttl !== 1 && (ttl < 60 || ttl > 86400)) {
throw new ValidationError("ttl must be 1 (auto) or 60-86400");
}
if (proxied && !["A", "AAAA", "CNAME"].includes(rt)) {
throw new ValidationError("proxied only allowed for A, AAAA, CNAME");
}
switch (rt) {
case "A":
if (!IPV4_RE.test(content)) {
throw new ValidationError("A record requires valid IPv4");
}
break;
case "AAAA":
if (!IPV6_RE.test(content)) {
throw new ValidationError("AAAA record requires valid IPv6");
}
break;
case "CNAME":
case "NS":
if (!content || content.includes(" ")) {
throw new ValidationError("CNAME/NS requires valid hostname");
}
break;
case "TXT":
if (!content || content.length > 2048) {
throw new ValidationError("TXT content length 1-2048");
}
break;
}
}
function certStatusFromExpiry(daysLeft) {
if (daysLeft < 0) return CERT_EXPIRED;
if (daysLeft <= 30) return CERT_WARNING;
return CERT_OK;
}
function shouldMonitorService(service, group) {
if (!service.enabled) return false;
if (!service.service_group_id) return true;
return group?.enabled ?? false;
}
function isValidIpv4(ip) {
const parts = ip.split(".");
if (parts.length !== 4) return false;
return parts.every((p) => {
const n = Number(p);
return Number.isInteger(n) && n >= 0 && n <= 255;
});
}
// src/subdomain.ts
function dnsNameToSubdomainLabel(recordName, zoneName) {
const rn = recordName.trim().replace(/\.+$/, "");
const zn = zoneName.trim().replace(/\.+$/, "");
if (!rn || !zn) return null;
if (rn === "*") return "*";
const wildcardFqdn = `*.${zn}`;
if (rn.toLowerCase() === wildcardFqdn.toLowerCase()) return "*";
if (rn.toLowerCase() === zn.toLowerCase()) return "@";
const zoneSuffix = `.${zn}`;
if (rn.toLowerCase().endsWith(zoneSuffix.toLowerCase())) {
const prefix = rn.slice(0, rn.length - zoneSuffix.length);
return prefix || "@";
}
if (!rn.includes(".")) return rn;
return null;
}
function subdomainLabelToFqdn(label, zoneName) {
return label === "@" ? zoneName : `${label}.${zoneName}`;
}
function normalizeDnsRecordName(recordName, zoneName) {
const label = dnsNameToSubdomainLabel(recordName, zoneName);
if (label == null) {
return recordName.trim().replace(/\.+$/, "");
}
return subdomainLabelToFqdn(label, zoneName);
}
function dnsRecordNamesMatch(left, right, zoneName) {
return normalizeDnsRecordName(left, zoneName).toLowerCase() === normalizeDnsRecordName(right, zoneName).toLowerCase();
}
// src/parse-fqdn.ts
function fqdnToDisplay(hostname, zoneName) {
if (hostname === "@") {
return zoneName;
}
return `${hostname}.${zoneName}`;
}
function parseFqdn(fqdn, knownZones) {
const normalized = fqdn.trim().toLowerCase();
if (!normalized) {
return null;
}
const zones = [...knownZones].sort((a, b) => b.length - a.length);
for (const zone of zones) {
const zoneLower = zone.toLowerCase();
if (normalized === zoneLower) {
return {
zoneName: zone,
hostname: "@",
fqdn: fqdnToDisplay("@", zone)
};
}
const suffix = `.${zoneLower}`;
if (normalized.endsWith(suffix)) {
const prefix = normalized.slice(0, -suffix.length);
if (prefix) {
return {
zoneName: zone,
hostname: prefix,
fqdn: fqdnToDisplay(prefix, zone)
};
}
}
}
return null;
}
function bindingToFqdn(binding) {
return binding.fqdn ?? fqdnToDisplay(binding.hostname, binding.zone_name);
}
// src/schemas.ts
import { z } from "zod";
var certMonitoringSchema = z.enum(["auto", "required", "skipped"]);
var lbModeSchema = z.enum(["round_robin", "failover", "weighted"]);
var healthCheckTypeSchema = z.enum(["tcp", "http"]);
var ipHealthStateSchema = z.enum(["up", "down", "degraded", "unknown"]);
var healthCheckScopeSchema = z.enum(["binding", "group"]);
var ipHealthStatusSchema = z.object({
scope: healthCheckScopeSchema,
ref_id: z.number(),
ip: z.string(),
status: ipHealthStateSchema,
latency_ms: z.number().nullable(),
consecutive_failures: z.number(),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable()
});
var groupSchema = z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
created_at: z.string(),
updated_at: z.string()
});
var groupWithStatsSchema = groupSchema.extend({
domain_count: z.number()
});
var serviceGroupTypeSchema = z.enum([
"vpn",
"network",
"internet",
"bgp",
"custom"
]);
var serviceGroupSchema = z.object({
id: z.number(),
name: z.string(),
type: serviceGroupTypeSchema.catch("custom"),
icon: z.string().nullable(),
domain: z.string().nullable(),
enabled: z.coerce.boolean(),
lb_mode: lbModeSchema.catch("round_robin"),
health_check_enabled: z.coerce.boolean().default(false),
health_check_type: healthCheckTypeSchema.catch("tcp"),
health_check_port: z.number().nullable(),
health_check_path: z.string().nullable(),
health_check_expected_status: z.number().nullable(),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
created_at: z.string(),
updated_at: z.string()
});
var serviceSchema = z.object({
id: z.number(),
name: z.string(),
slug: z.string(),
service_group_id: z.number().nullable().optional(),
subdomain: z.string().optional(),
enabled: z.coerce.boolean().optional(),
computed_fqdn: z.string().nullable().optional(),
lb_weight: z.number().default(1),
lb_priority: z.number().default(1),
created_at: z.string(),
updated_at: z.string()
});
var serviceDomainBindingSchema = z.object({
binding_id: z.number(),
domain_id: z.number(),
zone_name: z.string(),
hostname: z.string(),
fqdn: z.string(),
record_type: z.enum(["A", "CNAME"]).default("A"),
target_ips: z.array(z.string()).optional(),
target_ip: z.string().nullable().optional(),
target_ip_weights: z.record(z.string(), z.number()).optional(),
target_ip_priorities: z.record(z.string(), z.number()).optional(),
target_cname: z.string().nullable().optional(),
lb_mode: lbModeSchema.catch("round_robin"),
health_check_enabled: z.coerce.boolean().default(false),
health_check_type: healthCheckTypeSchema.catch("tcp"),
health_check_port: z.number().nullable(),
health_check_path: z.string().nullable(),
health_check_expected_status: z.number().nullable(),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
sync_status: z.string().nullable()
}).transform((binding) => ({
...binding,
target_ips: binding.target_ips && binding.target_ips.length > 0 ? binding.target_ips : binding.target_ip ? [binding.target_ip] : [],
target_ip_weights: binding.target_ip_weights ?? {},
target_ip_priorities: binding.target_ip_priorities ?? {},
target_cname: binding.target_cname?.trim() || null,
record_type: binding.target_cname?.trim() ? "CNAME" : binding.record_type ?? "A"
}));
var serviceViewSchema = serviceSchema.extend({
subdomain: z.string().default(""),
enabled: z.coerce.boolean().default(false),
ips: z.array(z.string()).default([]),
domains: z.array(serviceDomainBindingSchema).default([])
});
var serviceGroupViewSchema = serviceGroupSchema.extend({
services: z.array(serviceViewSchema).default([])
});
var serviceGroupsResponseSchema = z.object({
groups: z.array(serviceGroupViewSchema).default([]),
ungrouped: z.array(serviceViewSchema).default([])
});
var domainSchema = z.object({
id: z.number(),
group_id: z.number().nullable(),
zone_name: z.string(),
cf_zone_id: z.string(),
status: z.string(),
cert_monitoring: certMonitoringSchema.default("auto"),
last_synced_at: z.string().nullable(),
created_at: z.string(),
updated_at: z.string()
});
var domainListItemSchema = domainSchema.extend({
group_name: z.string().nullable(),
service_count: z.number()
});
var serviceBindingSchema = z.object({
id: z.number(),
domain_id: z.number(),
service_id: z.number(),
hostname: z.string(),
dns_record_id: z.number().nullable(),
zone_name: z.string(),
group_id: z.number().nullable(),
group_name: z.string().nullable(),
service_name: z.string(),
service_slug: z.string(),
target_ip: z.string().nullable(),
target_ips: z.array(z.string()).optional(),
target_ip_weights: z.record(z.string(), z.number()).optional(),
target_ip_priorities: z.record(z.string(), z.number()).optional(),
lb_mode: lbModeSchema.catch("round_robin"),
health_check_enabled: z.coerce.boolean().default(false),
health_check_type: healthCheckTypeSchema.catch("tcp"),
health_check_port: z.number().nullable(),
health_check_path: z.string().nullable(),
health_check_expected_status: z.number().nullable(),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
sync_status: z.string().nullable(),
created_at: z.string(),
updated_at: z.string()
}).transform((binding) => ({
...binding,
target_ips: binding.target_ips && binding.target_ips.length > 0 ? binding.target_ips : binding.target_ip ? [binding.target_ip] : [],
target_ip_weights: binding.target_ip_weights ?? {},
target_ip_priorities: binding.target_ip_priorities ?? {}
}));
var dnsRecordSchema = z.object({
id: z.number(),
domain_id: z.number(),
cf_record_id: z.string().nullable(),
record_type: z.string(),
name: z.string(),
content: z.string(),
ttl: z.number(),
proxied: z.boolean(),
priority: z.number().nullable(),
sync_status: z.string(),
origin: z.string(),
last_error: z.string().nullable(),
created_at: z.string(),
updated_at: z.string()
});
var certificateSchema = z.object({
id: z.number(),
domain_id: z.number(),
subdomain_id: z.number().nullable(),
hostname: z.string(),
expires_at: z.string().nullable(),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable(),
status: z.string(),
created_at: z.string(),
updated_at: z.string()
});
var createGroupSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435"),
slug: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 slug")
});
var ipv4Schema = z.string().regex(
/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,
"\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 IPv4"
);
var healthCheckConfigFields = {
health_check_enabled: z.boolean().optional(),
health_check_type: healthCheckTypeSchema.optional(),
health_check_port: z.number().int().min(1).max(65535).nullable().optional(),
health_check_path: z.string().nullable().optional(),
health_check_expected_status: z.number().int().min(100).max(599).nullable().optional(),
health_check_interval_sec: z.number().int().min(5).max(3600).optional(),
health_check_timeout_ms: z.number().int().min(100).max(3e4).optional()
};
var healthCheckConfigSchema = z.object(healthCheckConfigFields);
var serviceDomainInputSchema = z.object({
fqdn: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 FQDN"),
target_ips: z.array(ipv4Schema).optional(),
target_cname: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 CNAME-\u0446\u0435\u043B\u044C").optional(),
target_ip_weights: z.record(ipv4Schema, z.number().int().min(1).max(100)).optional(),
target_ip_priorities: z.record(ipv4Schema, z.number().int().min(1).max(100)).optional(),
lb_mode: lbModeSchema.optional(),
...healthCheckConfigFields
}).superRefine((data, ctx) => {
const hasIps = (data.target_ips?.length ?? 0) > 0;
const hasCname = Boolean(data.target_cname?.trim());
if (!hasIps && !hasCname) {
ctx.addIssue({
code: "custom",
message: "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 IP \u0438\u043B\u0438 CNAME-\u0446\u0435\u043B\u044C",
path: ["target_ips"]
});
}
if (hasIps && hasCname) {
ctx.addIssue({
code: "custom",
message: "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043B\u0438\u0431\u043E IP, \u043B\u0438\u0431\u043E CNAME-\u0446\u0435\u043B\u044C",
path: ["target_cname"]
});
}
});
var createServiceSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435"),
slug: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 slug")
});
var createServiceWithConfigSchema = createServiceSchema.extend({
service_group_id: z.number().nullable().optional(),
ips: z.array(ipv4Schema).default([]),
lb_weight: z.number().int().min(1).max(100).optional(),
lb_priority: z.number().int().min(1).max(100).optional(),
domains: z.array(serviceDomainInputSchema).default([])
});
var createServiceBindingSchema = z.object({
domain_id: z.string().min(1, "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u043E\u043C\u0435\u043D"),
service_id: z.string().min(1, "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441"),
hostname: z.string().optional(),
target_ip: z.string().optional()
});
var updateDomainGroupSchema = z.object({
group_id: z.number().nullable(),
status: z.string().optional()
});
var createDomainSchema = z.object({
zone_name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0438\u043C\u044F \u0437\u043E\u043D\u044B"),
group_id: z.string()
});
var loginSchema = z.object({
username: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F"),
password: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044C")
});
var createDnsRecordSchema = z.object({
record_type: z.enum(["A", "AAAA", "CNAME", "TXT", "MX"]),
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0438\u043C\u044F"),
content: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"),
ttl: z.number().int().min(1),
proxied: z.boolean()
});
var subdomainSchema = z.object({
id: z.number(),
domain_id: z.number(),
name: z.string(),
fqdn: z.string(),
enabled: z.boolean(),
cert_monitoring: certMonitoringSchema.default("auto"),
created_at: z.string(),
updated_at: z.string()
});
var createSubdomainSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0438\u043C\u044F \u043F\u043E\u0434\u0434\u043E\u043C\u0435\u043D\u0430")
});
var updateSubdomainSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0438\u043C\u044F \u043F\u043E\u0434\u0434\u043E\u043C\u0435\u043D\u0430").optional(),
enabled: z.boolean().optional(),
cert_monitoring: certMonitoringSchema.optional()
});
var updateDomainSchema = z.object({
group_id: z.number().nullable().optional(),
status: z.string().optional(),
cert_monitoring: certMonitoringSchema.optional()
});
var updateServiceConfigSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435").optional(),
slug: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 slug").optional(),
service_group_id: z.number().nullable().optional(),
ips: z.array(ipv4Schema).optional(),
lb_weight: z.number().int().min(1).max(100).optional(),
lb_priority: z.number().int().min(1).max(100).optional(),
domains: z.array(serviceDomainInputSchema).optional()
});
var createServiceGroupSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435"),
type: serviceGroupTypeSchema.default("custom"),
icon: z.string().nullable().optional(),
domain: z.string().nullable().optional(),
lb_mode: lbModeSchema.optional(),
...healthCheckConfigFields
});
var updateServiceGroupSchema = z.object({
name: z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435").optional(),
type: serviceGroupTypeSchema.optional(),
icon: z.string().nullable().optional(),
domain: z.string().nullable().optional(),
lb_mode: lbModeSchema.optional(),
...healthCheckConfigFields
});
var toggleEnabledSchema = z.object({
enabled: z.boolean()
});
var reorderServicesSchema = z.object({
group_id: z.union([z.number(), z.null()]).optional().default(null),
service_ids: z.array(z.number().int().positive()).min(1)
});
var healthStatusQuerySchema = z.object({
scope: healthCheckScopeSchema,
ref_id: z.coerce.number().int().positive()
});
// src/app-switcher.ts
import { z as z2 } from "zod";
var appSwitcherIconSchema = z2.enum([
"server",
"cloud",
"globe",
"dashboard",
"chart"
]);
var appSwitcherEntrySchema = z2.object({
id: z2.string(),
name: z2.string(),
subtitle: z2.string().optional(),
url: z2.string().url(),
icon: appSwitcherIconSchema.default("server"),
shortcut: z2.string().optional()
});
var appSwitcherConfigSchema = z2.object({
menuLabel: z2.string().default("\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F"),
apps: z2.array(appSwitcherEntrySchema).min(1)
});
// src/integration-vps-tracker.ts
import { z as z3 } from "zod";
var cfdmBindingSyncItemSchema = z3.object({
bindingId: z3.number().int().positive(),
serviceId: z3.number().int().positive(),
serviceName: z3.string().min(1),
serviceSlug: z3.string().min(1),
fqdn: z3.string().min(1),
zoneName: z3.string().min(1),
hostname: z3.string(),
ips: z3.array(z3.string()),
deleted: z3.boolean().optional()
});
var cfdmSyncBindingsBodySchema = z3.object({
bindings: z3.array(cfdmBindingSyncItemSchema).min(1)
});
var appSettingsPatchSchema = z3.object({
appSwitcher: appSwitcherConfigSchema.optional(),
vpsTrackerUrl: z3.string().url().or(z3.literal("")).optional(),
vpsTrackerIntegrationToken: z3.string().optional(),
vpsTrackerSyncEnabled: z3.boolean().optional()
});
var vpsTrackerEventSchema = z3.object({
event: z3.enum(["vps_down", "vps_up"]),
vps: z3.array(
z3.object({
id: z3.string().min(1),
ip: z3.string().optional(),
label: z3.string().optional()
})
),
timestamp: z3.string().datetime().optional()
});
export {
CERT_ERROR,
CERT_EXPIRED,
CERT_MONITORING_VALUES,
CERT_MONITOR_AUTO,
CERT_MONITOR_REQUIRED,
CERT_MONITOR_SKIPPED,
CERT_OK,
CERT_UNKNOWN,
CERT_WARNING,
SYNC_CONFLICT,
SYNC_ERROR,
SYNC_PENDING_DELETE,
SYNC_PENDING_PUSH,
SYNC_SYNCED,
ValidationError,
appSettingsPatchSchema,
appSwitcherConfigSchema,
appSwitcherEntrySchema,
appSwitcherIconSchema,
bindingToFqdn,
certMonitoringSchema,
certStatusFromExpiry,
certificateSchema,
cfdmBindingSyncItemSchema,
cfdmSyncBindingsBodySchema,
createDnsRecordSchema,
createDomainSchema,
createGroupSchema,
createServiceBindingSchema,
createServiceGroupSchema,
createServiceSchema,
createServiceWithConfigSchema,
createSubdomainSchema,
dnsNameToSubdomainLabel,
dnsRecordNamesMatch,
dnsRecordSchema,
domainListItemSchema,
domainSchema,
fqdnToDisplay,
groupSchema,
groupWithStatsSchema,
healthCheckConfigSchema,
healthCheckScopeSchema,
healthCheckTypeSchema,
healthStatusQuerySchema,
ipHealthStateSchema,
ipHealthStatusSchema,
isValidIpv4,
lbModeSchema,
loginSchema,
normalizeDnsRecordName,
parseFqdn,
reorderServicesSchema,
serviceBindingSchema,
serviceDomainBindingSchema,
serviceGroupSchema,
serviceGroupTypeSchema,
serviceGroupViewSchema,
serviceGroupsResponseSchema,
serviceSchema,
serviceViewSchema,
shouldMonitorService,
subdomainLabelToFqdn,
subdomainSchema,
toggleEnabledSchema,
updateDomainGroupSchema,
updateDomainSchema,
updateServiceConfigSchema,
updateServiceGroupSchema,
updateSubdomainSchema,
validateDnsRecord,
vpsTrackerEventSchema
};