| import { put } from '@vercel/blob'; | |
| export default async function handler(req, res) { | |
| if (req.method !== 'PUT') { | |
| return res.status(405).json({ message: 'Method not allowed' }); | |
| } | |
| try { | |
| const token = process.env.BLOB_READ_WRITE_TOKEN; | |
| // Prefer project credentials; if that fails and a token is present, retry with token. | |
| const name = (req.query.name && String(req.query.name)) || `uploads/${Date.now()}.bin`; | |
| const contentType = req.headers['content-type'] || 'application/octet-stream'; | |
| // Debug logs (streaming, no buffering) | |
| try { | |
| console.log('blob-upload debug', { | |
| name, | |
| contentType, | |
| streamed: true, | |
| }); | |
| } catch {} | |
| // Stream the incoming request directly to Vercel Blob to avoid buffering large files | |
| const baseOpts = { contentType, access: 'public', addRandomSuffix: false }; | |
| let result; | |
| try { | |
| // Attempt using project credentials (no token) - stream request | |
| result = await put(name, req, baseOpts); | |
| } catch (e1) { | |
| try { console.error('blob-upload first attempt failed (no token)', e1?.message || String(e1)); } catch {} | |
| if (token) { | |
| try { | |
| // Fallback: attempt with provided token - stream request | |
| result = await put(name, req, { ...baseOpts, token }); | |
| } catch (e2) { | |
| try { console.error('blob-upload second attempt failed (with token)', e2?.message || String(e2)); } catch {} | |
| throw e2; | |
| } | |
| } else { | |
| throw e1; | |
| } | |
| } | |
| return res.status(201).json({ url: result.url }); | |
| } catch (error) { | |
| try { console.error('blob-upload error', error); } catch {} | |
| return res.status(500).json({ message: 'Upload failed', error: error.message || String(error) }); | |
| } | |
| } | |