Ryth Azhur e0fc46058c fastapi: channels and RPC over one socket, invalidation included
The adapter served no websocket, so a FastAPI project had no channel and no
socket RPC. It has both now, on mizan-django's envelope, so a client speaks to
either backend unchanged.

RPC dispatches through the same execute_function the HTTP route calls — one
dispatch path, so the transports cannot disagree about what a function does.
`data` is the {result, invalidate, merge} envelope the Tauri and webview
transports already document, so mizanCall applies a socket mutation's
invalidation exactly as it applies an HTTP one, param-scoped and unchanged.
mizan-django's socket sends a bare result and drops it.

Channel membership is held in this process; Django's channel layer carries
groups across workers and nothing here does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 22:24:49 -04:00
2026-06-04 21:37:24 -04:00
2026-07-13 15:46:28 -04:00
2026-06-04 03:38:26 -04:00
2026-06-04 21:37:24 -04:00
2026-06-04 03:38:26 -04:00
2026-06-04 21:37:24 -04:00

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

Backends: Django (backends/mizan-django, the reference implementation), FastAPI (backends/mizan-fastapi), Rust/Axum (backends/mizan-rust-axum), Tauri (backends/mizan-tauri), and TypeScript (backends/mizan-ts). Frontends are generated from the KDL IR over the @mizan/base kernel; frontends/ holds the kernel, the per-framework adapters, and the transports.

Per-adapter transport shape:

  • 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 and Tauri are the IR authority via the #[mizan::client] macro + linkme registry; the codegen links the crate directly (build_ir() / the export-ir bin) rather than fetching over HTTP.
  • "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.
  • FastAPI and Rust/Axum expose GET /session/ returning a null CSRF token for wire parity; CSRF is Django-only.
  • TypeScript is an edge/protocol-reference adapter (HMAC cache, manifest, PSR), not a codegen source — it demonstrates the cache + invalidation protocol is language-agnostic.

Caveat: Rust/Axum and Tauri accept auth= on a function but their dispatch paths do not enforce it — do not rely on auth= for access control on those adapters.

Auth-provider integration (django-allauth) lives in its own repository, mizan-allauth — a dedicated Django system built on mizan-django's forms and context primitives.

Conformance

Per-adapter capability support is measured by the AFI conformance suite in tests/afi/, not maintained as prose — the suite asserts IR-shape parity: the same fixture through Django, FastAPI, and the Rust adapter emits byte-identical KDL (test_codegen_parity.py).

Documentation

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.

Description
No description provided
Readme 4.8 MiB
Languages
Python 49.3%
Rust 26.7%
TypeScript 21.1%
Jinja 2.4%
JavaScript 0.3%
Other 0.2%