Files
Webklar-Kundenbereich/analytics/src/assets.js
T
2026-10-01 09:58:10 +00:00

61 lines
2.4 KiB
JavaScript

// GET/HEAD /a/w.js und /a/h.js (öffentlicher Listener): generierte Client-Skripte aus client/dist/.
// Einmal beim Start in den Speicher geladen (roh + gzip); fehlt eine Datei, antwortet der Pfad mit 503.
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { gzipSync } from 'node:zlib';
import crypto from 'node:crypto';
const DEFAULT_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'client', 'dist');
const FILES = { '/a/w.js': 'w.js', '/a/h.js': 'h.js' };
export function createAssets({ distDir = DEFAULT_DIR, log = console } = {}) {
const assets = new Map();
for (const [path, file] of Object.entries(FILES)) {
try {
const raw = readFileSync(join(distDir, file));
assets.set(path, { raw, gz: gzipSync(raw, { level: 9 }), etag: `"${crypto.createHash('sha256').update(raw).digest('hex')}"` });
} catch (e) {
log.error(`Analytics: Skript ${file} fehlt in ${distDir} (${e.code || e.message}); ${path} antwortet mit 503`);
}
}
// true, wenn die Anfrage ein Skript betraf.
return function handle(req, res, pathname) {
if (!(pathname in FILES)) return false;
if (req.method !== 'GET' && req.method !== 'HEAD') {
res.writeHead(405, { Allow: 'GET, HEAD' });
res.end();
return true;
}
const a = assets.get(pathname);
if (!a) {
res.writeHead(503, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store' });
res.end(req.method === 'HEAD' ? '' : JSON.stringify({ error: 'Skript nicht verfügbar' }));
return true;
}
const headers = {
'Content-Type': 'text/javascript; charset=utf-8',
'Cache-Control': 'public, max-age=3600',
ETag: a.etag,
Vary: 'Accept-Encoding',
'X-Content-Type-Options': 'nosniff',
'Cross-Origin-Resource-Policy': 'cross-origin',
'Access-Control-Allow-Origin': '*',
};
const inm = req.headers['if-none-match'];
if (inm && inm.split(',').some((t) => t.trim().replace(/^W\//, '') === a.etag)) {
res.writeHead(304, headers);
res.end();
return true;
}
const gzip = /\bgzip\b/i.test(req.headers['accept-encoding'] || '');
const body = gzip ? a.gz : a.raw;
if (gzip) headers['Content-Encoding'] = 'gzip';
headers['Content-Length'] = body.length;
res.writeHead(200, headers);
res.end(req.method === 'HEAD' ? undefined : body);
return true;
};
}