import { existsSync, mkdirSync, writeFileSync } from 'node:fs' import { join } from 'node:path' import { readMultipartFormData } from 'h3' const publicDir = './public' const allowedFolders = ['scores', 'pubs', 'album_art', 'images', 'hdp_images'] const allowedExtensions = ['.pdf', '.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.mp3', '.wav', '.ogg'] function getFolderPath(folder) { return join(publicDir, folder) } function sanitizeFilename(filename) { return filename.replace(/[^a-zA-Z0-9._-]/g, '_') } export default defineEventHandler(async (event) => { const query = getQuery(event) const folder = query.folder if (!folder || !allowedFolders.includes(folder)) { throw createError({ statusCode: 400, message: 'Invalid folder' }) } const folderPath = getFolderPath(folder) if (!existsSync(folderPath)) { mkdirSync(folderPath, { recursive: true }) } const formData = await readMultipartFormData(event) if (!formData || formData.length === 0) { throw createError({ statusCode: 400, message: 'No file uploaded' }) } const fileField = formData.find(f => f.name === 'file') if (!fileField || !fileField.data) { throw createError({ statusCode: 400, message: 'No file data' }) } const ext = fileField.filename ? fileField.filename.toLowerCase().slice(fileField.filename.lastIndexOf('.')) : '' if (!allowedExtensions.includes(ext)) { throw createError({ statusCode: 400, message: `File type not allowed. Allowed: ${allowedExtensions.join(', ')}` }) } const filename = fileField.filename ? sanitizeFilename(fileField.filename) : `upload${ext}` const filePath = join(folderPath, filename) writeFileSync(filePath, fileField.data) return { success: true, filename, url: `/${folder}/${filename}` } })