// /components/files/fileController.js const catchAsync = require('../../utils/catchAsync'); const fileService = require('./fileService'); const { successResponse } = require('../../utils/apiResponse'); const AppError = require('../../utils/AppError'); const pickUploadedFile = (req) => { if (req.file) return req.file; if (Array.isArray(req.files) && req.files.length) return req.files[0]; if (req.files && typeof req.files === 'object') { return req.files.file?.[0] || req.files['filepond-image']?.[0] || Object.values(req.files).flat().find(Boolean) || null; } return null; }; exports.uploadTemp = catchAsync(async (req, res, next) => { const uploaded = pickUploadedFile(req); if (!uploaded) { return next(new AppError('FILE_REQUIRED')); } const result = await fileService.uploadTempFile(uploaded); // 200 matches the working FilePond Node.js uploader (2xx is required) return successResponse(res, 200, 'File uploaded to temp bucket successfully', result); }); exports.getSignedUrl = catchAsync(async (req, res, next) => { const { filename } = req.params; const { bucket } = req.query; const result = await fileService.getPresignedUrl(filename, bucket); return successResponse(res, 200, 'Temporary presigned URL generated successfully', result); }); exports.streamFile = catchAsync(async (req, res, next) => { const key = req.query.key || req.params.filename; const bucket = req.query.bucket; if (!key) { return next(new AppError('VALIDATION_FAILED', null, 'Filename is required')); } const { buffer, contentType } = await fileService.getFileContent(key, bucket); res.set('Content-Type', contentType); res.set('Cache-Control', 'private, max-age=60'); return res.status(200).send(buffer); }); exports.deleteFile = catchAsync(async (req, res, next) => { const { filename } = req.params; const { bucket } = req.query; await fileService.deleteFile(filename, bucket); return successResponse(res, 200, 'File deleted successfully'); });