import { ApiError, apiRequest, getApiUrl } from '@/lib/api/client'; import type { ApiEnvelope } from '@/types/api'; import type { LatestReleaseInfo, ReleaseChannel, UploadedServerBinaryInfo, } from '@/features/update/types'; export function getLatestRelease(channel: ReleaseChannel = 'stable') { return apiRequest( `/update/latest-release?channel=${channel}`, ); } export function upgradeServer(channel: ReleaseChannel = 'stable') { return apiRequest('/update/upgrade', { method: 'POST', body: JSON.stringify({ channel }), }); } export function uploadServerBinary( binary: File, onProgress?: (progress: number) => void, ): Promise { const formData = new FormData(); formData.append('binary', binary); if (!onProgress) { return apiRequest('/update/manual-upload', { method: 'POST', body: formData, }); } return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', getApiUrl('/update/manual-upload')); xhr.withCredentials = true; xhr.upload.addEventListener('progress', (event) => { if (event.lengthComputable) { onProgress(Math.round((event.loaded / event.total) * 100)); } }); xhr.addEventListener('load', () => { let payload: ApiEnvelope | null = null; try { payload = JSON.parse(xhr.responseText) as ApiEnvelope; } catch { payload = null; } if (xhr.status < 200 || xhr.status >= 300) { reject( new ApiError( payload?.message || `请求失败(${xhr.status})`, xhr.status, ), ); return; } if (!payload) { reject(new ApiError('响应格式无效', xhr.status)); return; } if (!payload.success) { reject(new ApiError(payload.message || '请求失败', xhr.status)); return; } resolve(payload.data); }); xhr.addEventListener('error', () => { reject(new ApiError('上传过程中网络连接中断,请检查网络后重试', 0)); }); xhr.send(formData); }); } export function confirmManualServerUpgrade(uploadToken: string) { return apiRequest('/update/manual-upgrade', { method: 'POST', body: JSON.stringify({ upload_token: uploadToken }), }); }