import { fetchJson, type ApiRequestOptions } from "../client"; import { getBackendConfig } from "@/lib/config"; import type { SystemInfo, DiskUsageResponse, DatabaseStats, SnapshotInfo, LogFileInfo, LogTailResponse, UpdatesResponse, JobAcceptResponse, RestartCapability, RestartResponse, StorageAdoptionResponse, StorageMaintenanceRun, StorageMaintenanceSettings, StorageOverviewResponse, StorageQuarantineEntry, StorageSettingsResponse, } from "@/lib/types/system"; const SYSTEM_BASE = "/api/v1/system"; // --- Info --------------------------------------------------------------- export function fetchSystemInfo(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/info`, options); } // --- Disk usage --------------------------------------------------------- export function fetchDiskUsage(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/disk-usage`, options); } export function refreshDiskUsage(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/disk-usage/refresh`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } export function openDataFolder(options?: ApiRequestOptions): Promise<{ path: string }> { return fetchJson<{ path: string }>(`${SYSTEM_BASE}/disk-usage/open`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } // --- Database ----------------------------------------------------------- export function fetchDatabaseStats(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/database`, options); } export function vacuumDatabase(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/database/vacuum`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } export function optimizeDatabase(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/database/optimize`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } export function resetDatabase( confirm: string, options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/database/reset`, { ...options, init: { method: "POST", body: JSON.stringify({ confirm }), ...(options?.init ?? {}) }, }); } // --- Backups ------------------------------------------------------------ export async function fetchBackups(options?: ApiRequestOptions): Promise { const res = await fetchJson<{ snapshots: SnapshotInfo[] }>(`${SYSTEM_BASE}/backups`, options); return res.snapshots ?? []; } export function createBackup(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/backups`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } export function restoreBackup( name: string, confirm: string, options?: ApiRequestOptions, ): Promise { return fetchJson( `${SYSTEM_BASE}/backups/${encodeURIComponent(name)}/restore`, { ...options, init: { method: "POST", body: JSON.stringify({ confirm }), ...(options?.init ?? {}) }, }, ); } export function deleteBackup(name: string, options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/backups/${encodeURIComponent(name)}`, { ...options, init: { method: "DELETE", ...(options?.init ?? {}) }, }); } /** * Builds an absolute URL for downloading a snapshot. Snapshot downloads stream * binary data, so they cannot reuse fetchJson — they are typically wired into * or window.open(). */ export function buildBackupDownloadUrl(name: string, baseUrl?: string): string { const root = baseUrl ?? getBackendConfig().apiBaseUrl; return `${root}${SYSTEM_BASE}/backups/${encodeURIComponent(name)}/download`; } // --- Logs --------------------------------------------------------------- export async function fetchLogFiles(options?: ApiRequestOptions): Promise { const res = await fetchJson<{ files: LogFileInfo[] }>(`${SYSTEM_BASE}/logs`, options); return res.files ?? []; } export function fetchLogTail(n = 1000, options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/logs/tail?n=${encodeURIComponent(String(n))}`, { cache: "no-store", ...options, }); } export function buildLogDownloadUrl(name: string, baseUrl?: string): string { const root = baseUrl ?? getBackendConfig().apiBaseUrl; return `${root}${SYSTEM_BASE}/logs/${encodeURIComponent(name)}/download`; } // --- Jobs --------------------------------------------------------------- export function fetchSystemJob( jobId: string, options?: ApiRequestOptions, ): Promise { return fetchJson( `${SYSTEM_BASE}/jobs/${encodeURIComponent(jobId)}`, { cache: "no-store", ...options }, ); } // --- Updates ------------------------------------------------------------ export function fetchUpdates(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/updates`, options); } export function checkUpdates(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/updates/check`, { ...options, init: { method: "POST", ...(options?.init ?? {}) }, }); } export function applyUpdate( confirm = "UPDATE", options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/updates/apply`, { ...options, // Spread caller init first so the required method/body can't be overridden. init: { ...(options?.init ?? {}), method: "POST", body: JSON.stringify({ confirm }) }, }); } // --- Restart ------------------------------------------------------------ export function fetchRestartCapability(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/restart-capability`, { ...options, cache: "no-store", }); } export function requestRestart(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/restart`, { ...options, init: { ...(options?.init ?? {}), method: "POST" }, }); } // --- Storage maintenance ------------------------------------------------ export function fetchStorageOverview( options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/storage`, { ...options, cache: "no-store", }); } export function saveStorageSettings( settings: StorageMaintenanceSettings, dedicatedDockerConfirmation?: "DEDICATED", options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/storage/settings`, { ...options, init: { ...(options?.init ?? {}), method: "PATCH", body: JSON.stringify({ settings, confirmations: dedicatedDockerConfirmation ? { dedicated_docker: dedicatedDockerConfirmation } : {}, }), }, }); } export function adoptStorageGoCache( path: string, options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/storage/go-cache/adopt`, { ...options, init: { ...(options?.init ?? {}), method: "POST", body: JSON.stringify({ path, confirm: "ADOPT" }), }, }); } export function analyzeStorage(options?: ApiRequestOptions): Promise { return fetchJson(`${SYSTEM_BASE}/storage/analyze`, { ...options, init: { ...(options?.init ?? {}), method: "POST" }, }); } export function runStorageMaintenance( resources?: string[], options?: ApiRequestOptions, ): Promise { return fetchJson(`${SYSTEM_BASE}/storage/run`, { ...options, init: { ...(options?.init ?? {}), method: "POST", body: JSON.stringify(resources?.length ? { resources } : {}), }, }); } export async function fetchStorageRuns( limit = 20, options?: ApiRequestOptions, ): Promise { const response = await fetchJson<{ runs: StorageMaintenanceRun[] }>( `${SYSTEM_BASE}/storage/runs?limit=${encodeURIComponent(String(limit))}`, { ...options, cache: "no-store" }, ); return response.runs ?? []; } export async function fetchStorageQuarantine( options?: ApiRequestOptions, ): Promise { const response = await fetchJson<{ entries: StorageQuarantineEntry[] }>( `${SYSTEM_BASE}/storage/quarantine`, { ...options, cache: "no-store" }, ); return response.entries ?? []; } export async function restoreStorageQuarantine( id: string, options?: ApiRequestOptions, ): Promise { const response = await fetchJson<{ entry: StorageQuarantineEntry }>( `${SYSTEM_BASE}/storage/quarantine/${encodeURIComponent(id)}/restore`, { ...options, init: { ...(options?.init ?? {}), method: "POST" } }, ); return response.entry; } export function deleteStorageQuarantine( id: string, options?: ApiRequestOptions, ): Promise { return fetchJson( `${SYSTEM_BASE}/storage/quarantine/${encodeURIComponent(id)}`, { ...options, init: { ...(options?.init ?? {}), method: "DELETE", body: JSON.stringify({ confirm: "DELETE" }), }, }, ); }