Importer: set asset mime type from file extension

Uploaded manifest assets previously became application/octet-stream because the
Blob carried no type, so images/audio/pdf didn't display or thumbnail correctly.
Derive the mime from the extension. (Existing deduplicated assets keep their old
mime; only fresh uploads are affected.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 19:12:53 +02:00
co-authored by Claude Opus 4.8
parent 7fe8fadd8a
commit f10d7584d2
+8 -1
View File
@@ -41,11 +41,18 @@ function requireOk(response: Response, action: string) {
return response.text().then(body => { throw new Error(`${action} failed (${response.status}): ${body}`) }) return response.text().then(body => { throw new Error(`${action} failed (${response.status}): ${body}`) })
} }
const MIME_BY_EXT: Record<string, string> = {
png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp', svg: 'image/svg+xml',
pdf: 'application/pdf', mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4', txt: 'text/plain',
}
function mimeFor(filename: string) { return MIME_BY_EXT[filename.split('.').pop()?.toLowerCase() || ''] || 'application/octet-stream' }
async function uploadAsset(baseUrl: string, levelId: string, manifestDir: string, document: MysteryDocument, authorization?: string) { async function uploadAsset(baseUrl: string, levelId: string, manifestDir: string, document: MysteryDocument, authorization?: string) {
if (!document.asset) return undefined if (!document.asset) return undefined
const assetPath = path.resolve(manifestDir, document.asset) const assetPath = path.resolve(manifestDir, document.asset)
const filename = path.basename(assetPath)
const form = new FormData() const form = new FormData()
form.append('file', new Blob([await readFile(assetPath)]), path.basename(assetPath)) form.append('file', new Blob([await readFile(assetPath)], { type: mimeFor(filename) }), filename)
const response = await requireOk(await fetch(`${baseUrl}/api/levels/${levelId}/documents?edit=1`, { method: 'POST', headers: authorization ? { authorization } : undefined, body: form }), `Upload ${document.asset}`) const response = await requireOk(await fetch(`${baseUrl}/api/levels/${levelId}/documents?edit=1`, { method: 'POST', headers: authorization ? { authorization } : undefined, body: form }), `Upload ${document.asset}`)
return await response.json() as CaseDocument return await response.json() as CaseDocument
} }