'use strict'; // Copies frontend libraries from node_modules into public/vendor so the app // loads no remote scripts (works on a locked-down network, reproducible). const fs = require('fs'); const path = require('path'); const ROOT = path.join(__dirname, '..'); const OUT = path.join(ROOT, 'public', 'vendor'); const FILES = [ ['beercss/dist/cdn/beer.min.css', 'beer.min.css'], ['beercss/dist/cdn/beer.min.js', 'beer.min.js'], // Material Symbols icon fonts. beer.min.css references these by relative URL // (with a CDN fallback our CSP blocks), so they must sit beside it in /vendor. ['beercss/dist/cdn/material-symbols-outlined.woff2', 'material-symbols-outlined.woff2'], ['beercss/dist/cdn/material-symbols-rounded.woff2', 'material-symbols-rounded.woff2'], ['beercss/dist/cdn/material-symbols-sharp.woff2', 'material-symbols-sharp.woff2'], ['beercss/dist/cdn/material-symbols-subset.woff2', 'material-symbols-subset.woff2'], ['material-dynamic-colors/dist/cdn/material-dynamic-colors.min.js', 'material-dynamic-colors.min.js'], ['alpinejs/dist/cdn.min.js', 'alpine.min.js'], ]; fs.mkdirSync(OUT, { recursive: true }); let ok = 0; for (const [src, dest] of FILES) { const from = path.join(ROOT, 'node_modules', src); const to = path.join(OUT, dest); try { fs.copyFileSync(from, to); console.log(`vendored ${dest}`); ok++; } catch (e) { console.error(`FAILED to vendor ${src}: ${e.message}`); } } // Strip Beer CSS's remote @font-face fallbacks (jsdelivr CDN) so the icon font // resolves only to our local /vendor copy — no CDN load, no CSP violation. const beerCss = path.join(OUT, 'beer.min.css'); try { const before = fs.readFileSync(beerCss, 'utf8'); const after = before.replace(/,url\(https:\/\/cdn\.jsdelivr\.net[^)]*\)\s*format\("woff2"\)/g, ''); if (after !== before) { fs.writeFileSync(beerCss, after); console.log('stripped remote CDN font fallbacks from beer.min.css'); } } catch (e) { console.error(`WARN: could not post-process beer.min.css: ${e.message}`); } // material-dynamic-colors ships as an ES module: it sets the // globalThis.materialDynamicColors global (which Beer CSS's ui("theme") needs) // but ALSO ends with `export default ...`, which breaks classic