From 02fe55b53394b3de4ee904c3085e3537a11b8b82 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sun, 11 Jan 2026 16:24:28 +0100 Subject: [PATCH] fix: properly catch before fallback mount --- app/client/api-client/client/client.gen.ts | 72 ++---- app/client/api-client/index.ts | 217 +++++++++++++++- app/client/api-client/types.gen.ts | 241 ++++-------------- app/schemas/volumes.ts | 2 +- .../modules/backends/nfs/nfs-backend.ts | 11 +- .../modules/backends/smb/smb-backend.ts | 24 +- .../modules/backends/utils/backend-utils.ts | 4 +- .../modules/backends/webdav/webdav-backend.ts | 10 +- 8 files changed, 325 insertions(+), 256 deletions(-) diff --git a/app/client/api-client/client/client.gen.ts b/app/client/api-client/client/client.gen.ts index a8a478dc..cc9b1f4e 100644 --- a/app/client/api-client/client/client.gen.ts +++ b/app/client/api-client/client/client.gen.ts @@ -3,12 +3,7 @@ import { createSseClient } from "../core/serverSentEvents.gen"; import type { HttpMethod } from "../core/types.gen"; import { getValidRequestBody } from "../core/utils.gen"; -import type { - Client, - Config, - RequestOptions, - ResolvedRequestOptions, -} from "./types.gen"; +import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen"; import { buildUrl, createConfig, @@ -34,12 +29,7 @@ export const createClient = (config: Config = {}): Client => { return getConfig(); }; - const interceptors = createInterceptors< - Request, - Response, - unknown, - ResolvedRequestOptions - >(); + const interceptors = createInterceptors(); const beforeRequest = async (options: RequestOptions) => { const opts = { @@ -105,12 +95,7 @@ export const createClient = (config: Config = {}): Client => { for (const fn of interceptors.error.fns) { if (fn) { - finalError = (await fn( - error, - undefined as any, - request, - opts, - )) as unknown; + finalError = (await fn(error, undefined as any, request, opts)) as unknown; } } @@ -143,14 +128,9 @@ export const createClient = (config: Config = {}): Client => { if (response.ok) { const parseAs = - (opts.parseAs === "auto" - ? getParseAs(response.headers.get("Content-Type")) - : opts.parseAs) ?? "json"; + (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"; - if ( - response.status === 204 || - response.headers.get("Content-Length") === "0" - ) { + if (response.status === 204 || response.headers.get("Content-Length") === "0") { let emptyData: any; switch (parseAs) { case "arrayBuffer": @@ -246,30 +226,28 @@ export const createClient = (config: Config = {}): Client => { }; }; - const makeMethodFn = - (method: Uppercase) => (options: RequestOptions) => - request({ ...options, method }); + const makeMethodFn = (method: Uppercase) => (options: RequestOptions) => request({ ...options, method }); - const makeSseFn = - (method: Uppercase) => async (options: RequestOptions) => { - const { opts, url } = await beforeRequest(options); - return createSseClient({ - ...opts, - body: opts.body as BodyInit | null | undefined, - headers: opts.headers as unknown as Record, - method, - onRequest: async (url, init) => { - let request = new Request(url, init); - for (const fn of interceptors.request.fns) { - if (fn) { - request = await fn(request, opts); - } + const makeSseFn = (method: Uppercase) => async (options: RequestOptions) => { + const { opts, url } = await beforeRequest(options); + return createSseClient({ + ...opts, + body: opts.body as BodyInit | null | undefined, + headers: opts.headers as unknown as Record, + method, + onRequest: async (url, init) => { + let request = new Request(url, init); + for (const fn of interceptors.request.fns) { + if (fn) { + request = await fn(request, opts); } - return request; - }, - url, - }); - }; + } + return request; + }, + serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined, + url, + }); + }; return { buildUrl, diff --git a/app/client/api-client/index.ts b/app/client/api-client/index.ts index 7a716924..bee3869e 100644 --- a/app/client/api-client/index.ts +++ b/app/client/api-client/index.ts @@ -1,4 +1,217 @@ // This file is auto-generated by @hey-api/openapi-ts -export type * from "./types.gen"; -export * from "./sdk.gen"; +export { + browseFilesystem, + createBackupSchedule, + createNotificationDestination, + createRepository, + createVolume, + deleteBackupSchedule, + deleteNotificationDestination, + deleteRepository, + deleteSnapshot, + deleteSnapshots, + deleteVolume, + doctorRepository, + downloadResticPassword, + getBackupSchedule, + getBackupScheduleForVolume, + getMirrorCompatibility, + getNotificationDestination, + getRepository, + getScheduleMirrors, + getScheduleNotifications, + getSnapshotDetails, + getStatus, + getSystemInfo, + getUpdates, + getVolume, + healthCheckVolume, + listBackupSchedules, + listFiles, + listNotificationDestinations, + listRcloneRemotes, + listRepositories, + listSnapshotFiles, + listSnapshots, + listVolumes, + mountVolume, + type Options, + reorderBackupSchedules, + restoreSnapshot, + runBackupNow, + runForget, + stopBackup, + tagSnapshots, + testConnection, + testNotificationDestination, + unmountVolume, + updateBackupSchedule, + updateNotificationDestination, + updateRepository, + updateScheduleMirrors, + updateScheduleNotifications, + updateVolume, +} from "./sdk.gen"; +export type { + BrowseFilesystemData, + BrowseFilesystemResponse, + BrowseFilesystemResponses, + ClientOptions, + CreateBackupScheduleData, + CreateBackupScheduleResponse, + CreateBackupScheduleResponses, + CreateNotificationDestinationData, + CreateNotificationDestinationResponse, + CreateNotificationDestinationResponses, + CreateRepositoryData, + CreateRepositoryResponse, + CreateRepositoryResponses, + CreateVolumeData, + CreateVolumeResponse, + CreateVolumeResponses, + DeleteBackupScheduleData, + DeleteBackupScheduleResponse, + DeleteBackupScheduleResponses, + DeleteNotificationDestinationData, + DeleteNotificationDestinationErrors, + DeleteNotificationDestinationResponse, + DeleteNotificationDestinationResponses, + DeleteRepositoryData, + DeleteRepositoryResponse, + DeleteRepositoryResponses, + DeleteSnapshotData, + DeleteSnapshotResponse, + DeleteSnapshotResponses, + DeleteSnapshotsData, + DeleteSnapshotsResponse, + DeleteSnapshotsResponses, + DeleteVolumeData, + DeleteVolumeResponse, + DeleteVolumeResponses, + DoctorRepositoryData, + DoctorRepositoryResponse, + DoctorRepositoryResponses, + DownloadResticPasswordData, + DownloadResticPasswordResponse, + DownloadResticPasswordResponses, + GetBackupScheduleData, + GetBackupScheduleForVolumeData, + GetBackupScheduleForVolumeResponse, + GetBackupScheduleForVolumeResponses, + GetBackupScheduleResponse, + GetBackupScheduleResponses, + GetMirrorCompatibilityData, + GetMirrorCompatibilityResponse, + GetMirrorCompatibilityResponses, + GetNotificationDestinationData, + GetNotificationDestinationErrors, + GetNotificationDestinationResponse, + GetNotificationDestinationResponses, + GetRepositoryData, + GetRepositoryResponse, + GetRepositoryResponses, + GetScheduleMirrorsData, + GetScheduleMirrorsResponse, + GetScheduleMirrorsResponses, + GetScheduleNotificationsData, + GetScheduleNotificationsResponse, + GetScheduleNotificationsResponses, + GetSnapshotDetailsData, + GetSnapshotDetailsResponse, + GetSnapshotDetailsResponses, + GetStatusData, + GetStatusResponse, + GetStatusResponses, + GetSystemInfoData, + GetSystemInfoResponse, + GetSystemInfoResponses, + GetUpdatesData, + GetUpdatesResponse, + GetUpdatesResponses, + GetVolumeData, + GetVolumeErrors, + GetVolumeResponse, + GetVolumeResponses, + HealthCheckVolumeData, + HealthCheckVolumeErrors, + HealthCheckVolumeResponse, + HealthCheckVolumeResponses, + ListBackupSchedulesData, + ListBackupSchedulesResponse, + ListBackupSchedulesResponses, + ListFilesData, + ListFilesResponse, + ListFilesResponses, + ListNotificationDestinationsData, + ListNotificationDestinationsResponse, + ListNotificationDestinationsResponses, + ListRcloneRemotesData, + ListRcloneRemotesResponse, + ListRcloneRemotesResponses, + ListRepositoriesData, + ListRepositoriesResponse, + ListRepositoriesResponses, + ListSnapshotFilesData, + ListSnapshotFilesResponse, + ListSnapshotFilesResponses, + ListSnapshotsData, + ListSnapshotsResponse, + ListSnapshotsResponses, + ListVolumesData, + ListVolumesResponse, + ListVolumesResponses, + MountVolumeData, + MountVolumeResponse, + MountVolumeResponses, + ReorderBackupSchedulesData, + ReorderBackupSchedulesResponse, + ReorderBackupSchedulesResponses, + RestoreSnapshotData, + RestoreSnapshotResponse, + RestoreSnapshotResponses, + RunBackupNowData, + RunBackupNowResponse, + RunBackupNowResponses, + RunForgetData, + RunForgetResponse, + RunForgetResponses, + StopBackupData, + StopBackupErrors, + StopBackupResponse, + StopBackupResponses, + TagSnapshotsData, + TagSnapshotsResponse, + TagSnapshotsResponses, + TestConnectionData, + TestConnectionResponse, + TestConnectionResponses, + TestNotificationDestinationData, + TestNotificationDestinationErrors, + TestNotificationDestinationResponse, + TestNotificationDestinationResponses, + UnmountVolumeData, + UnmountVolumeResponse, + UnmountVolumeResponses, + UpdateBackupScheduleData, + UpdateBackupScheduleResponse, + UpdateBackupScheduleResponses, + UpdateNotificationDestinationData, + UpdateNotificationDestinationErrors, + UpdateNotificationDestinationResponse, + UpdateNotificationDestinationResponses, + UpdateRepositoryData, + UpdateRepositoryErrors, + UpdateRepositoryResponse, + UpdateRepositoryResponses, + UpdateScheduleMirrorsData, + UpdateScheduleMirrorsResponse, + UpdateScheduleMirrorsResponses, + UpdateScheduleNotificationsData, + UpdateScheduleNotificationsResponse, + UpdateScheduleNotificationsResponses, + UpdateVolumeData, + UpdateVolumeErrors, + UpdateVolumeResponse, + UpdateVolumeResponses, +} from "./types.gen"; diff --git a/app/client/api-client/types.gen.ts b/app/client/api-client/types.gen.ts index 7230304f..3cab252d 100644 --- a/app/client/api-client/types.gen.ts +++ b/app/client/api-client/types.gen.ts @@ -73,7 +73,7 @@ export type ListVolumesResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -100,8 +100,7 @@ export type ListVolumesResponses = { }>; }; -export type ListVolumesResponse = - ListVolumesResponses[keyof ListVolumesResponses]; +export type ListVolumesResponse = ListVolumesResponses[keyof ListVolumesResponses]; export type CreateVolumeData = { body?: { @@ -143,7 +142,7 @@ export type CreateVolumeData = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -209,7 +208,7 @@ export type CreateVolumeResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -236,8 +235,7 @@ export type CreateVolumeResponses = { }; }; -export type CreateVolumeResponse = - CreateVolumeResponses[keyof CreateVolumeResponses]; +export type CreateVolumeResponse = CreateVolumeResponses[keyof CreateVolumeResponses]; export type TestConnectionData = { body?: { @@ -279,7 +277,7 @@ export type TestConnectionData = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -310,8 +308,7 @@ export type TestConnectionResponses = { }; }; -export type TestConnectionResponse = - TestConnectionResponses[keyof TestConnectionResponses]; +export type TestConnectionResponse = TestConnectionResponses[keyof TestConnectionResponses]; export type DeleteVolumeData = { body?: never; @@ -331,8 +328,7 @@ export type DeleteVolumeResponses = { }; }; -export type DeleteVolumeResponse = - DeleteVolumeResponses[keyof DeleteVolumeResponses]; +export type DeleteVolumeResponse = DeleteVolumeResponses[keyof DeleteVolumeResponses]; export type GetVolumeData = { body?: never; @@ -400,7 +396,7 @@ export type GetVolumeResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -471,7 +467,7 @@ export type UpdateVolumeData = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -546,7 +542,7 @@ export type UpdateVolumeResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -573,8 +569,7 @@ export type UpdateVolumeResponses = { }; }; -export type UpdateVolumeResponse = - UpdateVolumeResponses[keyof UpdateVolumeResponses]; +export type UpdateVolumeResponse = UpdateVolumeResponses[keyof UpdateVolumeResponses]; export type MountVolumeData = { body?: never; @@ -595,8 +590,7 @@ export type MountVolumeResponses = { }; }; -export type MountVolumeResponse = - MountVolumeResponses[keyof MountVolumeResponses]; +export type MountVolumeResponse = MountVolumeResponses[keyof MountVolumeResponses]; export type UnmountVolumeData = { body?: never; @@ -617,8 +611,7 @@ export type UnmountVolumeResponses = { }; }; -export type UnmountVolumeResponse = - UnmountVolumeResponses[keyof UnmountVolumeResponses]; +export type UnmountVolumeResponse = UnmountVolumeResponses[keyof UnmountVolumeResponses]; export type HealthCheckVolumeData = { body?: never; @@ -646,8 +639,7 @@ export type HealthCheckVolumeResponses = { }; }; -export type HealthCheckVolumeResponse = - HealthCheckVolumeResponses[keyof HealthCheckVolumeResponses]; +export type HealthCheckVolumeResponse = HealthCheckVolumeResponses[keyof HealthCheckVolumeResponses]; export type ListFilesData = { body?: never; @@ -709,8 +701,7 @@ export type BrowseFilesystemResponses = { }; }; -export type BrowseFilesystemResponse = - BrowseFilesystemResponses[keyof BrowseFilesystemResponses]; +export type BrowseFilesystemResponse = BrowseFilesystemResponses[keyof BrowseFilesystemResponses]; export type ListRepositoriesData = { body?: never; @@ -824,8 +815,7 @@ export type ListRepositoriesResponses = { }>; }; -export type ListRepositoriesResponse = - ListRepositoriesResponses[keyof ListRepositoriesResponses]; +export type ListRepositoriesResponse = ListRepositoriesResponses[keyof ListRepositoriesResponses]; export type CreateRepositoryData = { body?: { @@ -938,8 +928,7 @@ export type CreateRepositoryResponses = { }; }; -export type CreateRepositoryResponse = - CreateRepositoryResponses[keyof CreateRepositoryResponses]; +export type CreateRepositoryResponse = CreateRepositoryResponses[keyof CreateRepositoryResponses]; export type ListRcloneRemotesData = { body?: never; @@ -958,8 +947,7 @@ export type ListRcloneRemotesResponses = { }>; }; -export type ListRcloneRemotesResponse = - ListRcloneRemotesResponses[keyof ListRcloneRemotesResponses]; +export type ListRcloneRemotesResponse = ListRcloneRemotesResponses[keyof ListRcloneRemotesResponses]; export type DeleteRepositoryData = { body?: never; @@ -979,8 +967,7 @@ export type DeleteRepositoryResponses = { }; }; -export type DeleteRepositoryResponse = - DeleteRepositoryResponses[keyof DeleteRepositoryResponses]; +export type DeleteRepositoryResponse = DeleteRepositoryResponses[keyof DeleteRepositoryResponses]; export type GetRepositoryData = { body?: never; @@ -1096,8 +1083,7 @@ export type GetRepositoryResponses = { }; }; -export type GetRepositoryResponse = - GetRepositoryResponses[keyof GetRepositoryResponses]; +export type GetRepositoryResponse = GetRepositoryResponses[keyof GetRepositoryResponses]; export type UpdateRepositoryData = { body?: { @@ -1227,8 +1213,7 @@ export type UpdateRepositoryResponses = { }; }; -export type UpdateRepositoryResponse = - UpdateRepositoryResponses[keyof UpdateRepositoryResponses]; +export type UpdateRepositoryResponse = UpdateRepositoryResponses[keyof UpdateRepositoryResponses]; export type DeleteSnapshotsData = { body?: { @@ -1250,8 +1235,7 @@ export type DeleteSnapshotsResponses = { }; }; -export type DeleteSnapshotsResponse = - DeleteSnapshotsResponses[keyof DeleteSnapshotsResponses]; +export type DeleteSnapshotsResponse = DeleteSnapshotsResponses[keyof DeleteSnapshotsResponses]; export type ListSnapshotsData = { body?: never; @@ -1278,8 +1262,7 @@ export type ListSnapshotsResponses = { }>; }; -export type ListSnapshotsResponse = - ListSnapshotsResponses[keyof ListSnapshotsResponses]; +export type ListSnapshotsResponse = ListSnapshotsResponses[keyof ListSnapshotsResponses]; export type DeleteSnapshotData = { body?: never; @@ -1300,8 +1283,7 @@ export type DeleteSnapshotResponses = { }; }; -export type DeleteSnapshotResponse = - DeleteSnapshotResponses[keyof DeleteSnapshotResponses]; +export type DeleteSnapshotResponse = DeleteSnapshotResponses[keyof DeleteSnapshotResponses]; export type GetSnapshotDetailsData = { body?: never; @@ -1327,8 +1309,7 @@ export type GetSnapshotDetailsResponses = { }; }; -export type GetSnapshotDetailsResponse = - GetSnapshotDetailsResponses[keyof GetSnapshotDetailsResponses]; +export type GetSnapshotDetailsResponse = GetSnapshotDetailsResponses[keyof GetSnapshotDetailsResponses]; export type ListSnapshotFilesData = { body?: never; @@ -1369,8 +1350,7 @@ export type ListSnapshotFilesResponses = { }; }; -export type ListSnapshotFilesResponse = - ListSnapshotFilesResponses[keyof ListSnapshotFilesResponses]; +export type ListSnapshotFilesResponse = ListSnapshotFilesResponses[keyof ListSnapshotFilesResponses]; export type RestoreSnapshotData = { body?: { @@ -1401,8 +1381,7 @@ export type RestoreSnapshotResponses = { }; }; -export type RestoreSnapshotResponse = - RestoreSnapshotResponses[keyof RestoreSnapshotResponses]; +export type RestoreSnapshotResponse = RestoreSnapshotResponses[keyof RestoreSnapshotResponses]; export type DoctorRepositoryData = { body?: never; @@ -1428,8 +1407,7 @@ export type DoctorRepositoryResponses = { }; }; -export type DoctorRepositoryResponse = - DoctorRepositoryResponses[keyof DoctorRepositoryResponses]; +export type DoctorRepositoryResponse = DoctorRepositoryResponses[keyof DoctorRepositoryResponses]; export type TagSnapshotsData = { body?: { @@ -1454,8 +1432,7 @@ export type TagSnapshotsResponses = { }; }; -export type TagSnapshotsResponse = - TagSnapshotsResponses[keyof TagSnapshotsResponses]; +export type TagSnapshotsResponse = TagSnapshotsResponses[keyof TagSnapshotsResponses]; export type ListBackupSchedulesData = { body?: never; @@ -1578,15 +1555,7 @@ export type ListBackupSchedulesResponses = { name: string; shortId: string; status: "error" | "healthy" | "unknown" | null; - type: - | "azure" - | "gcs" - | "local" - | "r2" - | "rclone" - | "rest" - | "s3" - | "sftp"; + type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; updatedAt: number; }; repositoryId: string; @@ -1641,7 +1610,7 @@ export type ListBackupSchedulesResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -1670,8 +1639,7 @@ export type ListBackupSchedulesResponses = { }>; }; -export type ListBackupSchedulesResponse = - ListBackupSchedulesResponses[keyof ListBackupSchedulesResponses]; +export type ListBackupSchedulesResponse = ListBackupSchedulesResponses[keyof ListBackupSchedulesResponses]; export type CreateBackupScheduleData = { body?: { @@ -1734,8 +1702,7 @@ export type CreateBackupScheduleResponses = { }; }; -export type CreateBackupScheduleResponse = - CreateBackupScheduleResponses[keyof CreateBackupScheduleResponses]; +export type CreateBackupScheduleResponse = CreateBackupScheduleResponses[keyof CreateBackupScheduleResponses]; export type DeleteBackupScheduleData = { body?: never; @@ -1755,8 +1722,7 @@ export type DeleteBackupScheduleResponses = { }; }; -export type DeleteBackupScheduleResponse = - DeleteBackupScheduleResponses[keyof DeleteBackupScheduleResponses]; +export type DeleteBackupScheduleResponse = DeleteBackupScheduleResponses[keyof DeleteBackupScheduleResponses]; export type GetBackupScheduleData = { body?: never; @@ -1881,15 +1847,7 @@ export type GetBackupScheduleResponses = { name: string; shortId: string; status: "error" | "healthy" | "unknown" | null; - type: - | "azure" - | "gcs" - | "local" - | "r2" - | "rclone" - | "rest" - | "s3" - | "sftp"; + type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; updatedAt: number; }; repositoryId: string; @@ -1944,7 +1902,7 @@ export type GetBackupScheduleResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -1973,8 +1931,7 @@ export type GetBackupScheduleResponses = { }; }; -export type GetBackupScheduleResponse = - GetBackupScheduleResponses[keyof GetBackupScheduleResponses]; +export type GetBackupScheduleResponse = GetBackupScheduleResponses[keyof GetBackupScheduleResponses]; export type UpdateBackupScheduleData = { body?: { @@ -2038,8 +1995,7 @@ export type UpdateBackupScheduleResponses = { }; }; -export type UpdateBackupScheduleResponse = - UpdateBackupScheduleResponses[keyof UpdateBackupScheduleResponses]; +export type UpdateBackupScheduleResponse = UpdateBackupScheduleResponses[keyof UpdateBackupScheduleResponses]; export type GetBackupScheduleForVolumeData = { body?: never; @@ -2164,15 +2120,7 @@ export type GetBackupScheduleForVolumeResponses = { name: string; shortId: string; status: "error" | "healthy" | "unknown" | null; - type: - | "azure" - | "gcs" - | "local" - | "r2" - | "rclone" - | "rest" - | "s3" - | "sftp"; + type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; updatedAt: number; }; repositoryId: string; @@ -2227,7 +2175,7 @@ export type GetBackupScheduleForVolumeResponses = { server: string; share: string; username: string; - vers?: "1.0" | "2.0" | "2.1" | "3.0"; + vers?: "1.0" | "2.0" | "2.1" | "3.0" | "auto"; port?: number; domain?: string; readOnly?: boolean; @@ -2277,8 +2225,7 @@ export type RunBackupNowResponses = { }; }; -export type RunBackupNowResponse = - RunBackupNowResponses[keyof RunBackupNowResponses]; +export type RunBackupNowResponse = RunBackupNowResponses[keyof RunBackupNowResponses]; export type StopBackupData = { body?: never; @@ -2414,16 +2361,7 @@ export type GetScheduleNotificationsResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }; destinationId: number; @@ -2533,16 +2471,7 @@ export type UpdateScheduleNotificationsResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }; destinationId: number; @@ -2672,15 +2601,7 @@ export type GetScheduleMirrorsResponses = { name: string; shortId: string; status: "error" | "healthy" | "unknown" | null; - type: - | "azure" - | "gcs" - | "local" - | "r2" - | "rclone" - | "rest" - | "s3" - | "sftp"; + type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; updatedAt: number; }; repositoryId: string; @@ -2688,8 +2609,7 @@ export type GetScheduleMirrorsResponses = { }>; }; -export type GetScheduleMirrorsResponse = - GetScheduleMirrorsResponses[keyof GetScheduleMirrorsResponses]; +export type GetScheduleMirrorsResponse = GetScheduleMirrorsResponses[keyof GetScheduleMirrorsResponses]; export type UpdateScheduleMirrorsData = { body?: { @@ -2811,15 +2731,7 @@ export type UpdateScheduleMirrorsResponses = { name: string; shortId: string; status: "error" | "healthy" | "unknown" | null; - type: - | "azure" - | "gcs" - | "local" - | "r2" - | "rclone" - | "rest" - | "s3" - | "sftp"; + type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; updatedAt: number; }; repositoryId: string; @@ -2827,8 +2739,7 @@ export type UpdateScheduleMirrorsResponses = { }>; }; -export type UpdateScheduleMirrorsResponse = - UpdateScheduleMirrorsResponses[keyof UpdateScheduleMirrorsResponses]; +export type UpdateScheduleMirrorsResponse = UpdateScheduleMirrorsResponses[keyof UpdateScheduleMirrorsResponses]; export type GetMirrorCompatibilityData = { body?: never; @@ -2850,8 +2761,7 @@ export type GetMirrorCompatibilityResponses = { }>; }; -export type GetMirrorCompatibilityResponse = - GetMirrorCompatibilityResponses[keyof GetMirrorCompatibilityResponses]; +export type GetMirrorCompatibilityResponse = GetMirrorCompatibilityResponses[keyof GetMirrorCompatibilityResponses]; export type ReorderBackupSchedulesData = { body?: { @@ -2871,8 +2781,7 @@ export type ReorderBackupSchedulesResponses = { }; }; -export type ReorderBackupSchedulesResponse = - ReorderBackupSchedulesResponses[keyof ReorderBackupSchedulesResponses]; +export type ReorderBackupSchedulesResponse = ReorderBackupSchedulesResponses[keyof ReorderBackupSchedulesResponses]; export type ListNotificationDestinationsData = { body?: never; @@ -2957,16 +2866,7 @@ export type ListNotificationDestinationsResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }>; }; @@ -3126,16 +3026,7 @@ export type CreateNotificationDestinationResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }; }; @@ -3263,16 +3154,7 @@ export type GetNotificationDestinationResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }; }; @@ -3442,16 +3324,7 @@ export type UpdateNotificationDestinationResponses = { enabled: boolean; id: number; name: string; - type: - | "custom" - | "discord" - | "email" - | "generic" - | "gotify" - | "ntfy" - | "pushover" - | "slack" - | "telegram"; + type: "custom" | "discord" | "email" | "generic" | "gotify" | "ntfy" | "pushover" | "slack" | "telegram"; updatedAt: number; }; }; @@ -3514,8 +3387,7 @@ export type GetSystemInfoResponses = { }; }; -export type GetSystemInfoResponse = - GetSystemInfoResponses[keyof GetSystemInfoResponses]; +export type GetSystemInfoResponse = GetSystemInfoResponses[keyof GetSystemInfoResponses]; export type GetUpdatesData = { body?: never; @@ -3559,5 +3431,4 @@ export type DownloadResticPasswordResponses = { 200: string; }; -export type DownloadResticPasswordResponse = - DownloadResticPasswordResponses[keyof DownloadResticPasswordResponses]; +export type DownloadResticPasswordResponse = DownloadResticPasswordResponses[keyof DownloadResticPasswordResponses]; diff --git a/app/schemas/volumes.ts b/app/schemas/volumes.ts index 5589935a..5fab2c51 100644 --- a/app/schemas/volumes.ts +++ b/app/schemas/volumes.ts @@ -26,7 +26,7 @@ export const smbConfigSchema = type({ share: "string", username: "string", password: "string", - vers: type("'1.0' | '2.0' | '2.1' | '3.0'").default("3.0"), + vers: type("'1.0' | '2.0' | '2.1' | '3.0' | 'auto'").default("auto"), domain: "string?", port: type("string.integer").or(type("number")).to("1 <= number <= 65535").default(445), readOnly: "boolean?", diff --git a/app/server/modules/backends/nfs/nfs-backend.ts b/app/server/modules/backends/nfs/nfs-backend.ts index 876c18b0..d41d2cfb 100644 --- a/app/server/modules/backends/nfs/nfs-backend.ts +++ b/app/server/modules/backends/nfs/nfs-backend.ts @@ -54,10 +54,13 @@ const mount = async (config: BackendConfig, path: string) => { logger.debug(`Mounting volume ${path}...`); logger.info(`Executing mount: mount ${args.join(" ")}`); - await executeMount(args); - - // Fallback with -i flag if the first mount fails using the mount helper - await executeMount(["-i", ...args]); + try { + await executeMount(args); + } catch (error) { + logger.warn(`Initial NFS mount failed, retrying with -i flag: ${toMessage(error)}`); + // Fallback with -i flag if the first mount fails using the mount helper + await executeMount(["-i", ...args]); + } logger.info(`NFS volume at ${path} mounted successfully.`); return { status: BACKEND_STATUS.mounted }; diff --git a/app/server/modules/backends/smb/smb-backend.ts b/app/server/modules/backends/smb/smb-backend.ts index 39d97a29..2f76ff3f 100644 --- a/app/server/modules/backends/smb/smb-backend.ts +++ b/app/server/modules/backends/smb/smb-backend.ts @@ -40,14 +40,11 @@ const mount = async (config: BackendConfig, path: string) => { const source = `//${config.server}/${config.share}`; const { uid, gid } = os.userInfo(); - const options = [ - `user=${config.username}`, - `pass=${password}`, - `vers=${config.vers}`, - `port=${config.port}`, - `uid=${uid}`, - `gid=${gid}`, - ]; + const options = [`user=${config.username}`, `pass=${password}`, `port=${config.port}`, `uid=${uid}`, `gid=${gid}`]; + + if (config.vers && config.vers !== "auto") { + options.push(`vers=${config.vers}`); + } if (config.domain) { options.push(`domain=${config.domain}`); @@ -62,10 +59,13 @@ const mount = async (config: BackendConfig, path: string) => { logger.debug(`Mounting SMB volume ${path}...`); logger.info(`Executing mount: mount ${args.join(" ")}`); - await executeMount(args); - - // Fallback with -i flag if the first mount fails using the mount helper - await executeMount(["-i", ...args]); + try { + await executeMount(args); + } catch (error) { + logger.warn(`Initial SMB mount failed, retrying with -i flag: ${toMessage(error)}`); + // Fallback with -i flag if the first mount fails using the mount helper + await executeMount(["-i", ...args]); + } logger.info(`SMB volume at ${path} mounted successfully.`); return { status: BACKEND_STATUS.mounted }; diff --git a/app/server/modules/backends/utils/backend-utils.ts b/app/server/modules/backends/utils/backend-utils.ts index 20153e59..044f4a7e 100644 --- a/app/server/modules/backends/utils/backend-utils.ts +++ b/app/server/modules/backends/utils/backend-utils.ts @@ -7,10 +7,10 @@ import { logger } from "../../../utils/logger"; export const executeMount = async (args: string[]): Promise => { const shouldBeVerbose = process.env.LOG_LEVEL === "debug" || process.env.NODE_ENV !== "production"; const hasVerboseFlag = args.some((arg) => arg === "-v" || arg.startsWith("-vv")); - const effectiveArgs = shouldBeVerbose && !hasVerboseFlag ? ["-vvv", ...args] : args; + const effectiveArgs = shouldBeVerbose && !hasVerboseFlag ? ["-v", ...args] : args; logger.debug(`Executing mount ${effectiveArgs.join(" ")}`); - const result = await $`mount ${effectiveArgs}`.nothrow(); + let result = await $`mount ${effectiveArgs}`.nothrow(); const stdout = result.stdout.toString().trim(); const stderr = result.stderr.toString().trim(); diff --git a/app/server/modules/backends/webdav/webdav-backend.ts b/app/server/modules/backends/webdav/webdav-backend.ts index 864da6ca..345a200b 100644 --- a/app/server/modules/backends/webdav/webdav-backend.ts +++ b/app/server/modules/backends/webdav/webdav-backend.ts @@ -58,10 +58,14 @@ const mount = async (config: BackendConfig, path: string) => { logger.debug(`Mounting WebDAV volume ${path}...`); const args = ["-t", "davfs", "-o", options.join(","), source, path]; - await executeMount(args); - // Fallback with -i flag if the first mount fails using the mount helper - await executeMount(["-i", ...args]); + try { + await executeMount(args); + } catch (error) { + logger.warn(`Initial WebDAV mount failed, retrying with -i flag: ${toMessage(error)}`); + // Fallback with -i flag if the first mount fails using the mount helper + await executeMount(["-i", ...args]); + } logger.info(`WebDAV volume at ${path} mounted successfully.`); return { status: BACKEND_STATUS.mounted };