Introduced a new `verify_tls` boolean option in health check configurations across various services, allowing users to specify whether to validate TLS certificates during health checks. Updated related components and services to accommodate this new option, ensuring proper handling in both the backend and frontend. Enhanced tests to validate the new functionality and ensure correct behavior with different configurations.
685 lines
24 KiB
JavaScript
685 lines
24 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", "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 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),
|
|
health_check_verify_tls: z.coerce.boolean().default(false),
|
|
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),
|
|
health_check_verify_tls: z.coerce.boolean().default(false),
|
|
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([]),
|
|
health_status: ipHealthStateSchema.default("unknown"),
|
|
health_latency_ms: z.number().nullable().default(null)
|
|
});
|
|
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.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),
|
|
health_check_verify_tls: z.coerce.boolean().default(false),
|
|
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(),
|
|
health_check_verify_tls: z.boolean().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 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"),
|
|
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()),
|
|
deleted: z3.boolean().optional()
|
|
});
|
|
var cfdmSyncBindingsBodySchema = z3.object({
|
|
bindings: z3.array(cfdmBindingSyncItemSchema).min(1)
|
|
});
|
|
var appSettingsPatchSchema = z3.object({
|
|
vpsTrackerUrl: z3.string().url().or(z3.literal("")).optional(),
|
|
vpsTrackerIntegrationToken: z3.string().optional(),
|
|
vpsTrackerSyncEnabled: z3.boolean().optional(),
|
|
showQuickActions: 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,
|
|
bulkUpdateDomainsSchema,
|
|
certMonitoringSchema,
|
|
certStatusFromExpiry,
|
|
certificateSchema,
|
|
cfdmBindingSyncItemSchema,
|
|
cfdmSyncBindingsBodySchema,
|
|
createDnsRecordSchema,
|
|
createDomainMonitorSchema,
|
|
createDomainSchema,
|
|
createGroupSchema,
|
|
createServiceBindingSchema,
|
|
createServiceGroupSchema,
|
|
createServiceSchema,
|
|
createServiceWithConfigSchema,
|
|
createSubdomainSchema,
|
|
dnsNameToSubdomainLabel,
|
|
dnsRecordNamesMatch,
|
|
dnsRecordSchema,
|
|
domainEnvironmentSchema,
|
|
domainListItemSchema,
|
|
domainMonitorResultSchema,
|
|
domainMonitorSchema,
|
|
domainMonitorTypeSchema,
|
|
domainSchema,
|
|
fqdnToDisplay,
|
|
groupSchema,
|
|
groupWithStatsSchema,
|
|
healthCheckConfigSchema,
|
|
healthCheckScopeSchema,
|
|
healthCheckTypeSchema,
|
|
healthStatusQuerySchema,
|
|
ipHealthStateSchema,
|
|
ipHealthStatusSchema,
|
|
isValidIpv4,
|
|
lbModeSchema,
|
|
loginSchema,
|
|
normalizeDnsRecordName,
|
|
notificationLogSchema,
|
|
parseFqdn,
|
|
reorderServicesSchema,
|
|
serviceBindingSchema,
|
|
serviceDomainBindingSchema,
|
|
serviceGroupSchema,
|
|
serviceGroupTypeSchema,
|
|
serviceGroupViewSchema,
|
|
serviceGroupsResponseSchema,
|
|
serviceSchema,
|
|
serviceViewSchema,
|
|
shouldMonitorService,
|
|
subdomainLabelToFqdn,
|
|
subdomainSchema,
|
|
toggleEnabledSchema,
|
|
updateDomainGroupSchema,
|
|
updateDomainSchema,
|
|
updateServiceConfigSchema,
|
|
updateServiceGroupSchema,
|
|
updateSubdomainSchema,
|
|
validateDnsRecord,
|
|
vpsTrackerEventSchema
|
|
};
|