7.2 KiB
Mizan
Mizan is an Application Framework Interface (AFI). A single @client decorator on a
server function generates a typed frontend client; cache invalidation and caching are
handled by the protocol.
from mizan import client, ReactContext
UserContext = ReactContext('user')
# Context function — bundled into GET /api/mizan/ctx/user/
@client(context=UserContext)
def user_profile(request, user_id: int) -> UserShape:
return UserShape.query(lambda qs: qs.filter(pk=user_id))[0]
# Mutation — invalidation scoped automatically by matching param name
@client(affects=UserContext)
def update_profile(request, user_id: int, name: str) -> dict:
...
Adapters exist for Django, FastAPI, Rust/Axum, Tauri, and TypeScript. Django is the reference implementation; per-adapter support is inventoried below.
Status: Mizan is not production-tested. It passes its own test suites but has not been run in a production deployment. Treat it as pre-release.
Documentation
docs/— architecture references: AFI, SSR, cache keying, MWT, PSR vs. EdgeROADMAP.md·ISSUES.md— planned work and known gaps
Backend adapters
Every adapter implements the same AFI wire protocol. The matrix below inventories support per adapter, grouped to separate protocol guarantees from Django-specific features (forms, ORM projection, auth providers, SSR). A cell counts as supported only when that adapter wires the capability into its own dispatch surface, not merely that a shared core primitive exists.
Legend: ✅ supported · ◑ partial · ❌ not implemented · — not applicable to this transport
Protocol core
The surface every Mizan adapter implements.
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
RPC call dispatch ({result, invalidate}) |
✅ | ✅ | ✅ | ✅ ¹ | ✅ |
| Named-context bundle fetch | ✅ | ✅ | ✅ | ✅ | ✅ |
| Invalidation — JSON body | ✅ | ✅ | ✅ | ✅ | ✅ |
| Invalidation auto-scoping (three-tier) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Function discovery / registration | ✅ | ✅ | ✅ | ✅ | ✅ |
| Codegen IR export (KDL) | ✅ | ✅ | ✅ ⁶ | ✅ ⁶ | ❌ ⁸ |
File uploads (multipart, Upload type) |
✅ | ✅ | ❌ ⁹ | ❌ ⁹ | — ¹⁰ |
Edge, cache & enforcement
Protocol transports and guarantees co-equal with the body channel in the spec.
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
Invalidation — X-Mizan-Invalidate header |
✅ | ✅ | ❌ | — ¹ | ✅ |
Auth-guard enforcement (auth=… rejects) |
✅ | ✅ | ❌ ⁵ | ◑ ⁵ | ✅ ¹¹ |
| Origin-side HMAC cache | ✅ | ✅ | ❌ | ❌ | ✅ |
| Edge manifest export | ✅ | ❌ | ❌ | — | ✅ |
PSR (render_strategy in manifest) |
✅ | ❌ | ❌ | — | ✅ |
| Session / CSRF init endpoint | ✅ | ◑ ⁷ | ◑ ⁷ | — | ❌ |
Caveat: Rust/Axum and Tauri accept
auth=on a function but do not yet enforce it — do not rely onauth=for access control on those adapters.Django, FastAPI, and TypeScript share one auth/invalidation/cache implementation (
mizan_corefor the Python adapters; the same spec, pinned cross-language, for TS).
Stack extensions (Django)
Django ecosystem features Mizan wraps. Other adapters provide these only where the target stack calls for them.
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
| WebSocket channels (declared transport) | ✅ | ❌ | ◑ ² | ❌ | ❌ |
| Forms (schema / validate / submit) | ✅ | ❌ | ◑ ³ | ❌ | ❌ |
| Formsets | ✅ | ❌ | ❌ | ❌ | ❌ |
| API shapes (ORM query projection) ⁴ | ✅ | — | — | — | — |
| JWT auth (access / refresh) ¹² | ✅ | ✅ | ❌ | ❌ | ◑ ¹³ |
| MWT (edge identity token) | ✅ | ✅ | ❌ | — | ◑ ¹³ |
| SSR bridge | ✅ | ❌ | ❌ | — | ❌ |
| Auth-provider integration (allauth) | ✅ | ❌ | ❌ | ❌ | ❌ |
Notes
- Tauri's transport is Tauri IPC (a single
#[tauri::command]envelope), not HTTP. Invalidation rides in the JSON response body; there is no header channel. - Rust/Axum declares
Transport::Websocketin the IR/macro but routes no Axum WebSocket handler yet. - Rust/Axum carries
is_form/form_roletrait stubs but no validate/submit endpoint. - "API shapes" is Django's django-readers queryset projection — ORM-coupled. Every adapter carries typed input/output through the KDL IR; the projection primitive itself is Django-only.
- Tauri's
FunctionSpeccarriesauth/privatefields; the dispatch path does not enforce them. Rust/Axum has no enforcement either. - Rust/Axum and Tauri are the IR authority via the
#[mizan::client]macro + linkme registry; the codegen links the crate directly (build_ir()/ theexport-irbin) rather than fetching over HTTP. - FastAPI and Rust/Axum expose
GET /session/returning a null CSRF token for wire parity; CSRF is Django-only. mizan-tsemits the Edge manifest (JSON) but has no KDL IR emitter, so it can't yet feed the codegen — an unbuilt gap. A TypeScript backend still needs the generated client (types +callXxx/fetchXxx+ framework hooks); same language doesn't remove the need for it.- The
mizan-codegencrate parses theuploadKDL node and emits the field across targets (the Rust target lowers it toVec<u8>). Multipart dispatch binding is wired for Django and FastAPI only; the Rust/Axum and Tauri adapters have no upload concept at dispatch yet. - The TypeScript column is the
mizan-tsbackend adapter, which has no upload dispatch. The matching client side lives in the kernel (@mizan/base):mizanCallauto-switches tomultipart/form-datawhen any argument is aFile. mizan-tsdispatch now enforcesauth=(true/'staff'/'superuser'/predicate) against a host-suppliedIdentity, byte-matching the Python guard's denial messages.- JWT/MWT token logic is single-sourced in
mizan_core.auth; Django and FastAPI ride it. Session-validation (immediate-logout revocation) is Django-only — FastAPI mints from its own credential check. mizan-tsships an optionaldecodeMwt/decodeJwtBearer/identityFromMwthelper (HS256 via Nodecrypto, cross-language pin-tested against a Python-minted MWT) so a TS edge worker can deriveIdentityfrom a Python-issued token. Identity source stays host-supplied;mizan-tsdoes not mint from a session.
Conformance
Adapter parity is gated by the AFI conformance suite in tests/afi/. It
currently asserts IR-shape parity — the same fixture through Django, FastAPI, and
the Rust adapter emits byte-identical KDL (test_codegen_parity.py). Per-capability
runtime assertions (header transport, auth= enforcement, cache behavior) are planned.
License
Mizan is licensed under the Elastic License 2.0 (SPDX: Elastic-2.0). You
may use, copy, modify, and distribute it freely, including in commercial products you
build on top of it. You may not provide Mizan to third parties as a hosted or
managed service that exposes a substantial set of its features.