mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
fix(atlas): gzip-compress responses so large country GeoJSON loads behind reverse proxies (#1262)
The admin-0 country GeoJSON served at /api/addons/atlas/countries/geo is ~30 MB uncompressed. With no compression in the request pipeline the transfer aborts (~8s, net::ERR_FAILED despite a 200) behind reverse proxies / Cloudflare Tunnel, so the Atlas map never colours visited countries. LAN is unaffected. Add the `compression` middleware to the shared applyGlobalMiddleware pipeline (gzip brings ~30 MB down to ~4 MB). text/event-stream is excluded so the /mcp StreamableHTTP (SSE) transport is not buffered. Adds BOOT-008 asserting content-encoding: gzip on the geo endpoint. Fixes #1254 Co-authored-by: pai <pai@stabpablo.eu>
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
"archiver": "^6.0.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"better-sqlite3": "^12.8.0",
|
||||
"compression": "^1.8.0",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.1",
|
||||
@@ -72,6 +73,7 @@
|
||||
"@types/archiver": "^7.0.0",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/better-sqlite3": "^7.6.13",
|
||||
"@types/compression": "^1.8.0",
|
||||
"@types/cookie-parser": "^1.4.10",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/express": "^4.17.25",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import compression from 'compression';
|
||||
import cors from 'cors';
|
||||
import helmet from 'helmet';
|
||||
import cookieParser from 'cookie-parser';
|
||||
@@ -28,6 +29,21 @@ export function applyGlobalMiddleware(
|
||||
app.set('trust proxy', Number.parseInt(process.env.TRUST_PROXY) || 1);
|
||||
}
|
||||
|
||||
// Compress responses (gzip via Accept-Encoding). The Atlas admin-0 country
|
||||
// GeoJSON is ~30 MB uncompressed, which stalls/aborts (~8s → net::ERR_FAILED)
|
||||
// behind reverse proxies and Cloudflare Tunnel (#1254); gzip brings it to ~4 MB.
|
||||
// SSE responses (the /mcp StreamableHTTP transport) must NOT be buffered, so
|
||||
// they are excluded explicitly.
|
||||
app.use(
|
||||
compression({
|
||||
filter: (req, res) => {
|
||||
const type = res.getHeader('Content-Type');
|
||||
if (typeof type === 'string' && type.includes('text/event-stream')) return false;
|
||||
return compression.filter(req, res);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const allowedOrigins = process.env.ALLOWED_ORIGINS
|
||||
? process.env.ALLOWED_ORIGINS.split(',').map(o => o.trim()).filter(Boolean)
|
||||
: null;
|
||||
|
||||
@@ -122,4 +122,17 @@ describe('BOOTSTRAP (F6) — unified NestJS app serves the whole surface', () =>
|
||||
else process.env.NODE_ENV = prev;
|
||||
}
|
||||
});
|
||||
|
||||
it('BOOT-008 — large responses are gzip-compressed (Atlas country GeoJSON, #1254)', async () => {
|
||||
// The admin-0 country GeoJSON is multi-MB; without compression it stalls
|
||||
// behind reverse proxies / Cloudflare Tunnel. Proves applyGlobalMiddleware
|
||||
// gzips it on the wire.
|
||||
const { user } = createUser(testDb);
|
||||
const res = await request(instance)
|
||||
.get('/api/addons/atlas/countries/geo')
|
||||
.set('Accept-Encoding', 'gzip')
|
||||
.set('Cookie', authCookie(user.id));
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.headers['content-encoding']).toBe('gzip');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user