import { z } from "zod"; export const REPOSITORY_BACKENDS = { local: "local", s3: "s3", r2: "r2", gcs: "gcs", azure: "azure", rclone: "rclone", rest: "rest", sftp: "sftp", } as const; export type RepositoryBackend = keyof typeof REPOSITORY_BACKENDS; export const BANDWIDTH_UNITS = { Kbps: "Kbps", Mbps: "Mbps", Gbps: "Gbps", } as const; export type BandwidthUnit = keyof typeof BANDWIDTH_UNITS; const bandwidthUnitSchema = z.enum(["Kbps", "Mbps", "Gbps"]); export const bandwidthLimitSchema = z.object({ enabled: z.boolean().default(false), value: z.number().positive().default(1), unit: bandwidthUnitSchema.default("Mbps"), }); export type BandwidthLimit = z.infer; const baseRepositoryConfigSchema = z.object({ isExistingRepository: z.boolean().optional(), customPassword: z.string().optional(), cacert: z.string().optional(), insecureTls: z.boolean().optional(), uploadLimit: bandwidthLimitSchema.optional(), downloadLimit: bandwidthLimitSchema.optional(), }); export const s3RepositoryConfigSchema = z .object({ backend: z.literal("s3"), endpoint: z.string().min(1), bucket: z.string().min(1), accessKeyId: z.string().min(1), secretAccessKey: z.string().min(1), }) .extend(baseRepositoryConfigSchema.shape); export const r2RepositoryConfigSchema = z .object({ backend: z.literal("r2"), endpoint: z.string().min(1), bucket: z.string().min(1), accessKeyId: z.string().min(1), secretAccessKey: z.string().min(1), }) .extend(baseRepositoryConfigSchema.shape); export const localRepositoryConfigSchema = z .object({ backend: z.literal("local"), path: z.string().min(1), }) .extend(baseRepositoryConfigSchema.shape); export const gcsRepositoryConfigSchema = z .object({ backend: z.literal("gcs"), bucket: z.string().min(1), projectId: z.string().min(1), credentialsJson: z.string().min(1), }) .extend(baseRepositoryConfigSchema.shape); export const azureRepositoryConfigSchema = z .object({ backend: z.literal("azure"), container: z.string().min(1), accountName: z.string().min(1), accountKey: z.string().min(1), endpointSuffix: z.string().optional(), }) .extend(baseRepositoryConfigSchema.shape); export const rcloneRepositoryConfigSchema = z .object({ backend: z.literal("rclone"), remote: z.string().min(1), path: z.string().min(1), }) .extend(baseRepositoryConfigSchema.shape); export const restRepositoryConfigSchema = z .object({ backend: z.literal("rest"), url: z.string().min(1), username: z.string().optional(), password: z.string().optional(), path: z.string().optional(), }) .extend(baseRepositoryConfigSchema.shape); export const sftpRepositoryConfigSchema = z .object({ backend: z.literal("sftp"), host: z.string().min(1), port: z .union([z.string(), z.number()]) .transform((value) => (typeof value === "string" ? Number.parseInt(value, 10) : value)) .pipe(z.number().int().min(1).max(65535)) .default(22), user: z.string().min(1), path: z.string().min(1), privateKey: z.string().min(1), skipHostKeyCheck: z.boolean().default(true), knownHosts: z.string().optional(), }) .extend(baseRepositoryConfigSchema.shape); export const repositoryConfigSchemaBase = z.discriminatedUnion("backend", [ s3RepositoryConfigSchema, r2RepositoryConfigSchema, localRepositoryConfigSchema, gcsRepositoryConfigSchema, azureRepositoryConfigSchema, rcloneRepositoryConfigSchema, restRepositoryConfigSchema, sftpRepositoryConfigSchema, ]); export const repositoryConfigSchema = repositoryConfigSchemaBase; export type RepositoryConfig = z.infer; export const COMPRESSION_MODES = { off: "off", auto: "auto", max: "max", } as const; export type CompressionMode = keyof typeof COMPRESSION_MODES; export const REPOSITORY_STATUS = { healthy: "healthy", error: "error", unknown: "unknown", doctor: "doctor", cancelled: "cancelled", } as const; export type RepositoryStatus = keyof typeof REPOSITORY_STATUS; export const doctorStepSchema = z.object({ step: z.string(), success: z.boolean(), output: z.string().nullable(), error: z.string().nullable(), }); export type DoctorStep = z.infer; export const doctorResultSchema = z.object({ success: z.boolean(), steps: doctorStepSchema.array(), completedAt: z.number(), }); export type DoctorResult = z.infer; export const OVERWRITE_MODES = { always: "always", ifChanged: "if-changed", ifNewer: "if-newer", never: "never", } as const; export type OverwriteMode = (typeof OVERWRITE_MODES)[keyof typeof OVERWRITE_MODES];