v0.12.0 - Compile-Time Verification & Contract Manifests
Compile-Time Verification & Contract Manifests
This release adds two new compile-time analysis passes that turn zigttp from "a fast small JS runtime" into "a runtime that understands what your handler is allowed to do."
Handler Verification (-Dverify)
Statically proves handler correctness at build time:
- Exhaustive returns - every code path returns a Response (missing
elsebranches,switchwithoutdefault) - Result safety - Result values from
jwtVerify,validateJson, etc. must have.okchecked before.valueis accessed - Unreachable code - statements after unconditional returns are flagged
This works because zigttp's JS subset eliminates all non-trivial control flow. The IR tree IS the control flow graph. Verification is a recursive tree walk, not a fixpoint dataflow analysis.
$ zig build -Dhandler=handler.ts -Dverify
verify error: not all code paths return a Response
--> handler.ts:2:17
= help: ensure every branch (if/else, switch/default) ends with a return statement
Contract Manifest (-Dcontract)
Emits a machine-readable contract.json describing what your handler is allowed to do:
- Virtual module imports and which functions are used
- Literal env var names (
"dynamic": falsewhen all calls use string literals) - Outbound hosts extracted from
fetchSync()URL arguments - Cache namespace strings from
cacheGet/cacheSet/etc. - Verification results (when combined with
-Dverify)
{
"modules": ["zigttp:auth", "zigttp:cache"],
"functions": { "zigttp:auth": ["jwtVerify"], "zigttp:cache": ["cacheGet"] },
"env": { "literal": ["JWT_SECRET"], "dynamic": false },
"egress": { "hosts": ["api.example.com"], "dynamic": false },
"cache": { "namespaces": ["sessions"], "dynamic": false }
}Non-literal arguments honestly report "dynamic": true. No other JS runtime can do this because full JS is not statically analyzable.
Also in This Release
- fetchSync - native outbound HTTP bridge with
fetchSync(url, init?)returning response-shaped objects - Build fixes - transpiler output includes
dep_count/dep_bytecodes;mkdiruses absolute path for Zig 0.16 sandbox compatibility - Memory safety -
errdeferguards on all dupe-before-append paths in contract builder; proper cleanup on error inContractBuilder.deinit() - JSON fix -
\uescape in contract serializer now correctly emits hex instead of decimal - Code dedup -
findHandlerFunctionshared between precompile tool and verifier; three extract functions unified intoextractLiteralArg
Build Commands
# Verify + contract + AOT + optimized (the full pipeline)
zig build -Doptimize=ReleaseFast -Dhandler=handler.ts -Dverify -Dcontract -DaotDocumentation
- Verification specification
- README updated with Compile-Time Toolchain section
- User Guide updated with verification and contract sections