rowboat/apps/rowboat/app/api/uploads/[fileId]/route.ts
2025-08-17 08:06:17 +05:30

86 lines
3 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import path from 'path';
import fs from 'fs/promises';
import fsSync from 'fs';
import { container } from '@/di/container';
import { IDataSourceDocsRepository } from '@/src/application/repositories/data-source-docs.repository.interface';
const UPLOADS_DIR = process.env.RAG_UPLOADS_DIR || '/uploads';
const dataSourceDocsRepository = container.resolve<IDataSourceDocsRepository>('dataSourceDocsRepository');
// PUT endpoint to handle file uploads
export async function PUT(request: NextRequest, props: { params: Promise<{ fileId: string }> }) {
const params = await props.params;
const fileId = params.fileId;
if (!fileId) {
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
}
const filePath = path.join(UPLOADS_DIR, fileId);
try {
const data = await request.arrayBuffer();
await fs.writeFile(filePath, new Uint8Array(data));
return NextResponse.json({ success: true });
} catch (error) {
console.error('Error saving file:', error);
return NextResponse.json(
{ error: 'Failed to save file' },
{ status: 500 }
);
}
}
// GET endpoint to handle file downloads
export async function GET(request: NextRequest, props: { params: Promise<{ fileId: string }> }) {
const params = await props.params;
const fileId = params.fileId;
if (!fileId) {
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
}
// get mimetype from database
const doc = await dataSourceDocsRepository.fetch(fileId);
if (!doc) {
return NextResponse.json({ error: 'File not found' }, { status: 404 });
}
if (doc.data.type !== 'file_local') {
return NextResponse.json({ error: 'File is not local' }, { status: 400 });
}
const mimeType = 'application/octet-stream';
const fileName = doc.data.name;
try {
// strip uploads dir from path
const filePath = path.join(UPLOADS_DIR, doc.data.path.split('/api/uploads/')[1]);
// Check if file exists
await fs.access(filePath);
// Create a readable stream
const nodeStream = fsSync.createReadStream(filePath);
// Convert Node.js stream to Web stream
const webStream = new ReadableStream({
start(controller) {
nodeStream.on('data', (chunk) => controller.enqueue(chunk));
nodeStream.on('end', () => controller.close());
nodeStream.on('error', (err) => controller.error(err));
}
});
return new NextResponse(webStream, {
status: 200,
headers: {
'Content-Type': mimeType,
'Content-Disposition': `attachment; filename="${fileName}"`,
},
});
} catch (error) {
console.error('Error reading file:', error);
return NextResponse.json(
{ error: 'File not found' },
{ status: 404 }
);
}
}