You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add mailer.layout (a path) and mailer.partials (a { header, footer, button, styles } map of paths). Devkit ships the defaults in config/templates/_layout/, built on brand tokens: logo, colors, font, signature, contact footer and links.
render(key, params, { subject }) compiles the body, then the layout. The layout receives {{{body}}}, brand and subject, and subject fills <title>.
Use an isolated handlebars.create() instance, with partials registered from config.
Legacy passthrough: a template whose trimmed source starts with <!doctype or <html (case-insensitive) is sent unwrapped.
Layout and partial paths go through the resolver's containment check.
Acceptance criteria
A downstream replaces the whole layout, or a single partial, through its config only.
Full-document templates (all 15 today, plus any that exist only in a downstream) render byte-identical.
A body-only fragment gets the layout.
{{> button url=url label="..."}} is available to every template.
Nothing is registered on the global handlebars instance.
Tests
Wrap vs passthrough, including a leading-whitespace or uppercase doctype.
A partial override from a mocked downstream-shaped config.
Containment on layout and partial paths.
Escaping: params stay escaped and the body is injected once.
Activity
PierreBrisorgueil commentedon Oct 2, 2026
WIP — session 20261002T193722Z-13C22542, branch feat/4132-mailer-layout-partials, started 2026-10-02T19:37:22Z
PierreBrisorgueil commentedon Oct 2, 2026
merged via drain (Automerge: absent, --review: false) — PR #4166. Reviewers: CodeRabbit (1 finding fixed) + Claude fallback on later heads (CodeRabbit rate-limited).