import type { RequestHandler } from './$types'; import { json, error } from '@sveltejs/kit'; import { createHash } from 'node:crypto'; import { existsSync } from 'node:fs'; import { mkdir, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { getDb } from '$lib/server/db'; import { parsePositiveIntParam } from '$lib/server/api-helpers'; import { getRecipeById, updateImagePath } from '$lib/server/recipes/repository'; import { IMAGE_DIR } from '$lib/server/paths'; const MAX_BYTES = 10 * 1024 * 1024; const EXT_BY_MIME: Record = { 'image/jpeg': '.jpg', 'image/jpg': '.jpg', 'image/png': '.png', 'image/webp': '.webp', 'image/gif': '.gif', 'image/avif': '.avif' }; export const POST: RequestHandler = async ({ params, request }) => { const id = parsePositiveIntParam(params.id, 'id'); const db = getDb(); if (!getRecipeById(db, id)) error(404, { message: 'Recipe not found' }); const form = await request.formData().catch(() => null); const file = form?.get('file'); if (!(file instanceof File)) error(400, { message: 'Field "file" missing' }); if (file.size === 0) error(400, { message: 'Empty file' }); if (file.size > MAX_BYTES) error(413, { message: 'Image too large (max 10 MB)' }); const mime = file.type.toLowerCase(); const ext = EXT_BY_MIME[mime]; if (!ext) error(415, { message: `Image format ${file.type || 'unknown'} not supported` }); const buf = Buffer.from(await file.arrayBuffer()); const hash = createHash('sha256').update(buf).digest('hex'); const filename = `${hash}${ext}`; const target = join(IMAGE_DIR, filename); if (!existsSync(target)) { await mkdir(IMAGE_DIR, { recursive: true }); await writeFile(target, buf); } updateImagePath(db, id, filename); return json({ ok: true, image_path: filename }); }; export const DELETE: RequestHandler = ({ params }) => { const id = parsePositiveIntParam(params.id, 'id'); const db = getDb(); if (!getRecipeById(db, id)) error(404, { message: 'Recipe not found' }); updateImagePath(db, id, null); return json({ ok: true }); };