import sharp from "sharp"; import { HttpError } from "@/lib/security/http"; import { hasValidImageSignature, MAX_MEDIA_BYTES, type IMAGE_MIME_TYPES } from "./validation"; export const MAX_IMAGE_PIXELS = 40_000_000; export async function inspectImage(bytes: Uint8Array, mimeType: (typeof IMAGE_MIME_TYPES)[number]) { if (bytes.byteLength > MAX_MEDIA_BYTES) throw new HttpError(413, "image-too-large"); if (!hasValidImageSignature(bytes.subarray(0, 16), mimeType)) throw new HttpError(422, "invalid-image"); try { const image = sharp(bytes, { limitInputPixels: MAX_IMAGE_PIXELS, failOn: "warning", animated: true }); const metadata = await image.metadata(); const width = metadata.autoOrient.width || metadata.width; const height = metadata.autoOrient.height || metadata.height; if (!width || !height || width * height > MAX_IMAGE_PIXELS) throw new Error("invalid dimensions"); // Metadata alone accepts truncated images; decode pixels before publishing. await image.stats(); return { width, height }; } catch { throw new HttpError(422, "invalid-image"); } }