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