zerobyte/app/schemas/restic.ts
Nico 2ab37e6b67
refactor: async doctor (#375)
* feat: background doctor operation

* refactor(repo-details): design layout

* refactor(doctor): support abort signal in all operations

* chore: fix linting issue

* chore: pr feedbacks

* chore: merge conflicts

* refactor: handle aborted signal in all operations

* chore: pr feedbacks

* chore: remove old migration
2026-01-22 21:55:45 +01:00

160 lines
3.9 KiB
TypeScript

import { type } from "arktype";
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;
export const bandwidthLimitSchema = type({
enabled: "boolean = false",
value: "number > 0 = 1",
unit: type.valueOf(BANDWIDTH_UNITS).default("Mbps"),
});
export type BandwidthLimit = typeof bandwidthLimitSchema.infer;
// Common fields for all repository configs
const baseRepositoryConfigSchema = type({
isExistingRepository: "boolean?",
customPassword: "string?",
cacert: "string?",
insecureTls: "boolean?",
// Bandwidth controls
uploadLimit: bandwidthLimitSchema.optional(),
downloadLimit: bandwidthLimitSchema.optional(),
});
export const s3RepositoryConfigSchema = type({
backend: "'s3'",
endpoint: "string",
bucket: "string",
accessKeyId: "string",
secretAccessKey: "string",
}).and(baseRepositoryConfigSchema);
export const r2RepositoryConfigSchema = type({
backend: "'r2'",
endpoint: "string",
bucket: "string",
accessKeyId: "string",
secretAccessKey: "string",
}).and(baseRepositoryConfigSchema);
export const localRepositoryConfigSchema = type({
backend: "'local'",
name: "string",
path: "string?",
}).and(baseRepositoryConfigSchema);
export const gcsRepositoryConfigSchema = type({
backend: "'gcs'",
bucket: "string",
projectId: "string",
credentialsJson: "string",
}).and(baseRepositoryConfigSchema);
export const azureRepositoryConfigSchema = type({
backend: "'azure'",
container: "string",
accountName: "string",
accountKey: "string",
endpointSuffix: "string?",
}).and(baseRepositoryConfigSchema);
export const rcloneRepositoryConfigSchema = type({
backend: "'rclone'",
remote: "string",
path: "string",
}).and(baseRepositoryConfigSchema);
export const restRepositoryConfigSchema = type({
backend: "'rest'",
url: "string",
username: "string?",
password: "string?",
path: "string?",
}).and(baseRepositoryConfigSchema);
export const sftpRepositoryConfigSchema = type({
backend: "'sftp'",
host: "string",
port: type("string.integer").or(type("number")).to("1 <= number <= 65535").default(22),
user: "string",
path: "string",
privateKey: "string",
skipHostKeyCheck: "boolean = true",
knownHosts: "string?",
}).and(baseRepositoryConfigSchema);
export const repositoryConfigSchemaBase = s3RepositoryConfigSchema
.or(r2RepositoryConfigSchema)
.or(localRepositoryConfigSchema)
.or(gcsRepositoryConfigSchema)
.or(azureRepositoryConfigSchema)
.or(rcloneRepositoryConfigSchema)
.or(restRepositoryConfigSchema)
.or(sftpRepositoryConfigSchema);
export const repositoryConfigSchema = repositoryConfigSchemaBase.onUndeclaredKey("delete");
export type RepositoryConfig = typeof repositoryConfigSchema.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 = type({
step: "string",
success: "boolean",
output: "string | null",
error: "string | null",
});
export type DoctorStep = typeof doctorStepSchema.infer;
export const doctorResultSchema = type({
success: "boolean",
steps: doctorStepSchema.array(),
completedAt: "number",
});
export type DoctorResult = typeof doctorResultSchema.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];