43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
import { FastifyPluginAsync } from 'fastify'
|
|
import { createWriteStream, mkdirSync } from 'fs'
|
|
import { join, extname } from 'path'
|
|
import { randomUUID } from 'crypto'
|
|
import { pipeline } from 'stream/promises'
|
|
|
|
const UPLOADS_DIR = process.env.UPLOADS_DIR ?? join(process.cwd(), 'uploads')
|
|
|
|
// Ensure uploads directory exists
|
|
mkdirSync(UPLOADS_DIR, { recursive: true })
|
|
|
|
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
|
|
const MAX_SIZE = 10 * 1024 * 1024 // 10MB
|
|
|
|
const upload: FastifyPluginAsync = async (fastify) => {
|
|
// POST /api/upload — upload a single image, returns { url }
|
|
fastify.post(
|
|
'/api/upload',
|
|
{ onRequest: [fastify.authenticate] },
|
|
async (request, reply) => {
|
|
const data = await request.file({ limits: { fileSize: MAX_SIZE } })
|
|
if (!data) return reply.code(400).send({ error: 'No file provided' })
|
|
|
|
if (!ALLOWED_TYPES.includes(data.mimetype)) {
|
|
return reply.code(400).send({ error: 'Only images allowed (jpg, png, webp, gif)' })
|
|
}
|
|
|
|
const ext = extname(data.filename) || '.jpg'
|
|
const filename = `${randomUUID()}${ext}`
|
|
const filepath = join(UPLOADS_DIR, filename)
|
|
|
|
await pipeline(data.file, createWriteStream(filepath))
|
|
|
|
const host = (request.headers['x-forwarded-proto'] ?? 'https') + '://' +
|
|
(request.headers['x-forwarded-host'] ?? request.headers.host ?? 'api.hotelsync.ru')
|
|
|
|
return { url: `${host}/uploads/${filename}` }
|
|
},
|
|
)
|
|
}
|
|
|
|
export default upload
|