diff --git a/src/routes/upload.ts b/src/routes/upload.ts index 8c618a6..17fb3d1 100644 --- a/src/routes/upload.ts +++ b/src/routes/upload.ts @@ -1,3 +1,4 @@ +import { createReadStream, unlinkSync } from 'node:fs'; import { eq } from 'drizzle-orm'; import { nanoid } from 'nanoid'; import { db, files as fileSchema } from '../db'; @@ -33,6 +34,7 @@ export const handleUpload = async (req: Request): Promise => { }; const handleMultipartUpload = async (req: Request): Promise => { + let tempPath = ''; try { const formData = await req.formData(); const file = formData.get('file'); @@ -88,7 +90,12 @@ const handleMultipartUpload = async (req: Request): Promise => { return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 }); } - const result = await forwardToStorage(fileBuffer, finalFileName, fileType); + // Write file to disk temporarily + tempPath = `/tmp/teleuploader-${nanoid()}`; + await Bun.write(tempPath, fileBuffer); + + const fileStream = createReadStream(tempPath); + const result = await forwardToStorage(fileStream, finalFileName, fileType); const bot = getBot(); const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any; @@ -129,10 +136,20 @@ const handleMultipartUpload = async (req: Request): Promise => { } catch (error: any) { logger.error('Multipart upload error', { error: error.message }); return Response.json({ error: error.message }, { status: 500 }); + } finally { + if (tempPath) { + const p = tempPath; + setTimeout(() => { + try { + unlinkSync(p); + } catch {} + }, 50); + } } }; const handleJSONUpload = async (req: Request): Promise => { + let tempPath = ''; try { const { file, fileName = 'file' } = (await req.json()) as any; @@ -195,7 +212,12 @@ const handleJSONUpload = async (req: Request): Promise => { return Response.json({ error: `File size exceeds ${fileType} limit` }, { status: 400 }); } - const result = await forwardToStorage(fileBytes, finalFileName, fileType); + // Write file to disk temporarily + tempPath = `/tmp/teleuploader-${nanoid()}`; + await Bun.write(tempPath, fileBytes); + + const fileStream = createReadStream(tempPath); + const result = await forwardToStorage(fileStream, finalFileName, fileType); const bot = getBot(); const fileInfo = (await bot.telegram.getFile(result.telegramFileId)) as any; @@ -236,5 +258,14 @@ const handleJSONUpload = async (req: Request): Promise => { } catch (error: any) { logger.error('JSON upload error', { error: error.message }); return Response.json({ error: error.message }, { status: 500 }); + } finally { + if (tempPath) { + const p = tempPath; + setTimeout(() => { + try { + unlinkSync(p); + } catch {} + }, 50); + } } }; diff --git a/test/upload.test.ts b/test/upload.test.ts index 68c354f..2827585 100644 --- a/test/upload.test.ts +++ b/test/upload.test.ts @@ -47,8 +47,9 @@ mock.module('../src/db/index', () => ({ })); // Mock nanoid +let nanoidCounter = 0; mock.module('nanoid', () => ({ - nanoid: () => 'mocked-nanoid-id', + nanoid: () => `mocked-nanoid-id-${nanoidCounter++}`, })); // Mock telegram utils @@ -124,7 +125,7 @@ describe('Upload Route Handler', () => { expect(res.status).toBe(200); const body = await res.json(); - expect(body.public_id).toBe('mocked-nanoid-id'); + expect(body.public_id).toContain('mocked-nanoid-id'); expect(body.telegram_file_id).toBe('tg-file-id-123'); expect(body.telegram_file_unique_id).toBe('tg-unique-id-abc'); expect(body.file_name).toBe('test.png'); @@ -161,7 +162,7 @@ describe('Upload Route Handler', () => { const res = await handleUpload(req); expect(res.status).toBe(200); const body = await res.json(); - expect(body.public_id).toBe('mocked-nanoid-id'); + expect(body.public_id).toContain('mocked-nanoid-id'); expect(body.file_name).toBe('test_multi.png'); });