// Schreibt /_headers aus src/headers.json -- dieselben Regeln, die der // Worker auf seine eigenen Antworten setzt (src/worker.ts). Cloudflare liest // _headers nur im Root des Asset-Ordners und nur fuer Asset-Antworten. // Aufruf: node scripts/headers.mjs build/site import { readFileSync, writeFileSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const regeln = JSON.parse(readFileSync(join(root, "src/headers.json"), "utf8")); const ziel = process.argv[2]; if (!ziel) { console.error("Aufruf: node scripts/headers.mjs "); process.exit(2); } function csp(prefix) { const alle = { ...regeln.csp_basis, ...(prefix ? regeln.csp_sammlung[prefix] : {}) }; return Object.entries(alle) .map(([name, d]) => `${name} ${d.werte.join(" ")}`) .join("; "); } const zeilen = ["# Erzeugt von scripts/headers.mjs aus src/headers.json -- nicht von Hand aendern.", "/*"]; for (const [name, h] of Object.entries(regeln.global)) zeilen.push(` ${name}: ${h.wert}`); zeilen.push(` Content-Security-Policy: ${csp(null)}`, ""); for (const prefix of Object.keys(regeln.csp_sammlung)) { // Mehrere passende Regeln werden zusammengefuehrt; ohne "!" stuenden zwei // CSP-Header da und der Browser wendete beide (also die strengere) an. zeilen.push(`${prefix}*`, " ! Content-Security-Policy", ` Content-Security-Policy: ${csp(prefix)}`, ""); } // Cloudflare: hoechstens 2.000 Zeichen je Zeile, 100 Regeln. for (const z of zeilen) { if (z.length > 2000) { console.error(`headers: Zeile laenger als 2000 Zeichen: ${z.slice(0, 60)}...`); process.exit(1); } } writeFileSync(join(ziel, "_headers"), zeilen.join("\n")); console.error(`headers: ${join(ziel, "_headers")} geschrieben (${Object.keys(regeln.csp_sammlung).length + 1} Regeln)`);