Implement streaming file download for backup route

- Enhanced the backup server route to support streaming of large backup files using Node.js streams.
- Improved error handling for file access and added appropriate HTTP responses for missing parameters and inaccessible files.
- Updated response headers to include content length and type for better client handling.
This commit is contained in:
2026-04-15 17:54:28 -05:00
parent c3e50a2727
commit 50bbf7bdcc
2 changed files with 567 additions and 558 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,12 @@
import { env } from '$env/dynamic/private';
import { createReadStream } from 'node:fs';
import fs from 'node:fs/promises';
import path from 'node:path';
import { Readable } from 'node:stream';
import type { RequestHandler } from './$types';
// GET /backup?file=nombre.bak -> descarga el archivo físico desde BACKUP_PATH
export const GET = async ({ url }: { url: URL }) => {
// GET /backup?file=nombre.bak -> descarga el archivo físico desde BACKUP_PATH (streaming; soporta archivos muy grandes)
export const GET: RequestHandler = async ({ url, request }) => {
const fileName = url.searchParams.get('file');
if (!fileName) {
return new Response('Missing file parameter', { status: 400 });
@@ -28,14 +31,20 @@ export const GET = async ({ url }: { url: URL }) => {
console.error('Backup path is not a regular file:', filePath);
return new Response('Backup file not found or inaccessible', { status: 404 });
}
console.log('Serving backup file from', filePath);
const data = await fs.readFile(filePath);
console.log('Serving backup file from', filePath, 'size', st.size);
const nodeStream = createReadStream(filePath, { highWaterMark: 1024 * 1024 });
request.signal.addEventListener('abort', () => {
nodeStream.destroy();
});
const body = Readable.toWeb(nodeStream) as unknown as ReadableStream<Uint8Array>;
const headers = new Headers();
headers.set('Content-Type', 'application/octet-stream');
headers.set('Content-Disposition', `attachment; filename="${fileName}"`);
return new Response(data, { status: 200, headers });
} catch (e: any) {
console.error('Error serving backup file:', e?.message ?? e);
headers.set('Content-Length', String(st.size));
return new Response(body, { status: 200, headers });
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
console.error('Error serving backup file:', msg);
return new Response('Backup file not found or inaccessible', { status: 404 });
}
};