The options, or just the template root (unsigned, no escaping).
Whether {{name}} values are HTML-escaped.
The fragment allowlist (empty allows every template).
Maximum template file size in bytes.
The template root directory.
The signing options (never printed: see Setup.toJSON).
Whether templates are reloaded on change.
Validate the root and the signing keys, load and parse every template,
and start the watcher when watch is set.
The ready engine.
AnzaError VALIDATION when the root does not exist;
CRYPTO for a missing, short or malformed signing key;
TEMPLATE for a template that does not parse or is larger than
maxTemplateBytes; NOT_FOUND for a template that cannot be read.
The options with key material replaced by <redacted> (see redact), safe to log.
Check that the template root exists.
AnzaError VALIDATION when root is empty or does not exist.
Configures and starts an Engine: Setup.run checks the template root and the signing keys, then loads and parses every template once.
Remarks
Template layout. Templates are plain
.htmlfiles underroot, addressed by their relative path:layout/shell.html{{content}}.pages/home.html/.pages/<route>.html/<route>(fallbackpages/index.html, elseNOT_FOUND).feed/card.html(limited byfragmentswhen set).Parse once.
run()reads every.htmlfile, splits it into static strings and{{name}}/{{{name}}}placeholders (extract) and builds one render function per template (compile). There is no parsing or regular expression work at request time, and request input never reaches the filesystem: lookups only use the in-memory cache. Symlinked directories are not followed, symlinked files that resolve outside the root are skipped, and errors name the template, never the absolute path.Keys. Signing keys are validated here, once. Each of these makes
run()reject with aCRYPTOerror, so a running engine never sends unsigned envelopes by accident: an HMACsecretthat is missing or shorter than 32 bytes; an Ed25519privateKeythat is missing or not a 32-byte seed, a 64-char lowercase hex seed, a PEM string or aKeyObject; apublicKeythat does not match the private key.Setup, Engine and Signer never print key material:inspectandJSON.stringifyshow<redacted>.Runtimes. The engine uses Node.js built-ins (
node:fs,node:crypto) and has no runtime dependencies. It runs on Node.js 18+ (tested), and on Bun and Deno through their Node compatibility. Runtimes without a filesystem (Cloudflare Workers and similar edge isolates) are not supported; there, only the template core (extract, compile, escapeHtml, stringify) works.Example: HMAC-signed engine
Example: Ed25519 with a generated key pair