import { createReadStream, statSync } from 'node:fs'; import type { IncomingMessage, ServerResponse } from 'node:http'; import { pipeline } from 'node:stream'; import { BUILDINGS } from '../src/constants/buildings.ts'; // Only serves the precomputed building buffer; other assets use Vite's defaults. export function buildingCompressionMiddleware(publicDirectory: URL) { const path = new URL(BUILDINGS.assetBufferUrl.slice(1) + '.gz', publicDirectory); return (request: IncomingMessage, response: ServerResponse, next: () => void) => { if (request.url?.split('?')[0] !== BUILDINGS.assetBufferUrl || !['GET', 'HEAD'].includes(request.method ?? '')) return next(); const vary = response.getHeader('Vary'); response.setHeader('Vary', vary ? `${vary}, Accept-Encoding` : 'Accept-Encoding'); const encodings = (request.headers['accept-encoding'] ?? '').toLowerCase().split(',').map(entry => { const [name, ...parameters] = entry.trim().split(';'); const quality = parameters.find(value => value.trim().startsWith('q=')); return { name, quality: quality ? Number(quality.trim().slice(2)) : 1 }; }); const accepted = encodings.find(entry => entry.name === 'gzip') ?? encodings.find(entry => entry.name === '*'); if (!accepted || !(accepted.quality > 0) || request.headers.range) return next(); let size: number; try { size = statSync(path).size; } catch { return next(); } response.setHeader('Content-Encoding', 'gzip'); response.setHeader('Content-Type', 'application/octet-stream'); response.setHeader('Content-Length', size); response.setHeader('Cache-Control', 'no-cache'); if (request.method === 'HEAD') { response.end(); return; } pipeline(createReadStream(path), response, error => { if (error) response.destroy(error); }); }; }