Anza Engine: Rust Reference
The Rust engine (crate anza) renders server-templated UI (STUI) from plain
.html files: full HTML pages for the first load, and JSON envelopes
({ v: 2, slot, ts, html, sig?, css? }) for fragments, fetches and SSE/WebSocket
pushes. Envelopes can be signed with HMAC-SHA256 or Ed25519 over the v2
signature message, and checked with anza::verify_envelope. The behaviour is
shared with the TypeScript and Python engines (see the
Engine Contract).
┌─────────────────┐ Full page (HTML, open DSD) ┌─────────────────┐
│ Rust server ├────────────────────────────────────────►│ Browser │
│ (crate `anza`) │ Envelopes over fetch / SSE / WS │ (custom elements│
│ ├────────────────────────────────────────►│ + your code) │
└─────────────────┘ { v, slot, ts, html, sig? } └─────────────────┘
The CLI is a different crate:
anza-cli(its binary isanza). These docs cover only the engine crateanza.
Key points
- Small core.
default = []inCargo.toml: no web framework and no async runtime unless you enable theaxum,actixorwatchfeatures. - Parse once.
Setup::run()reads every.htmlfile under the root and splits it into static byte chunks and{{name}}placeholders. Rendering only copies chunks and parameter values into one pre-sized buffer. - Placeholders only. The syntax is
{{name}}(value) and{{{name}}}(raw). There are no loops, conditionals, filters or includes. By default values are inserted without HTML escaping: escape anything that comes from users withanza::escape_html, or setsetup.escape = trueso that{{name}}is escaped (see Rendering Pipeline). - Two outputs.
Pagereturns aDocument(full HTML).FragmentandStreamreturn anEnvelope. - Signing.
SignMode::HmacandSignMode::Ed25519add a hexsigto every envelope. Keys are validated inSetup::run().anza::verify_envelopechecks received envelopes on a server or edge. The browser library does not verify signatures for you (see Cryptographic Verification). - Errors.
anza::Errorhas the variantsValidation,NotFound,Template,CryptoandInternal. They display as[Anza:CODE] message, andError::code()returns the code (NOT_FOUND, …).
Quick example
[dependencies]
anza = "0.6"
serde_json = "1"
use anza::{Fragment, Page, Setup};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Load and parse ./templates once.
let mut setup = Setup::new("templates");
setup.signing = Setup::hmac(b"super-secret-origin-key-32-bytes");
let engine = setup.run()?;
// 2. Full page: templates/pages/home.html inside templates/layout/shell.html.
let doc = Page::new("/").param("title", "Home Page").run(&engine)?;
println!("{}", doc.html);
// 3. Signed fragment envelope from templates/feed/card.html.
let env = Fragment::new("feed/card.html", "main")
.param("title", "Real-Time Update")
.param("author", "Alex")
.run(&engine)?;
println!("{}", serde_json::to_string_pretty(&env)?);
Ok(())
}
Root exports
anza::{Setup, Page, Fragment, Stream, Engine, SignMode, Params, Data, escape_html, verify_envelope, VerifyKey, VerifyOptions, Document, Envelope, Manifest, Error, Result}. Everything else is reached through its module
path (anza::crypto::…, anza::stream::…, anza::render::…,
anza::engine::…, anza::adapters::…).