sc-theme-builder/lib/headers.js
2026-07-01 20:07:28 -05:00

54 lines
2.2 KiB
JavaScript

// lib/headers.js
// headers(cfg) injection + per-role / layout-mode suppression (ARCHITECTURE.md 7.6)
//
// Grounding (real Saltcorn source under packages/):
// - server/wrapper.js:137 -- a header is emitted only when `h.only_if(req) === true`
// (strict equality), so every predicate here returns an explicit boolean.
// - saltcorn-data/db/state.ts:1122-1135 -- only `script` URLs are de-duped; `css`
// headers are not, so distinct per-role ?v/&theme/&role links coexist.
const { CSS_ROUTE } = require("./constants");
const {
getActiveThemeId,
getActiveByRole,
activeHashHint,
isLayoutMode,
requestRendersViaThemeBuilder,
} = require("./cfgReaders");
function headers(cfg) {
const def = getActiveThemeId(cfg);
const byRole = getActiveByRole(cfg);
const list = [];
if (!def) return list;
// ONE header; only_if decides per-request whether this role gets the overlay.
list.push({
css: `${CSS_ROUTE}?v=${activeHashHint(cfg)}`,
only_if: (req) => {
const role = req.user?.role_id ?? 100;
// LAYOUT MODE: suppress ONLY for requests that actually render via theme-builder.
// Detected by replicating getLayout's fallback precedence (cfgReaders), NOT by reading
// getLayout().pluginName -- the last-installed fallback omits pluginName, so an uncovered
// role would otherwise be double-themed (overlay + wrap()). (folded review fix)
if (isLayoutMode(cfg) && requestRendersViaThemeBuilder(req)) return false;
// role with an explicit override gets its own header below, not this one
return byRole[role] === undefined || byRole[role] === def;
},
});
// per-role overlays for explicit overrides (Phase 1)
for (const [roleStr, tid] of Object.entries(byRole)) {
if (tid === def) continue;
const role = Number(roleStr);
list.push({
css: `${CSS_ROUTE}?v=${activeHashHint(cfg)}&theme=${encodeURIComponent(tid)}&role=${role}`,
only_if: (req) => {
if (isLayoutMode(cfg) && requestRendersViaThemeBuilder(req)) return false;
return (req.user?.role_id ?? 100) === role; // MUST strictly return true (wrapper.js:137)
},
});
}
return list;
}
module.exports = { headers };