Files
cloudflare-domain-manager/packages/shared/dist/index.js
T
Denozordec 6d1d8ca4f3
Build, Test, and Push CFDM Docker Image / test (push) Failing after 51s
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:Update pnpm-lock.yaml to link shared package; modify API routes to utilize new schemas for domain and service management; enhance DNS record handling with CNAME support; refactor service and subdomain routes for improved functionality; implement confirm dialog for domain deletion in the frontend; clean up unused components and improve UI consistency.
2026-06-22 13:52:33 +07:00

460 lines
15 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 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.boolean(),
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.boolean().optional(),
computed_fqdn: z.string().nullable().optional(),
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_cname: z.string().nullable().optional(),
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_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.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(),
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] : []
}));
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 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()
}).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([]),
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(),
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()
});
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)
});
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,
bindingToFqdn,
certMonitoringSchema,
certStatusFromExpiry,
certificateSchema,
createDnsRecordSchema,
createDomainSchema,
createGroupSchema,
createServiceBindingSchema,
createServiceGroupSchema,
createServiceSchema,
createServiceWithConfigSchema,
createSubdomainSchema,
dnsNameToSubdomainLabel,
dnsRecordNamesMatch,
dnsRecordSchema,
domainListItemSchema,
domainSchema,
fqdnToDisplay,
groupSchema,
groupWithStatsSchema,
isValidIpv4,
loginSchema,
normalizeDnsRecordName,
parseFqdn,
reorderServicesSchema,
serviceBindingSchema,
serviceDomainBindingSchema,
serviceGroupSchema,
serviceGroupTypeSchema,
serviceGroupViewSchema,
serviceGroupsResponseSchema,
serviceSchema,
serviceViewSchema,
shouldMonitorService,
subdomainLabelToFqdn,
subdomainSchema,
toggleEnabledSchema,
updateDomainGroupSchema,
updateDomainSchema,
updateServiceConfigSchema,
updateSubdomainSchema,
validateDnsRecord
};