{"release_id":"01a1c502-4ad1-0000-ec62-adc54d3c69aa","chunk_id":"01a1c502-4adb-7a92-86d3-e11d6b4be942","file":"6O34v4Qp.mjs","mappings":"wVAEA,MAAMA,EAAa,IAAI,IAAI,CAAC,aAAc,YAAa,YAAY,CAAC,EAE9DC,EAAW,KACXC,EAAe,IAerB,eAAsBC,EAAgBC,EAA2B,CAMhE,GAAI,CACH,MAAMC,EAAY,MAAMC,EAAWF,CAAI,EACnCC,IAAcD,IAAMA,EAAOC,EAChC,MAAQ,CAER,CAGA,GADI,CAACL,EAAW,IAAII,EAAK,IAAI,GACzB,OAAO,mBAAsB,YAAc,OAAO,gBAAoB,IACzE,OAAOA,EAGR,GAAI,CACH,MAAMG,EAAS,MAAM,kBAAkBH,EAAM,CAAE,iBAAkB,aAAc,EACzEI,EAAU,KAAK,IAAID,EAAO,MAAOA,EAAO,MAAM,EAC9CE,EAAQD,EAAUP,EAAWA,EAAWO,EAAU,EAClDE,EAAQ,KAAK,MAAMH,EAAO,MAAQE,CAAK,EACvCE,EAAS,KAAK,MAAMJ,EAAO,OAASE,CAAK,EAEzCG,EAAS,IAAI,gBAAgBF,EAAOC,CAAM,EAC1CE,EAAMD,EAAO,WAAW,IAAI,EAClC,GAAI,CAACC,EACJ,OAAAN,EAAO,MAAA,EACAH,EAERS,EAAI,UAAUN,EAAQ,EAAG,EAAGG,EAAOC,CAAM,EACzCJ,EAAO,MAAA,EAEP,MAAMO,EAAUV,EAAK,OAAS,YAAc,YAAcA,EAAK,KACzDW,EAAO,MAAMH,EAAO,cACzBE,IAAY,YAAc,CAAE,KAAM,WAAA,EAAgB,CAAE,KAAMA,EAAS,QAASZ,CAAA,CAAa,EAGpFc,EAAMF,IAAY,YAAc,MAAQA,IAAY,aAAe,OAAS,MAC5EG,EAAWb,EAAK,KAAK,QAAQ,WAAY,EAAE,GAAK,QACtD,OAAO,IAAI,KAAK,CAACW,CAAI,EAAG,GAAGE,CAAQ,IAAID,CAAG,GAAI,CAAE,KAAMF,EAAS,aAAc,KAAK,IAAA,EAAO,CAC1F,MAAQ,CACP,OAAOV,CACR,CACD","names":["STRIPPABLE","MAX_EDGE","JPEG_QUALITY","stripExifClient","file","converted","heicToJpeg","bitmap","longest","scale","width","height","canvas","ctx","outType","blob","ext","baseName"],"sources":["../../../../../../src/lib/utils/strip-exif-client.ts"],"sourcesContent":["import { heicToJpeg } from '$lib/utils/heic-to-jpeg';\n\nconst STRIPPABLE = new Set(['image/jpeg', 'image/png', 'image/webp']);\n\nconst MAX_EDGE = 2048;\nconst JPEG_QUALITY = 0.92;\n\n/**\n * Client-side EXIF removal via canvas re-encode. Canvas drawing never carries\n * pixel-adjacent metadata (EXIF, IPTC, XMP), so the canvas → blob round-trip\n * is a free strip on every browser that supports `createImageBitmap`. Bonus:\n * we downscale photos over 2048px on the longer edge — modern phones shoot\n * 4032×3024 by default, which is ~5MB before any user sees it.\n *\n * This is the FIRST line of defence. The server still re-strips with sharp on\n * the publishing path so a bypassed/failed client strip never leaks GPS.\n *\n * Returns the original `file` unchanged on any failure (unsupported mime,\n * canvas error, decode error) — server-side belt catches it.\n */\nexport async function stripExifClient(file: File): Promise<File> {\n\t// HEIC/HEIF first — neither canvas nor sharp (no libheif) can read it, so\n\t// without this branch an iPhone HEIC slips through with full EXIF intact.\n\t// Guarded: the magic-byte sniff reads the file, which can reject on iOS\n\t// (iCloud-offloaded photo not yet materialized) — this function's contract\n\t// is \"never throws\", and a throw here would strand callers' uploading flags.\n\ttry {\n\t\tconst converted = await heicToJpeg(file);\n\t\tif (converted !== file) file = converted;\n\t} catch {\n\t\t// fall through with the original file — server-side strip is the belt\n\t}\n\n\tif (!STRIPPABLE.has(file.type)) return file;\n\tif (typeof createImageBitmap !== 'function' || typeof OffscreenCanvas === 'undefined') {\n\t\treturn file;\n\t}\n\n\ttry {\n\t\tconst bitmap = await createImageBitmap(file, { imageOrientation: 'from-image' });\n\t\tconst longest = Math.max(bitmap.width, bitmap.height);\n\t\tconst scale = longest > MAX_EDGE ? MAX_EDGE / longest : 1;\n\t\tconst width = Math.round(bitmap.width * scale);\n\t\tconst height = Math.round(bitmap.height * scale);\n\n\t\tconst canvas = new OffscreenCanvas(width, height);\n\t\tconst ctx = canvas.getContext('2d');\n\t\tif (!ctx) {\n\t\t\tbitmap.close();\n\t\t\treturn file;\n\t\t}\n\t\tctx.drawImage(bitmap, 0, 0, width, height);\n\t\tbitmap.close();\n\n\t\tconst outType = file.type === 'image/png' ? 'image/png' : file.type;\n\t\tconst blob = await canvas.convertToBlob(\n\t\t\toutType === 'image/png' ? { type: 'image/png' } : { type: outType, quality: JPEG_QUALITY }\n\t\t);\n\n\t\tconst ext = outType === 'image/png' ? 'png' : outType === 'image/webp' ? 'webp' : 'jpg';\n\t\tconst baseName = file.name.replace(/\\.[^.]+$/, '') || 'photo';\n\t\treturn new File([blob], `${baseName}.${ext}`, { type: outType, lastModified: Date.now() });\n\t} catch {\n\t\treturn file;\n\t}\n}\n"],"version":3}