Compile-time asset server for the mailglass_admin preview dashboard.
Embeds priv/static/app.css, the concatenated Phoenix + Phoenix
LiveView JS bundles, the logo SVG, and the font woff2 subsets into
module attributes at compile time via @external_resource +
File.read!/1. Request-time cost is a single Plug.Conn.send_resp/3
from the module-attribute bytes — no filesystem I/O, no Plug.Static
in the chain.
Caching
Every response sets:
cache-control: public, max-age=31536000, immutableMD5 hashes of the bundles are exposed via css_hash/0 and js_hash/0
so layouts can emit cache-busting URLs like css-<hash>.css. New
builds produce new hashes → new URLs → bypass the immutable cache.
Phoenix + LiveView JS not charged to our tarball
phoenix.js and phoenix_live_view.js are read from their host
packages' priv/static/ directories via Application.app_dir/2.
Those bytes are NOT in mailglass_admin's Hex tarball — adopters
already pay for them via their own :phoenix + :phoenix_live_view
deps. The CONTEXT D-23 2 MB tarball gate only measures files we ship.
Font allowlist
call(conn, :font) hits the six-member @allowed_fonts guard before
constructing a filesystem path. A path traversal attempt like
GET /fonts/..%2F..%2Fetc%2Fpasswd fails the guard, falls through to
_ -> :error, and returns 404 with an empty body. The 2-weights-per-
family lock from 05-UI-SPEC lines 71-79 means the allowlist is small
and stable; adding a seventh weight requires updating BOTH the
@allowed_fonts list AND the brand test fixture.
Boundary classification: submodule auto-classifies into the
MailglassAdmin root boundary declared in lib/mailglass_admin.ex;
classify_to: is reserved for mix tasks and protocol implementations
and is not used here.
Summary
Functions
MD5 hash (lowercase hex) of the embedded priv/static/app.css bytes.
MD5 hash (lowercase hex) of the concatenated Phoenix + LiveView JS.
Functions
@spec css_hash() :: String.t()
MD5 hash (lowercase hex) of the embedded priv/static/app.css bytes.
Used by MailglassAdmin.Layouts.css_url/0 to build cache-busting URLs
like css-<hash>.css. The macro's get "/css-:md5", ... route
captures the hash in conn.path_params["md5"] but the handler does
not currently validate it — browsers never emit stale URLs because
the immutable cache drops when the rendered document URL changes.
@spec js_hash() :: String.t()
MD5 hash (lowercase hex) of the concatenated Phoenix + LiveView JS.
Same cache-busting role as css_hash/0.