// app/api/download/route.ts import { NextResponse } from 'next/server'; import fs from 'fs'; import { RESOURCE_PATH } from '@/lib/constants'; import { validatePath } from '@/lib/fs-utils'; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const project = searchParams.get('project'); const version = searchParams.get('version'); const filename = searchParams.get('filename'); if (!project || !version || !filename) { return NextResponse.json( { error: 'Project, version, and filename parameters are required' }, { status: 400 } ); } // Validate the full path to prevent path traversal attacks const filePath = validatePath(RESOURCE_PATH, project, version, 'apks', filename); try { // Check if file exists if (!fs.existsSync(filePath)) { return NextResponse.json( { error: 'File not found' }, { status: 404 } ); } // Use streaming to avoid loading entire file into memory const fileStream = fs.createReadStream(filePath); const stat = await fs.promises.stat(filePath); return new NextResponse(fileStream as any, { headers: { 'Content-Type': 'application/vnd.android.package-archive', 'Content-Disposition': `attachment; filename="${encodeURIComponent(filename)}"`, 'Content-Length': stat.size.toString(), }, }); } catch (error) { return NextResponse.json( { error: 'Failed to download file' }, { status: 500 } ); } }