mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:41:09 +02:00
iPhone HEIC photos uploaded through Chrome on macOS landed as
`mimeType: application/octet-stream` because Chrome doesn't recognise
the HEIC MIME and `file.type` was empty. The transform endpoint then
refused with `Transform only supported for images` (HTTP 400) and
the wardrobe Try-On flow surfaced this as `mana-media transform
failed for <id>: HTTP 400`. Even fixing the MIME wouldn't have been
enough — sharp's prebuilt binary ships the heif container format
without a HEVC decoder plugin (libde265 is omitted for patent
reasons), so the actual decode would still throw.
Three-part fix at the upload edge:
1. New `services/sniff.ts` — magic-byte sniffer for image MIMEs.
Reads the first ~16 bytes and recognises JPEG, PNG, GIF, WebP,
BMP, TIFF, HEIC, HEIF, AVIF. Returns `null` for everything else
so the caller can fall back to whatever the browser claimed.
2. Upload route — sniffs every upload before passing the buffer to
`uploadService.upload`. Trusts magic bytes over `file.type` so
Chrome's empty-type HEIC still lands with `image/heic`. Removes
the entire class of `application/octet-stream` rows for files
that are obviously images.
3. HEIC/HEIF transcoded to JPEG at upload via the new
`heic-convert` dependency (pure-JS WASM, no system libs needed).
The original buffer is replaced with the JPEG bytes, the MIME
becomes `image/jpeg`, and the filename's `.HEIC` extension is
rewritten to `.jpg`. Downstream code (process pipeline, transform
endpoint, sharp) then deals exclusively with formats sharp can
actually decode. Failure path returns HTTP 500 with a clear
`HEIC conversion failed` error so the client knows it wasn't a
generic crash.
Bonus, transform endpoint hardening: `mimeType.startsWith('image/')`
gate now also accepts a row whose stored MIME is wrong (legacy
`application/octet-stream` from before this fix) when the actual
bytes sniff as an image. Lets old broken rows still serve where
the format itself is decodable; the upload-side fix prevents new
ones from existing.
Sharp 0.33 on this machine reports `heif: 1.18.2` for the container
but rejects the actual HEVC compressed bitstream — confirmed by the
exact error string `No decoding plugin installed for this
compression format (11.6003)`. Going through `heic-convert` first
sidesteps that entirely.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
34 lines
836 B
JSON
34 lines
836 B
JSON
{
|
|
"name": "@mana-media/api",
|
|
"version": "0.2.0",
|
|
"private": true,
|
|
"scripts": {
|
|
"dev": "bun run --hot src/index.ts",
|
|
"start": "bun run src/index.ts",
|
|
"type-check": "tsc --noEmit",
|
|
"db:push": "drizzle-kit push",
|
|
"db:generate": "drizzle-kit generate",
|
|
"db:migrate": "bun run src/db/migrate.ts",
|
|
"db:studio": "drizzle-kit studio"
|
|
},
|
|
"dependencies": {
|
|
"bullmq": "^5.34.0",
|
|
"drizzle-orm": "^0.38.3",
|
|
"exifr": "^7.1.3",
|
|
"heic-convert": "^2.1.0",
|
|
"hono": "^4.7.0",
|
|
"mime-types": "^2.1.35",
|
|
"minio": "^8.0.0",
|
|
"postgres": "^3.4.5",
|
|
"prom-client": "^15.1.0",
|
|
"sharp": "^0.33.0"
|
|
},
|
|
"devDependencies": {
|
|
"@mana/shared-drizzle-config": "workspace:*",
|
|
"@types/heic-convert": "^2.1.0",
|
|
"@types/mime-types": "^2.1.4",
|
|
"@types/node": "^22.0.0",
|
|
"drizzle-kit": "^0.30.1",
|
|
"typescript": "^5.7.0"
|
|
}
|
|
}
|