Files
cloudflare-domain-manager/packages/shared/dist/index.js
T
DenozordecandCursor 7eb195c5d7
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 4s
quality / changes (push) Successful in 8s
quality / docker-check (push) Skipped
quality / web (push) Successful in 53s
quality / api (push) Successful in 49s
CD / quality (push) Successful in 1m54s
CD / publish (push) Successful in 1m29s
feat(sync): передавать lbMode в payload для VPS Tracker
Тип HA уходит в bindings, чтобы схема могла показать резервирование.

Co-authored-by: Cursor <[email protected]>
2026-09-01 11:30:41 +07:00

1098 lines
38 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 LABEL_RE = "[a-zA-Z0-9_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?";
var NAME_RE = new RegExp(
`^(@|\\*|(\\*\\.)?${LABEL_RE}(?:\\.${LABEL_RE})*)$`
);
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;
});
}
function isIpLiteral(value) {
const v = value.trim();
if (!v) return false;
if (isValidIpv4(v)) return true;
return IPV6_RE.test(v);
}
// 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.startsWith("*.")) return rn;
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";
// src/health-providers.ts
var HEALTH_CHECK_PROVIDERS = [
"local",
"cloudflare",
"globalping"
];
var HEALTH_STATUS_PROVIDERS = [
...HEALTH_CHECK_PROVIDERS,
"aggregate"
];
var HEALTH_CHECK_AGGREGATES = ["any", "all", "majority"];
var PROVIDER_SET = new Set(HEALTH_CHECK_PROVIDERS);
var STATUS_SET = new Set(HEALTH_STATUS_PROVIDERS);
var AGGREGATE_SET = new Set(HEALTH_CHECK_AGGREGATES);
function normalizeProbeProvider(value) {
return value === "cloudflare" || value === "globalping" || value === "local" ? value : "local";
}
function normalizeStatusProvider(value) {
if (typeof value === "string" && STATUS_SET.has(value)) {
return value;
}
return "local";
}
function uniqueHealthProviders(values) {
const out = [];
for (const value of values) {
if (!PROVIDER_SET.has(String(value))) continue;
const next = value;
if (!out.includes(next)) out.push(next);
}
return out;
}
function parseHealthProviders(json, fallback) {
if (Array.isArray(json)) {
const parsed = uniqueHealthProviders(json);
if (parsed.length > 0) return parsed;
}
if (typeof json === "string" && json.trim()) {
const trimmed = json.trim();
if (trimmed.startsWith("[")) {
try {
const parsed = uniqueHealthProviders(JSON.parse(trimmed));
if (parsed.length > 0) return parsed;
} catch {
}
}
const one = uniqueHealthProviders(trimmed.split(","));
if (one.length > 0) return one;
}
return [normalizeProbeProvider(fallback)];
}
function serializeHealthProviders(providers) {
const unique = uniqueHealthProviders(providers);
return JSON.stringify(unique.length > 0 ? unique : ["local"]);
}
function parseHealthAggregate(value) {
if (typeof value === "string" && AGGREGATE_SET.has(value)) {
return value;
}
return "majority";
}
function derivePrimaryProvider(providers) {
return uniqueHealthProviders(providers)[0] ?? "local";
}
function targetProviders(target) {
if (target.providers && target.providers.length > 0) {
return uniqueHealthProviders(target.providers);
}
return [normalizeProbeProvider(target.provider)];
}
function targetHasProvider(target, provider) {
return targetProviders(target).includes(provider);
}
function aggregateHealthOk(oks, policy) {
const n = oks.length;
if (n === 0) return false;
const down = oks.filter((ok) => !ok).length;
if (policy === "any") return down === 0;
if (policy === "all") return down < n;
return down < Math.floor(n / 2) + 1;
}
function clampGlobalpingLimit(value, fallback = 3) {
const n = typeof value === "number" ? value : Number(value);
if (!Number.isFinite(n)) return fallback;
return Math.min(10, Math.max(1, Math.trunc(n)));
}
function parseGlobalpingLocations(value) {
const raw = typeof value === "string" ? value : "";
const parts = raw.split(",").map((part) => part.trim()).filter(Boolean);
return parts.length > 0 ? parts : ["World"];
}
// src/schemas.ts
var certMonitoringSchema = z.enum(["auto", "required", "skipped"]);
var lbModeSchema = z.enum(["round_robin", "failover", "weighted"]);
var healthCheckTypeSchema = z.enum(["tcp", "http", "ping", "dns"]);
var domainEnvironmentSchema = z.enum(["prod", "staging", "dev"]);
var domainMonitorTypeSchema = z.enum(["http", "ping", "dns"]);
var ipHealthStateSchema = z.enum(["up", "down", "degraded", "unknown"]);
var nodeHealthStateSchema = z.enum([
"unknown",
"checking",
"healthy",
"degraded",
"unhealthy",
"disabled"
]);
var healthCheckProviderSchema = z.enum(HEALTH_CHECK_PROVIDERS);
var healthStatusProviderSchema = z.enum(HEALTH_STATUS_PROVIDERS);
var healthCheckAggregateSchema = z.enum(HEALTH_CHECK_AGGREGATES);
var healthCheckProvidersSchema = z.preprocess(
(value) => {
if (value === void 0) return void 0;
return Array.isArray(value) ? value : parseHealthProviders(value);
},
z.array(healthCheckProviderSchema).min(1).transform((arr) => {
const unique = uniqueHealthProviders(arr);
return unique.length > 0 ? unique : ["local"];
})
);
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(),
consecutive_successes: z.number().optional().default(0),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable(),
colo: z.string().nullable().optional(),
provider: healthStatusProviderSchema.optional()
});
var serviceIpHealthSchema = z.object({
ip: z.string(),
status: ipHealthStateSchema,
latency_ms: z.number().nullable(),
last_checked_at: z.string().nullable().optional(),
last_error: z.string().nullable().optional(),
provider: healthStatusProviderSchema.optional(),
colo: z.string().nullable().optional()
});
var healthProbeLogSchema = z.object({
id: z.number(),
scope: z.string(),
ref_id: z.number(),
ip: z.string(),
provider: healthCheckProviderSchema,
status: ipHealthStateSchema,
ok: z.coerce.boolean(),
latency_ms: z.number().nullable(),
colo: z.string().nullable(),
error: z.string().nullable(),
checked_at: z.string()
});
var failoverLogSchema = z.object({
id: z.number(),
service_id: z.number(),
binding_id: z.number(),
fqdn: z.string(),
ip: z.string(),
action: z.enum(["added", "removed"]),
created_at: z.string()
});
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().default(null),
domain: z.string().nullable().default(null),
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().default(null),
health_check_path: z.string().nullable().default(null),
health_check_expected_status: z.number().nullable().default(null),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
health_check_verify_tls: z.coerce.boolean().default(false),
health_check_provider: healthCheckProviderSchema.catch("local"),
health_check_providers: healthCheckProvidersSchema.catch(["local"]),
health_check_aggregate: healthCheckAggregateSchema.catch("majority"),
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.coerce.number()).optional(),
target_ip_priorities: z.record(z.string(), z.coerce.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().default(null),
health_check_path: z.string().nullable().default(null),
health_check_expected_status: z.number().nullable().default(null),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
health_check_verify_tls: z.coerce.boolean().default(false),
health_check_provider: healthCheckProviderSchema.catch("local"),
health_check_providers: healthCheckProvidersSchema.catch(["local"]),
health_check_aggregate: healthCheckAggregateSchema.catch("majority"),
cert_monitoring: certMonitoringSchema.default("auto"),
sync_status: z.string().nullable().default(null),
active_ips: z.array(z.string()).default([])
}).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([]),
health_status: ipHealthStateSchema.default("unknown"),
health_latency_ms: z.number().nullable().default(null),
ip_health: z.array(serviceIpHealthSchema).default([]),
ip_enabled: z.record(z.string(), z.boolean()).default({}),
lb_mode: lbModeSchema.catch("round_robin"),
active_ips: z.array(z.string()).default([])
});
var serviceGroupViewSchema = serviceGroupSchema.extend({
services: z.array(serviceViewSchema).default([]),
health_status: ipHealthStateSchema.default("unknown"),
health_latency_ms: z.number().nullable().default(null)
});
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"),
environment: domainEnvironmentSchema.nullable().optional().default(null),
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(),
health_status: ipHealthStateSchema.default("unknown"),
health_latency_ms: z.number().nullable().default(null),
tags: z.array(z.string()).default([])
});
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.coerce.number()).optional(),
target_ip_priorities: z.record(z.string(), z.coerce.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().default(null),
health_check_path: z.string().nullable().default(null),
health_check_expected_status: z.number().nullable().default(null),
health_check_interval_sec: z.number().default(30),
health_check_timeout_ms: z.number().default(3e3),
health_check_verify_tls: z.coerce.boolean().default(false),
cert_monitoring: certMonitoringSchema.default("auto"),
sync_status: z.string().nullable().default(null),
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(),
service_id: z.number().nullable().optional().default(null),
service_name: z.string().nullable().optional().default(null),
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 serviceCertificateRowSchema = z.object({
binding_id: z.number(),
domain_id: z.number(),
service_id: z.number(),
hostname: z.string(),
cert_monitoring: certMonitoringSchema,
id: z.number().nullable(),
status: z.string(),
expires_at: z.string().nullable(),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable()
});
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 nodeAddressSchema = z.string().min(1, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 IP \u0438\u043B\u0438 hostname").max(255);
var healthCheckConfigFields = {
health_check_enabled: z.coerce.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(),
health_check_verify_tls: z.coerce.boolean().optional(),
health_check_provider: healthCheckProviderSchema.optional(),
health_check_providers: healthCheckProvidersSchema.optional(),
health_check_aggregate: healthCheckAggregateSchema.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(),
environment: domainEnvironmentSchema.nullable().optional(),
tags: z.array(z.string().min(1).max(64)).max(20).optional()
});
var bulkUpdateDomainsSchema = z.object({
ids: z.array(z.number().int().positive()).min(1),
group_id: z.number().nullable().optional(),
environment: domainEnvironmentSchema.nullable().optional(),
tags_add: z.array(z.string().min(1).max(64)).max(20).optional()
});
var domainMonitorSchema = z.object({
id: z.number(),
domain_id: z.number(),
hostname: z.string(),
type: domainMonitorTypeSchema,
enabled: z.coerce.boolean(),
interval_sec: z.number(),
timeout_ms: z.number(),
path: z.string().nullable(),
expected_status: z.number().nullable(),
last_status: ipHealthStateSchema.default("unknown"),
last_latency_ms: z.number().nullable(),
last_checked_at: z.string().nullable(),
last_error: z.string().nullable(),
created_at: z.string(),
updated_at: z.string()
});
var createDomainMonitorSchema = z.object({
hostname: z.string().min(1),
type: domainMonitorTypeSchema,
enabled: z.boolean().optional().default(true),
interval_sec: z.number().int().min(10).max(3600).optional().default(60),
timeout_ms: z.number().int().min(500).max(3e4).optional().default(5e3),
path: z.string().nullable().optional(),
expected_status: z.number().int().min(100).max(599).nullable().optional()
});
var domainMonitorResultSchema = z.object({
id: z.number(),
monitor_id: z.number(),
status: ipHealthStateSchema,
latency_ms: z.number().nullable(),
error: z.string().nullable(),
checked_at: z.string()
});
var notificationLogSchema = z.object({
id: z.number(),
kind: z.string(),
ref_type: z.string(),
ref_id: z.number().nullable(),
title: z.string(),
message: z.string(),
created_at: z.string()
});
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 toggleServiceIpSchema = z.object({
ip: ipv4Schema,
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()
});
var serviceNodeSchema = z.object({
id: z.number(),
service_id: z.number(),
address: z.string(),
protocol: z.string(),
port: z.number().nullable(),
enabled: z.coerce.boolean(),
priority: z.number(),
weight: z.number(),
health_status: nodeHealthStateSchema,
health_check_id: z.number().nullable(),
consecutive_failures: z.number(),
consecutive_successes: z.number(),
last_check_at: z.string().nullable(),
last_failure_reason: z.string().nullable(),
created_at: z.string(),
updated_at: z.string()
});
var createServiceNodeSchema = z.object({
address: nodeAddressSchema,
protocol: z.enum(["tcp", "http", "https"]).optional().default("tcp"),
port: z.number().int().min(1).max(65535).nullable().optional(),
enabled: z.boolean().optional().default(true),
priority: z.number().int().min(1).max(100).optional().default(1),
weight: z.number().int().min(1).max(100).optional().default(1),
health_check_id: z.number().int().positive().nullable().optional()
});
var updateServiceNodeSchema = createServiceNodeSchema.partial();
var originHealthCheckSchema = z.object({
id: z.number(),
provider: healthCheckProviderSchema,
cf_healthcheck_id: z.string().nullable(),
cf_zone_id: z.string().nullable(),
name: z.string(),
protocol: z.string(),
path: z.string().nullable(),
method: z.string().nullable(),
timeout: z.number(),
interval_sec: z.number(),
retries: z.number(),
expected_status: z.number().nullable(),
consecutive_fails: z.number(),
consecutive_successes: z.number(),
suspended: z.coerce.boolean(),
created_at: z.string(),
updated_at: z.string()
});
var createOriginHealthCheckSchema = z.object({
provider: healthCheckProviderSchema,
name: z.string().min(1).max(64),
cf_zone_id: z.string().nullable().optional(),
protocol: z.enum(["HTTP", "HTTPS", "TCP", "tcp", "http", "https"]).optional(),
path: z.string().nullable().optional(),
method: z.string().nullable().optional(),
timeout: z.number().int().min(1).max(60).optional(),
interval_sec: z.number().int().min(5).max(3600).optional(),
retries: z.number().int().min(0).max(10).optional(),
expected_status: z.number().int().min(100).max(599).nullable().optional(),
consecutive_fails: z.number().int().min(1).max(20).optional(),
consecutive_successes: z.number().int().min(1).max(20).optional(),
suspended: z.boolean().optional(),
node_id: z.number().int().positive().optional()
});
var changeIpSchema = z.object({
from_ip: z.string().optional(),
to_ip: z.string().min(1).optional(),
node_id: z.number().int().positive().optional(),
dry_run: z.boolean().optional().default(false)
});
var changeDomainSchema = z.object({
from_domain_id: z.number().int().positive(),
to_domain_id: z.number().int().positive(),
hostnames: z.array(z.string().min(1)).optional(),
dry_run: z.boolean().optional().default(false)
});
// 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"),
enabled: z2.boolean().optional(),
sort: z2.number().optional(),
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()),
/** CNAME-цель (FQDN), если binding — CNAME; для матчинга в VPS Tracker. */
cnameTarget: z3.string().optional(),
/** HA-режим binding (fallback — service group). Optional для старых payload. */
lbMode: z3.enum(["round_robin", "failover", "weighted"]).optional(),
deleted: z3.boolean().optional()
});
var cfdmSyncBindingsBodySchema = z3.object({
bindings: z3.array(cfdmBindingSyncItemSchema),
/** Полная пересинхронизация: удалить CFDM-домены, которых нет в payload. */
fullSync: z3.boolean().optional()
}).refine((data) => data.fullSync === true || data.bindings.length >= 1, {
message: "bindings \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D, \u0435\u0441\u043B\u0438 fullSync \u043D\u0435 \u0437\u0430\u0434\u0430\u043D",
path: ["bindings"]
});
var appSettingsPatchSchema = z3.object({
vpsTrackerUrl: z3.string().url().or(z3.literal("")).optional(),
vpsTrackerIntegrationToken: z3.string().optional(),
vpsTrackerSyncEnabled: z3.boolean().optional(),
showQuickActions: z3.boolean().optional(),
healthCheckCron: z3.string().trim().min(1).max(64).optional(),
healthDegradedFailures: z3.number().int().min(1).max(20).optional(),
healthDownFailures: z3.number().int().min(1).max(50).optional(),
healthLatencyWarnMs: z3.number().int().min(50).max(6e4).optional(),
healthSuccessRecoveries: z3.number().int().min(1).max(20).optional(),
healthWorkerUrl: z3.string().url().or(z3.literal("")).optional(),
healthWorkerToken: z3.string().optional(),
globalpingToken: z3.string().optional(),
globalpingLocations: z3.string().trim().max(200).optional(),
globalpingLimit: z3.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: "\u043E\u0448\u0438\u0431\u043E\u043A \u0434\u043E down \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435, \u0447\u0435\u043C \u0434\u043E degraded",
path: ["healthDownFailures"]
});
}
});
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()
});
// src/health-probe-mailbox.ts
var HEALTH_PROBE_SCRIPT_NAME = "cfdm-health-probe";
var HEALTH_PROBE_KV_TITLE = "cfdm-health-probe";
var HEALTH_KV_TARGETS_KEY = "targets";
var HEALTH_KV_RESULTS_KEY = "results";
var HEALTH_KV_CURSOR_KEY = "cursor";
var HEALTH_PROBE_BATCH = 48;
var HEALTH_PROBE_CONCURRENCY = 5;
// src/audit.ts
import { z as z4 } from "zod";
var AUDIT_SEVERITIES = ["info", "warning", "critical"];
var auditSeveritySchema = z4.enum(AUDIT_SEVERITIES);
var AUDIT_SOURCE_APPS = [
"portal",
"vps",
"cfdm",
"bgp",
"fw"
];
var auditSourceAppSchema = z4.enum(AUDIT_SOURCE_APPS);
var AUDIT_TARGET_TYPES = [
"user",
"settings",
"session",
"system",
"app_resource"
];
var auditTargetTypeSchema = z4.enum(AUDIT_TARGET_TYPES);
var auditLogEntrySchema = z4.object({
id: z4.string(),
event_id: z4.string().nullable(),
source_app: auditSourceAppSchema,
action: z4.string(),
severity: auditSeveritySchema,
actor_user_id: z4.string().nullable(),
actor_email: z4.string().nullable(),
actor_name: z4.string().nullable(),
target_type: auditTargetTypeSchema.nullable(),
target_id: z4.string().nullable(),
summary: z4.string(),
details: z4.record(z4.string(), z4.unknown()).nullable(),
ip: z4.string().nullable(),
created_at: z4.string()
});
var auditListQuerySchema = z4.object({
action: z4.string().optional(),
severity: auditSeveritySchema.optional(),
user_id: z4.string().optional(),
source_app: auditSourceAppSchema.optional(),
limit: z4.coerce.number().int().min(1).max(500).default(200)
});
var ingestAuditEventSchema = z4.object({
event_id: z4.string().min(1).max(128),
source_app: z4.enum(["vps", "cfdm", "bgp", "fw"]),
action: z4.string().min(1).max(200),
severity: auditSeveritySchema.optional(),
actor_user_id: z4.string().nullable().optional(),
actor_email: z4.string().email().nullable().optional(),
actor_name: z4.string().nullable().optional(),
target_type: auditTargetTypeSchema.nullable().optional(),
target_id: z4.string().nullable().optional(),
summary: z4.string().min(1).max(500),
details: z4.record(z4.string(), z4.unknown()).nullable().optional(),
ip: z4.string().nullable().optional(),
created_at: z4.string().optional()
});
export {
AUDIT_SEVERITIES,
AUDIT_SOURCE_APPS,
AUDIT_TARGET_TYPES,
CERT_ERROR,
CERT_EXPIRED,
CERT_MONITORING_VALUES,
CERT_MONITOR_AUTO,
CERT_MONITOR_REQUIRED,
CERT_MONITOR_SKIPPED,
CERT_OK,
CERT_UNKNOWN,
CERT_WARNING,
HEALTH_CHECK_AGGREGATES,
HEALTH_CHECK_PROVIDERS,
HEALTH_KV_CURSOR_KEY,
HEALTH_KV_RESULTS_KEY,
HEALTH_KV_TARGETS_KEY,
HEALTH_PROBE_BATCH,
HEALTH_PROBE_CONCURRENCY,
HEALTH_PROBE_KV_TITLE,
HEALTH_PROBE_SCRIPT_NAME,
HEALTH_STATUS_PROVIDERS,
SYNC_CONFLICT,
SYNC_ERROR,
SYNC_PENDING_DELETE,
SYNC_PENDING_PUSH,
SYNC_SYNCED,
ValidationError,
aggregateHealthOk,
appSettingsPatchSchema,
appSwitcherConfigSchema,
appSwitcherEntrySchema,
appSwitcherIconSchema,
auditListQuerySchema,
auditLogEntrySchema,
auditSeveritySchema,
auditSourceAppSchema,
auditTargetTypeSchema,
bindingToFqdn,
bulkUpdateDomainsSchema,
certMonitoringSchema,
certStatusFromExpiry,
certificateSchema,
cfdmBindingSyncItemSchema,
cfdmSyncBindingsBodySchema,
changeDomainSchema,
changeIpSchema,
clampGlobalpingLimit,
createDnsRecordSchema,
createDomainMonitorSchema,
createDomainSchema,
createGroupSchema,
createOriginHealthCheckSchema,
createServiceBindingSchema,
createServiceGroupSchema,
createServiceNodeSchema,
createServiceSchema,
createServiceWithConfigSchema,
createSubdomainSchema,
derivePrimaryProvider,
dnsNameToSubdomainLabel,
dnsRecordNamesMatch,
dnsRecordSchema,
domainEnvironmentSchema,
domainListItemSchema,
domainMonitorResultSchema,
domainMonitorSchema,
domainMonitorTypeSchema,
domainSchema,
failoverLogSchema,
fqdnToDisplay,
groupSchema,
groupWithStatsSchema,
healthCheckAggregateSchema,
healthCheckConfigSchema,
healthCheckProviderSchema,
healthCheckProvidersSchema,
healthCheckScopeSchema,
healthCheckTypeSchema,
healthProbeLogSchema,
healthStatusProviderSchema,
healthStatusQuerySchema,
ingestAuditEventSchema,
ipHealthStateSchema,
ipHealthStatusSchema,
isIpLiteral,
isValidIpv4,
lbModeSchema,
loginSchema,
nodeHealthStateSchema,
normalizeDnsRecordName,
normalizeProbeProvider,
normalizeStatusProvider,
notificationLogSchema,
originHealthCheckSchema,
parseFqdn,
parseGlobalpingLocations,
parseHealthAggregate,
parseHealthProviders,
reorderServicesSchema,
serializeHealthProviders,
serviceBindingSchema,
serviceCertificateRowSchema,
serviceDomainBindingSchema,
serviceGroupSchema,
serviceGroupTypeSchema,
serviceGroupViewSchema,
serviceGroupsResponseSchema,
serviceIpHealthSchema,
serviceNodeSchema,
serviceSchema,
serviceViewSchema,
shouldMonitorService,
subdomainLabelToFqdn,
subdomainSchema,
targetHasProvider,
targetProviders,
toggleEnabledSchema,
toggleServiceIpSchema,
uniqueHealthProviders,
updateDomainGroupSchema,
updateDomainSchema,
updateServiceConfigSchema,
updateServiceGroupSchema,
updateServiceNodeSchema,
updateSubdomainSchema,
validateDnsRecord,
vpsTrackerEventSchema
};