chore: merge conflicts

This commit is contained in:
Nicolas Meienberger 2026-01-22 21:42:31 +01:00
parent dc77cf6318
commit 25b1bf0479
10 changed files with 1682 additions and 17 deletions

View file

@ -47,6 +47,7 @@ import {
runBackupNow, runBackupNow,
runForget, runForget,
setRegistrationStatus, setRegistrationStatus,
startDoctor,
stopBackup, stopBackup,
tagSnapshots, tagSnapshots,
testConnection, testConnection,
@ -144,6 +145,8 @@ import type {
RunForgetResponse, RunForgetResponse,
SetRegistrationStatusData, SetRegistrationStatusData,
SetRegistrationStatusResponse, SetRegistrationStatusResponse,
StartDoctorData,
StartDoctorResponse,
StopBackupData, StopBackupData,
StopBackupResponse, StopBackupResponse,
TagSnapshotsData, TagSnapshotsData,

View file

@ -44,6 +44,7 @@ export {
runBackupNow, runBackupNow,
runForget, runForget,
setRegistrationStatus, setRegistrationStatus,
startDoctor,
stopBackup, stopBackup,
tagSnapshots, tagSnapshots,
testConnection, testConnection,
@ -189,6 +190,10 @@ export type {
SetRegistrationStatusData, SetRegistrationStatusData,
SetRegistrationStatusResponse, SetRegistrationStatusResponse,
SetRegistrationStatusResponses, SetRegistrationStatusResponses,
StartDoctorData,
StartDoctorErrors,
StartDoctorResponse,
StartDoctorResponses,
StopBackupData, StopBackupData,
StopBackupErrors, StopBackupErrors,
StopBackupResponse, StopBackupResponse,

View file

@ -92,6 +92,9 @@ import type {
RunForgetResponses, RunForgetResponses,
SetRegistrationStatusData, SetRegistrationStatusData,
SetRegistrationStatusResponses, SetRegistrationStatusResponses,
StartDoctorData,
StartDoctorErrors,
StartDoctorResponses,
StopBackupData, StopBackupData,
StopBackupErrors, StopBackupErrors,
StopBackupResponses, StopBackupResponses,

View file

@ -927,7 +927,7 @@ export type ListRepositoriesResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}>; }>;
@ -1365,7 +1365,7 @@ export type GetRepositoryResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -1585,7 +1585,7 @@ export type UpdateRepositoryResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -2051,7 +2051,7 @@ export type ListBackupSchedulesResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -2433,7 +2433,7 @@ export type GetBackupScheduleResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -2796,7 +2796,7 @@ export type GetBackupScheduleForVolumeResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -3367,7 +3367,7 @@ export type GetScheduleMirrorsResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };
@ -3587,7 +3587,7 @@ export type UpdateScheduleMirrorsResponses = {
lastError: string | null; lastError: string | null;
name: string; name: string;
shortId: string; shortId: string;
status: "doctor" | "error" | "healthy" | "unknown" | null; status: "cancelled" | "doctor" | "error" | "healthy" | "unknown" | null;
type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp"; type: "azure" | "gcs" | "local" | "r2" | "rclone" | "rest" | "s3" | "sftp";
updatedAt: number; updatedAt: number;
}; };

View file

@ -0,0 +1 @@
ALTER TABLE `repositories_table` ADD `doctor_result` text;

File diff suppressed because it is too large Load diff

View file

@ -302,6 +302,13 @@
"when": 1768687163221, "when": 1768687163221,
"tag": "0042_watery_liz_osborn", "tag": "0042_watery_liz_osborn",
"breakpoints": true "breakpoints": true
},
{
"idx": 43,
"version": "6",
"when": 1769085071955,
"tag": "0043_overjoyed_shen",
"breakpoints": true
} }
] ]
} }

View file

