refactor: strengthen upload boundary types
This commit is contained in:
+4
-3
@@ -19,12 +19,13 @@ export interface ParsedUpload {
|
||||
*/
|
||||
export async function parseMultiUpload(req: NextRequest): Promise<ParsedUpload> {
|
||||
const formData = await req.formData()
|
||||
const folderName = (formData.get('folderName') as string | null)?.trim() || 'assets'
|
||||
const folderValue = formData.get('folderName')
|
||||
const folderName = typeof folderValue === 'string' ? folderValue.trim() || 'assets' : 'assets'
|
||||
const safeFolderName = sanitizeFilename(folderName).replace(/[^a-zA-Z0-9-_]/g, '-')
|
||||
|
||||
const rawFiles = formData.getAll('files')
|
||||
const fileTypes = formData.getAll('fileTypes') as string[]
|
||||
const textureNames = formData.getAll('textureNames') as string[]
|
||||
const fileTypes = formData.getAll('fileTypes').filter((value): value is string => typeof value === 'string')
|
||||
const textureNames = formData.getAll('textureNames').filter((value): value is string => typeof value === 'string')
|
||||
|
||||
// Collect extra string fields
|
||||
const knownKeys = new Set(['folderName', 'files', 'fileTypes', 'textureNames'])
|
||||
|
||||
+35
-13
@@ -16,6 +16,20 @@ export interface StageResult {
|
||||
filesCount: number
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
|
||||
function getApiError(data: unknown, fallback: string) {
|
||||
return isRecord(data) && typeof data.error === 'string' ? data.error : fallback
|
||||
}
|
||||
|
||||
function isFileDiff(value: unknown): value is FileDiff {
|
||||
return isRecord(value)
|
||||
&& typeof value.name === 'string'
|
||||
&& (value.status === 'new' || value.status === 'changed' || value.status === 'deleted')
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared FormData builder
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -69,18 +83,20 @@ export async function checkFolderDiffs(
|
||||
signal,
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
const data: unknown = await res.json()
|
||||
|
||||
// Surface auth/server errors to the caller
|
||||
if (!res.ok) {
|
||||
throw new Error(data.error || `Erreur serveur (${res.status})`)
|
||||
throw new Error(getApiError(data, `Erreur serveur (${res.status})`))
|
||||
}
|
||||
|
||||
if (!data.success || !data.exists) {
|
||||
if (!isRecord(data) || data.success !== true || data.exists !== true) {
|
||||
return { exists: false, diffs: [] }
|
||||
}
|
||||
|
||||
return { exists: true, diffs: (data.diffs || []) as FileDiff[] }
|
||||
const diffs = Array.isArray(data.diffs) ? data.diffs.filter(isFileDiff) : []
|
||||
|
||||
return { exists: true, diffs }
|
||||
}
|
||||
|
||||
export async function stageUpload(
|
||||
@@ -96,10 +112,14 @@ export async function stageUpload(
|
||||
signal,
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
const data: unknown = await res.json()
|
||||
|
||||
if (!res.ok || !data.success) {
|
||||
throw new Error(data.error || `Erreur serveur (${res.status})`)
|
||||
if (!res.ok || !isRecord(data) || data.success !== true) {
|
||||
throw new Error(getApiError(data, `Erreur serveur (${res.status})`))
|
||||
}
|
||||
|
||||
if (typeof data.stagingId !== 'string' || typeof data.folderName !== 'string' || typeof data.filesCount !== 'number') {
|
||||
throw new Error('Reponse serveur invalide')
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -130,8 +150,10 @@ export async function uploadDrive(
|
||||
body: JSON.stringify({ stagingId, action }),
|
||||
signal,
|
||||
})
|
||||
const data = await res.json()
|
||||
if (!data.success) return { success: false, error: data.error }
|
||||
const data: unknown = await res.json()
|
||||
if (!res.ok || !isRecord(data) || data.success !== true) {
|
||||
return { success: false, error: getApiError(data, `Erreur serveur (${res.status})`) }
|
||||
}
|
||||
return { success: true }
|
||||
} catch (err) {
|
||||
if (err instanceof DOMException && err.name === 'AbortError') {
|
||||
@@ -166,14 +188,14 @@ export async function uploadGit(
|
||||
})
|
||||
|
||||
onProgress(80)
|
||||
const data = await res.json()
|
||||
const data: unknown = await res.json()
|
||||
|
||||
if (!data.success) {
|
||||
return { success: false, error: data.error }
|
||||
if (!res.ok || !isRecord(data) || data.success !== true) {
|
||||
return { success: false, error: getApiError(data, `Erreur serveur (${res.status})`) }
|
||||
}
|
||||
|
||||
onProgress(100)
|
||||
return { success: true, filename: data.folderName }
|
||||
return { success: true, filename: typeof data.folderName === 'string' ? data.folderName : undefined }
|
||||
} catch (err) {
|
||||
if (err instanceof DOMException && err.name === 'AbortError') {
|
||||
return { success: false, error: 'Upload annule' }
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
export type DriveAction = 'new' | 'replace'
|
||||
|
||||
interface StagingRequestBody {
|
||||
stagingId: string
|
||||
}
|
||||
|
||||
interface DriveRequestBody extends StagingRequestBody {
|
||||
action: DriveAction
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null
|
||||
}
|
||||
|
||||
export function parseStagingRequestBody(value: unknown): StagingRequestBody {
|
||||
if (!isRecord(value) || typeof value.stagingId !== 'string' || value.stagingId.trim() === '') {
|
||||
throw new Error('stagingId manquant')
|
||||
}
|
||||
|
||||
return { stagingId: value.stagingId }
|
||||
}
|
||||
|
||||
export function parseDriveRequestBody(value: unknown): DriveRequestBody {
|
||||
const { stagingId } = parseStagingRequestBody(value)
|
||||
const action = isRecord(value) && value.action === 'replace' ? 'replace' : 'new'
|
||||
|
||||
return { stagingId, action }
|
||||
}
|
||||
Reference in New Issue
Block a user