import { NextApiRequest, NextApiResponse } from 'next' import { IncomingForm, File as FormidableFile } from 'formidable' import FormData from 'form-data' import fs from 'fs' import { Readable } from 'stream' const MAX_FILE_SIZE = 50 * 1024 * 1024 // 50MB export const config = { api: { bodyParser: false, // Disable bodyParser to handle multipart }, } interface ParseResult { fields: Record files: Record } export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }) } // Get target endpoint from query or use default const targetEndpoint = (req.query.endpoint as string) || 'https://picstr.build/api/v1/upload' try { // Parse multipart form data // formidable needs the raw Node.js IncomingMessage, which NextApiRequest extends const form = new IncomingForm({ maxFileSize: MAX_FILE_SIZE, keepExtensions: true, }) const parseResult = await new Promise((resolve, reject) => { // Cast req to any to work with formidable - NextApiRequest extends IncomingMessage form.parse(req as any, (err, fields, files) => { if (err) { console.error('Formidable parse error:', err) reject(err) } else { resolve({ fields: fields as Record, files: files as Record }) } }) }) const { fields, files } = parseResult // Get the file from the parsed form const fileField = files.file?.[0] if (!fileField) { return res.status(400).json({ error: 'No file provided' }) } // Create FormData for the target endpoint const formData = new FormData() const fileStream = fs.createReadStream(fileField.filepath) formData.append('file', fileStream, { filename: fileField.originalFilename || fileField.newFilename || 'upload', contentType: fileField.mimetype || 'application/octet-stream', }) // Forward to target endpoint const response = await fetch(targetEndpoint, { method: 'POST', body: formData as unknown as BodyInit, headers: { ...formData.getHeaders(), }, }) // Clean up temporary file try { fs.unlinkSync(fileField.filepath) } catch (unlinkError) { console.error('Error deleting temp file:', unlinkError) } if (!response.ok) { const errorText = await response.text() return res.status(response.status).json({ error: errorText || `Upload failed: ${response.status} ${response.statusText}`, }) } const result = await response.json() return res.status(200).json(result) } catch (error) { console.error('NIP-95 proxy error:', error) return res.status(500).json({ error: error instanceof Error ? error.message : 'Internal server error', }) } }