"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.downloadAndOptimizeImage = downloadAndOptimizeImage; const fs = require("fs"); const path = require("path"); const sharp = require("sharp"); const uuid_1 = require("uuid"); const BLOCKED_HOSTNAMES = /^(localhost|127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|0\.0\.0\.0|::1|fc00:|fe80:)/i; async function downloadAndOptimizeImage(sourceUrl, destDir) { const raw = sourceUrl.trim(); const protocolNormalized = raw.startsWith('//') ? `https:${raw}` : raw; let parsedUrl; try { parsedUrl = new URL(protocolNormalized); } catch { throw new Error('Ogiltig bild-URL'); } if (parsedUrl.protocol !== 'https:') { throw new Error('Bild-URL måste använda https://'); } const hostname = parsedUrl.hostname; if (BLOCKED_HOSTNAMES.test(hostname)) { throw new Error('Bild-URL pekar på ett blockerat nätverk'); } const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 10_000); let response; try { response = await fetch(parsedUrl.toString(), { signal: controller.signal, headers: { 'User-Agent': 'Mozilla/5.0 (compatible; RecipeApp/1.0)' }, }); } finally { clearTimeout(timeout); } if (!response.ok) { throw new Error(`HTTP ${response.status} vid nedladdning av bild`); } const contentType = response.headers.get('content-type') ?? ''; if (!contentType.startsWith('image/')) { throw new Error(`Ogiltig content-type: ${contentType}`); } const arrayBuffer = await response.arrayBuffer(); if (arrayBuffer.byteLength > 5 * 1024 * 1024) { throw new Error('Bilden är för stor (max 5 MB)'); } const imageBuffer = Buffer.from(arrayBuffer); if (!fs.existsSync(destDir)) { fs.mkdirSync(destDir, { recursive: true }); } const filename = `${(0, uuid_1.v4)()}.jpg`; const outputPath = path.join(destDir, filename); await sharp(imageBuffer) .resize(1200, 800, { fit: 'inside', withoutEnlargement: true, }) .jpeg({ quality: 80 }) .toFile(outputPath); return `/images/${filename}`; } //# sourceMappingURL=download-image.js.map