Server-templated UI (STUI) for Node.js, Bun and Deno: full HTML pages for
the first load, and JSON envelopes ({ v: 2, slot, ts, html, sig?, css? })
for fragments, fetches and SSE / WebSocket pushes, optionally signed with
HMAC-SHA256 or Ed25519.
The behaviour (template names, page resolution, value conversion, escaping,
the envelope format, signature v2 and error codes) is shared with the Rust
and Python engines and specified in the
Engine Contract.
┌─────────────────┐ Full page (HTML, open DSD) ┌─────────────────┐
│ Node / Bun / ├────────────────────────────────────────►│ Browser │
│ Deno server │ Envelopes over fetch / SSE / WS │ (custom elements│
│ (@anzaui/engine)├────────────────────────────────────────►│ + your code) │
└─────────────────┘ { v, slot, ts, html, sig? } └─────────────────┘
// 3. Signed fragment envelope from templates/feed/card.html. constenvelope=awaitnewFragment('feed/card.html', 'feed', { title:'Live update' }).run(engine);
// 4. Whoever relays the envelope can check it. verifyEnvelope({ mode:'hmac', secret:process.env.ANZA_SECRET! }, envelope, { maxAgeSecs:60, slot:'feed' });
Guide
Engine: Setup loads the template root and validates keys,
giving an Engine. The template layout (layout/shell.html,
pages/…, fragments) is described on Setup.
Adapters: htmlResponse / jsonResponse for
web-standard Responses, and the Hono, Express and Fastify helpers
(@anzaui/engine/adapters/*, also the adapters namespace).
No auto-escaping by default.{{name}} and {{{name}}} insert
values as-is unless the engine runs with escape: true. Escape anything
that comes from users with escapeHtml before binding it, or set
escape: true so {{name}} is escaped and only {{{name}}} is raw.
Keys are checked at setup. A missing or short HMAC secret (under 32
bytes) or a malformed Ed25519 key makes Setup.run throw CRYPTO;
the engine never falls back to unsigned envelopes, and never prints keys.
Signature v2 covers ts, slot, html and css in a
length-prefixed, domain-separated message (signatureMessage).
Verify on receipt with verifyEnvelope: it checks the version,
freshness, the target slot and the signature in constant time. The Anza
browser library does not verify signatures for you.
Request input never reaches the filesystem. Templates are loaded once;
lookups are validated names in an in-memory cache (validName).
Server-templated UI (STUI) for Node.js, Bun and Deno: full HTML pages for the first load, and JSON envelopes (
{ v: 2, slot, ts, html, sig?, css? }) for fragments, fetches and SSE / WebSocket pushes, optionally signed with HMAC-SHA256 or Ed25519.The behaviour (template names, page resolution, value conversion, escaping, the envelope format, signature v2 and error codes) is shared with the Rust and Python engines and specified in the Engine Contract.
Quick start
Guide
layout/shell.html,pages/…, fragments) is described on Setup.{{name}}and{{{name}}}placeholders (extract, compile); values are converted with stringify.Responses, and the Hono, Express and Fastify helpers (@anzaui/engine/adapters/*, also the adapters namespace).Security
{{name}}and{{{name}}}insert values as-is unless the engine runs withescape: true. Escape anything that comes from users with escapeHtml before binding it, or setescape: trueso{{name}}is escaped and only{{{name}}}is raw.CRYPTO; the engine never falls back to unsigned envelopes, and never prints keys.ts,slot,htmlandcssin a length-prefixed, domain-separated message (signatureMessage).