Enhance CDN Manager: Add Cloudflare API token support, update documentation, and introduce new routes for managing nodes, aliases, and topology. Improve UI components and status badges for better user experience.
quality / commitlint (push) Skipped
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / web (push) Successful in 53s
quality / api (push) Successful in 49s
CD / quality (push) Successful in 1m57s
CD / publish (push) Successful in 27s
quality / commitlint (push) Skipped
quality / changes (push) Successful in 5s
quality / docker-check (push) Skipped
CD / update-wiki (push) Successful in 6s
quality / web (push) Successful in 53s
quality / api (push) Successful in 49s
CD / quality (push) Successful in 1m57s
CD / publish (push) Successful in 27s
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const nodeRoleSchema = z.enum(["hub", "gw", "edge", "ix"]);
|
||||
export type NodeRole = z.infer<typeof nodeRoleSchema>;
|
||||
|
||||
export const aliasPurposeSchema = z.enum([
|
||||
"geo",
|
||||
"ix",
|
||||
"backup",
|
||||
"admin",
|
||||
"custom",
|
||||
]);
|
||||
export type AliasPurpose = z.infer<typeof aliasPurposeSchema>;
|
||||
|
||||
export const aliasModeSchema = z.enum(["primary", "pair"]);
|
||||
export type AliasMode = z.infer<typeof aliasModeSchema>;
|
||||
|
||||
export const syncStatusSchema = z.enum([
|
||||
"pending",
|
||||
"ok",
|
||||
"drift",
|
||||
"missing",
|
||||
"error",
|
||||
]);
|
||||
export type SyncStatus = z.infer<typeof syncStatusSchema>;
|
||||
|
||||
export const addressFamilySchema = z.enum(["v4", "v6"]);
|
||||
|
||||
export const cfZoneSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
status: z.string().optional(),
|
||||
});
|
||||
export type CfZone = z.infer<typeof cfZoneSchema>;
|
||||
|
||||
export const cfDnsRecordSchema = z.object({
|
||||
id: z.string().optional(),
|
||||
type: z.string(),
|
||||
name: z.string(),
|
||||
content: z.string(),
|
||||
ttl: z.number(),
|
||||
proxied: z.boolean().optional(),
|
||||
priority: z.number().optional(),
|
||||
});
|
||||
export type CfDnsRecord = z.infer<typeof cfDnsRecordSchema>;
|
||||
|
||||
export const createDnsRecordPayloadSchema = z.object({
|
||||
type: z.string(),
|
||||
name: z.string(),
|
||||
content: z.string(),
|
||||
ttl: z.number(),
|
||||
proxied: z.boolean().optional(),
|
||||
priority: z.number().optional(),
|
||||
});
|
||||
export type CreateDnsRecordPayload = z.infer<typeof createDnsRecordPayloadSchema>;
|
||||
|
||||
export const patchDnsRecordPayloadSchema = createDnsRecordPayloadSchema.partial();
|
||||
export type PatchDnsRecordPayload = z.infer<typeof patchDnsRecordPayloadSchema>;
|
||||
|
||||
export const locationSchema = z.object({
|
||||
id: z.string(),
|
||||
code: z.string(),
|
||||
name: z.string(),
|
||||
country: z.string().nullable(),
|
||||
sortOrder: z.number(),
|
||||
});
|
||||
export type Location = z.infer<typeof locationSchema>;
|
||||
|
||||
export const zoneSchema = z.object({
|
||||
id: z.string(),
|
||||
cfZoneId: z.string().nullable(),
|
||||
name: z.string(),
|
||||
role: z.string(),
|
||||
namingTemplate: z.string(),
|
||||
defaultTtl: z.number(),
|
||||
lastSyncAt: z.string().nullable(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
});
|
||||
export type Zone = z.infer<typeof zoneSchema>;
|
||||
|
||||
export const zoneCreateSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
cfZoneId: z.string().optional().nullable(),
|
||||
role: z.string().default("routing"),
|
||||
namingTemplate: z.string().optional(),
|
||||
defaultTtl: z.number().int().min(60).max(86400).optional(),
|
||||
});
|
||||
export type ZoneCreate = z.infer<typeof zoneCreateSchema>;
|
||||
|
||||
export const zonePatchSchema = zoneCreateSchema.partial();
|
||||
export type ZonePatch = z.infer<typeof zonePatchSchema>;
|
||||
|
||||
export const nodeAddressSchema = z.object({
|
||||
id: z.string(),
|
||||
family: addressFamilySchema,
|
||||
ip: z.string(),
|
||||
});
|
||||
export type NodeAddress = z.infer<typeof nodeAddressSchema>;
|
||||
|
||||
export const nodeSchema = z.object({
|
||||
id: z.string(),
|
||||
zoneId: z.string(),
|
||||
locationId: z.string(),
|
||||
locationCode: z.string().optional(),
|
||||
locationName: z.string().optional(),
|
||||
hostname: z.string(),
|
||||
role: nodeRoleSchema,
|
||||
indexNum: z.number(),
|
||||
providerTag: z.string().nullable(),
|
||||
notes: z.string().nullable(),
|
||||
syncStatus: syncStatusSchema,
|
||||
cfARecordId: z.string().nullable(),
|
||||
cfAaaaRecordId: z.string().nullable(),
|
||||
lastError: z.string().nullable(),
|
||||
addresses: z.array(nodeAddressSchema).default([]),
|
||||
aliasCount: z.number().optional(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
});
|
||||
export type Node = z.infer<typeof nodeSchema>;
|
||||
|
||||
export const nodeCreateSchema = z.object({
|
||||
zoneId: z.string().min(1),
|
||||
locationId: z.string().min(1),
|
||||
role: nodeRoleSchema,
|
||||
indexNum: z.number().int().min(1).max(99).default(1),
|
||||
hostname: z.string().min(1).optional(),
|
||||
providerTag: z.string().optional().nullable(),
|
||||
notes: z.string().optional().nullable(),
|
||||
ipv4: z.string().min(1),
|
||||
ipv6: z.string().optional().nullable(),
|
||||
});
|
||||
export type NodeCreate = z.infer<typeof nodeCreateSchema>;
|
||||
|
||||
export const nodePatchSchema = z.object({
|
||||
locationId: z.string().optional(),
|
||||
role: nodeRoleSchema.optional(),
|
||||
indexNum: z.number().int().min(1).max(99).optional(),
|
||||
hostname: z.string().min(1).optional(),
|
||||
providerTag: z.string().optional().nullable(),
|
||||
notes: z.string().optional().nullable(),
|
||||
ipv4: z.string().min(1).optional(),
|
||||
ipv6: z.string().optional().nullable(),
|
||||
});
|
||||
export type NodePatch = z.infer<typeof nodePatchSchema>;
|
||||
|
||||
export const aliasSchema = z.object({
|
||||
id: z.string(),
|
||||
zoneId: z.string(),
|
||||
name: z.string(),
|
||||
purpose: aliasPurposeSchema,
|
||||
mode: aliasModeSchema,
|
||||
targetNodeId: z.string(),
|
||||
targetHostname: z.string().optional(),
|
||||
syncStatus: syncStatusSchema,
|
||||
cfRecordId: z.string().nullable(),
|
||||
lastError: z.string().nullable(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
});
|
||||
export type Alias = z.infer<typeof aliasSchema>;
|
||||
|
||||
export const aliasCreateSchema = z.object({
|
||||
zoneId: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
purpose: aliasPurposeSchema.default("geo"),
|
||||
mode: aliasModeSchema.default("primary"),
|
||||
targetNodeId: z.string().min(1),
|
||||
});
|
||||
export type AliasCreate = z.infer<typeof aliasCreateSchema>;
|
||||
|
||||
export const aliasPatchSchema = z.object({
|
||||
name: z.string().min(1).optional(),
|
||||
purpose: aliasPurposeSchema.optional(),
|
||||
mode: aliasModeSchema.optional(),
|
||||
targetNodeId: z.string().min(1).optional(),
|
||||
});
|
||||
export type AliasPatch = z.infer<typeof aliasPatchSchema>;
|
||||
|
||||
export const aliasRetargetSchema = z.object({
|
||||
targetNodeId: z.string().min(1),
|
||||
});
|
||||
export type AliasRetarget = z.infer<typeof aliasRetargetSchema>;
|
||||
|
||||
export const syncDiffOpSchema = z.object({
|
||||
id: z.string(),
|
||||
kind: z.enum([
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"orphan",
|
||||
"proxy_violation",
|
||||
"noop",
|
||||
]),
|
||||
entityType: z.enum(["node_a", "node_aaaa", "alias", "orphan"]),
|
||||
entityId: z.string().nullable(),
|
||||
recordName: z.string(),
|
||||
recordType: z.string(),
|
||||
desired: z.record(z.string(), z.unknown()).nullable(),
|
||||
observed: z.record(z.string(), z.unknown()).nullable(),
|
||||
detail: z.string().optional(),
|
||||
});
|
||||
export type SyncDiffOp = z.infer<typeof syncDiffOpSchema>;
|
||||
|
||||
export const syncJobSchema = z.object({
|
||||
id: z.string(),
|
||||
zoneId: z.string(),
|
||||
status: z.enum(["pending", "running", "done", "failed"]),
|
||||
diff: z.array(syncDiffOpSchema).optional(),
|
||||
error: z.string().nullable(),
|
||||
createdAt: z.string(),
|
||||
finishedAt: z.string().nullable(),
|
||||
});
|
||||
export type SyncJob = z.infer<typeof syncJobSchema>;
|
||||
|
||||
export const syncApplySchema = z.object({
|
||||
opIds: z.array(z.string()).optional(),
|
||||
});
|
||||
export type SyncApply = z.infer<typeof syncApplySchema>;
|
||||
|
||||
export const dashboardStatsSchema = z.object({
|
||||
nodes: z.number(),
|
||||
aliases: z.number(),
|
||||
syncOk: z.number(),
|
||||
drift: z.number(),
|
||||
proxyViolations: z.number(),
|
||||
orphans: z.number(),
|
||||
lastSyncAt: z.string().nullable(),
|
||||
nodesWithoutIp: z.number(),
|
||||
brokenAliases: z.number(),
|
||||
});
|
||||
export type DashboardStats = z.infer<typeof dashboardStatsSchema>;
|
||||
|
||||
export const topologyNodeSchema = z.object({
|
||||
id: z.string(),
|
||||
hostname: z.string(),
|
||||
role: nodeRoleSchema,
|
||||
locationCode: z.string(),
|
||||
ipv4: z.string().nullable(),
|
||||
syncStatus: syncStatusSchema,
|
||||
});
|
||||
|
||||
export const topologyEdgeSchema = z.object({
|
||||
id: z.string(),
|
||||
aliasName: z.string(),
|
||||
purpose: aliasPurposeSchema,
|
||||
fromNodeId: z.string(),
|
||||
toHostname: z.string(),
|
||||
});
|
||||
|
||||
export const topologySchema = z.object({
|
||||
nodes: z.array(topologyNodeSchema),
|
||||
edges: z.array(topologyEdgeSchema),
|
||||
locations: z.array(locationSchema),
|
||||
});
|
||||
export type Topology = z.infer<typeof topologySchema>;
|
||||
|
||||
export const bindExportSchema = z.object({
|
||||
zoneName: z.string(),
|
||||
content: z.string(),
|
||||
});
|
||||
export type BindExport = z.infer<typeof bindExportSchema>;
|
||||
|
||||
export const orphanIgnoreSchema = z.object({
|
||||
recordName: z.string().min(1),
|
||||
recordType: z.string().min(1),
|
||||
});
|
||||
@@ -1,2 +1,10 @@
|
||||
export * from "./app-switcher.js";
|
||||
export * from "./settings.js";
|
||||
export * from "./fleet.js";
|
||||
|
||||
export class ValidationError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "ValidationError";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ export type LoginResponse = {
|
||||
|
||||
export const appSettingsPatchSchema = z.object({
|
||||
showQuickActions: z.boolean().optional(),
|
||||
defaultTtl: z.number().int().min(60).max(86400).optional(),
|
||||
namingTemplate: z.string().min(1).optional(),
|
||||
proxiedLock: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type AppSettingsPatch = z.infer<typeof appSettingsPatchSchema>;
|
||||
@@ -32,6 +35,10 @@ export type AppSettingsPatch = z.infer<typeof appSettingsPatchSchema>;
|
||||
export const appSettingsSchema = z.object({
|
||||
id: z.string(),
|
||||
showQuickActions: z.boolean(),
|
||||
defaultTtl: z.number(),
|
||||
namingTemplate: z.string(),
|
||||
proxiedLock: z.boolean(),
|
||||
cloudflareConfigured: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type AppSettings = z.infer<typeof appSettingsSchema>;
|
||||
|
||||
Reference in New Issue
Block a user