// --------------------------------------------------------------------------- // Client-side API helpers for upload operations // --------------------------------------------------------------------------- import type { FolderEntry } from './client-types' import type { FileDiff } from './types' export interface CheckResult { exists: boolean diffs: FileDiff[] } // --------------------------------------------------------------------------- // Shared FormData builder // --------------------------------------------------------------------------- function buildUploadFormData( folder: FolderEntry, destination: string, extra?: Record, ): FormData { const formData = new FormData() formData.append('folderName', folder.folderName) formData.append('destination', destination) if (extra) { for (const [key, value] of Object.entries(extra)) { formData.append(key, value) } } formData.append('files', folder.modelFile) formData.append('fileTypes', 'model') formData.append('textureNames', '') for (const tex of folder.textures) { formData.append('files', tex.file) formData.append('fileTypes', 'texture') formData.append('textureNames', tex.name) } return formData } // --------------------------------------------------------------------------- // Check folder diffs against remote (GitHub) // --------------------------------------------------------------------------- /** * Check whether a folder already exists on the remote repo and compute diffs. * Throws on auth/network errors so callers can surface them to the user. */ export async function checkFolderDiffs( folder: FolderEntry, destination: string, secret: string, signal?: AbortSignal, ): Promise { const formData = buildUploadFormData(folder, destination) const res = await fetch('/api/upload/check', { method: 'POST', headers: { 'x-upload-secret': secret.trim() }, body: formData, signal, }) const data = await res.json() // Surface auth/server errors to the caller if (!res.ok) { throw new Error(data.error || `Erreur serveur (${res.status})`) } if (!data.success || !data.exists) { return { exists: false, diffs: [] } } return { exists: true, diffs: (data.diffs || []) as FileDiff[] } } // --------------------------------------------------------------------------- // Upload original files to Nextcloud Drive // --------------------------------------------------------------------------- /** Upload original files to Nextcloud Drive (no Blender compression). */ export async function uploadDrive( folder: FolderEntry, secret: string, destination: string, action: 'new' | 'replace', signal?: AbortSignal, ): Promise<{ success: boolean; error?: string }> { const formData = buildUploadFormData(folder, destination, { action }) try { const res = await fetch('/api/upload/drive', { method: 'POST', headers: { 'x-upload-secret': secret.trim() }, body: formData, signal, }) const data = await res.json() if (!data.success) return { success: false, error: data.error } return { success: true } } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') { return { success: false, error: 'Upload annule' } } return { success: false, error: 'Erreur reseau (Drive)' } } } // --------------------------------------------------------------------------- // Upload files to GitHub (with Blender compression) // --------------------------------------------------------------------------- /** Upload files to GitHub (with Blender compression). */ export async function uploadGit( folder: FolderEntry, secret: string, destination: string, onProgress: (pct: number) => void, signal?: AbortSignal, ): Promise<{ success: boolean; filename?: string; error?: string }> { const formData = buildUploadFormData(folder, destination) onProgress(10) try { const res = await fetch('/api/upload/git', { method: 'POST', headers: { 'x-upload-secret': secret.trim() }, body: formData, signal, }) onProgress(80) const data = await res.json() if (!data.success) { return { success: false, error: data.error } } onProgress(100) return { success: true, filename: folder.folderName } } catch (err) { if (err instanceof DOMException && err.name === 'AbortError') { return { success: false, error: 'Upload annule' } } return { success: false, error: 'Erreur reseau' } } }