@ -9,13 +9,15 @@ import { type } from "arktype";
import { serverEvents } from "../../core/events"; import { serverEvents } from "../../core/events";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
import { safeJsonParse } from "../../utils/json"; import { safeJsonParse } from "../../utils/json";
import { getOrganizationId } from "~/server/core/request-context";
class AbortError extends Error { class AbortError extends Error {
name = "AbortError"; name = "AbortError";
} }
const runUnlockStep = async (config: RepositoryConfig, signal?: AbortSignal) => { const runUnlockStep = async (config: RepositoryConfig, signal?: AbortSignal) => {
const result = await restic.unlock(config, { signal }).then( const orgId = getOrganizationId();
const result = await restic.unlock(config, { signal, organizationId: orgId }).then(
(result) => ({ success: true, message: result.message, error: null }), (result) => ({ success: true, message: result.message, error: null }),
(error) => ({ success: false, message: null, error: toMessage(error) }), (error) => ({ success: false, message: null, error: toMessage(error) }),
); );
@ -29,7 +31,8 @@ const runUnlockStep = async (config: RepositoryConfig, signal?: AbortSignal) =>
}; };
const runCheckStep = async (config: RepositoryConfig, signal: AbortSignal) => { const runCheckStep = async (config: RepositoryConfig, signal: AbortSignal) => {
const result = await restic.check(config, { readData: true, signal }).then( const orgId = getOrganizationId();
const result = await restic.check(config, { readData: true, signal, organizationId: orgId }).then(
(result) => result, (result) => result,
(error) => ({ success: false, output: null, error: toMessage(error), hasErrors: true }), (error) => ({ success: false, output: null, error: toMessage(error), hasErrors: true }),
); );
@ -43,7 +46,8 @@ const runCheckStep = async (config: RepositoryConfig, signal: AbortSignal) => {
}; };
const runRepairIndexStep = async (config: RepositoryConfig, signal: AbortSignal) => { const runRepairIndexStep = async (config: RepositoryConfig, signal: AbortSignal) => {
const result = await restic.repairIndex(config, { signal }).then( const orgId = getOrganizationId();
const result = await restic.repairIndex(config, { signal, organizationId: orgId }).then(
(result) => ({ success: true, output: result.output, error: null }), (result) => ({ success: true, output: result.output, error: null }),
(error) => ({ success: false, output: null, error: toMessage(error) }), (error) => ({ success: false, output: null, error: toMessage(error) }),
); );

View file

@ -1,6 +1,6 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
import { and, eq, or } from "drizzle-orm"; import { and, eq, or } from "drizzle-orm";
import { InternalServerError, NotFoundError } from "http-errors-enhanced"; import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
import { db } from "../../db/db"; import { db } from "../../db/db";
import { repositoriesTable } from "../../db/schema"; import { repositoriesTable } from "../../db/schema";
import { toMessage } from "../../utils/errors"; import { toMessage } from "../../utils/errors";
@ -17,6 +17,11 @@ import {
type RepositoryConfig, type RepositoryConfig,
} from "~/schemas/restic"; } from "~/schemas/restic";
import { getOrganizationId } from "~/server/core/request-context"; import { getOrganizationId } from "~/server/core/request-context";
import { serverEvents } from "~/server/core/events";
import { executeDoctor } from "./doctor";
import { logger } from "~/server/utils/logger";
const runningDoctors = new Map<string, AbortController>();
const findRepository = async (idOrShortId: string) => { const findRepository = async (idOrShortId: string) => {
const organizationId = getOrganizationId(); const organizationId = getOrganizationId();
@ -345,7 +350,6 @@ const checkHealth = async (repositoryId: string) => {
}; };
const startDoctor = async (id: string) => { const startDoctor = async (id: string) => {
const organizationId = getOrganizationId();
const repository = await findRepository(id); const repository = await findRepository(id);
if (!repository) { if (!repository) {

View file

@ -736,7 +736,7 @@ const ls = async (config: RepositoryConfig, snapshotId: string, organizationId:
return { snapshot, nodes }; return { snapshot, nodes };
}; };
const unlock = async (config: RepositoryConfig, options: { signal?: AbortSignal, organizationId: string }) => { const unlock = async (config: RepositoryConfig, options: { signal?: AbortSignal; organizationId: string }) => {
const repoUrl = buildRepoUrl(config); const repoUrl = buildRepoUrl(config);
const env = await buildEnv(config, options.organizationId); const env = await buildEnv(config, options.organizationId);
@ -755,7 +755,10 @@ const unlock = async (config: RepositoryConfig, options: { signal?: AbortSignal,
return { success: true, message: "Repository unlocked successfully" }; return { success: true, message: "Repository unlocked successfully" };
}; };
const check = async (config: RepositoryConfig, options?: { readData?: boolean; signal?: AbortSignal }) => { const check = async (
config: RepositoryConfig,
options: { readData?: boolean; signal?: AbortSignal; organizationId: string },
) => {
const repoUrl = buildRepoUrl(config); const repoUrl = buildRepoUrl(config);
const env = await buildEnv(config, options.organizationId); const env = await buildEnv(config, options.organizationId);
@ -794,9 +797,9 @@ const check = async (config: RepositoryConfig, options?: { readData?: boolean; s
}; };
}; };
const repairIndex = async (config: RepositoryConfig, options?: { signal?: AbortSignal }) => { const repairIndex = async (config: RepositoryConfig, options: { signal?: AbortSignal; organizationId: string }) => {
const repoUrl = buildRepoUrl(config); const repoUrl = buildRepoUrl(config);
const env = await buildEnv(config, organizationId); const env = await buildEnv(config, options.organizationId);
const args = ["repair", "index", "--repo", repoUrl]; const args = ["repair", "index", "--repo", repoUrl];
addCommonArgs(args, env, config); addCommonArgs(args, env, config);