@@ -31,9 +31,20 @@ router.route('/dump/structures')
3131 requireRoles ( [ 'admin' ] ) ,
3232 async ( req , res ) => {
3333 try {
34- res . setHeader ( 'Content-Type' , 'application/x-ndjson' ) ;
35- res . setHeader ( 'Content-Encoding' , 'gzip' ) ;
36- res . setHeader ( 'Content-Disposition' , 'attachment; filename="structures-dump.ndjson.gz"' ) ;
34+ // Check if it's a browser download (query param ?download=true for raw .gz file)
35+ const isBrowserDownload = req . query . download === 'true' ;
36+
37+ if ( isBrowserDownload ) {
38+ // For browser downloads: send as raw gzip file (not auto-decompressed)
39+ res . setHeader ( 'Content-Type' , 'application/gzip' ) ;
40+ res . setHeader ( 'Content-Disposition' , 'attachment; filename="structures-dump.ndjson.gz"' ) ;
41+ } else {
42+ // For programmatic access: browsers will auto-decompress, Python sees compressed
43+ res . setHeader ( 'Content-Type' , 'application/x-ndjson' ) ;
44+ res . setHeader ( 'Content-Encoding' , 'gzip' ) ;
45+ res . setHeader ( 'Content-Disposition' , 'attachment; filename="structures-dump.ndjson.gz"' ) ;
46+ }
47+
3748 res . setHeader ( 'Transfer-Encoding' , 'chunked' ) ;
3849 res . setHeader ( 'Cache-Control' , 'no-cache' ) ;
3950
@@ -56,8 +67,13 @@ router.route('/dump/structures')
5667 res
5768 ) ;
5869 } catch ( error ) {
59- console . error ( error ) ;
60- return res . status ( 500 ) . json ( { error : 'Failed to generate dump' , message : error . message } ) ;
70+ // Only send error if headers haven't been sent
71+ if ( ! res . headersSent ) {
72+ res . status ( 500 ) . json ( { error : 'Failed to generate dump' , message : error . message } ) ;
73+ } else {
74+ // If streaming has started, we can only close the connection
75+ res . end ( ) ;
76+ }
6177 }
6278 } ,
6379 ] ) ;
0 commit comments