Metadata-Version: 2.5
Name: tempestweb
Version: 0.64.0
Summary: Build web apps in typed Python — one tree, a DOM renderer, three execution modes (WASM + server + transpile).
Author-email: Mauricio Benjamin <mauricio.benjamin@reloverelations.com>
License: MIT
Requires-Python: >=3.11
Requires-Dist: tempest-core>=0.11.0
Provides-Extra: cli
Requires-Dist: tomlkit>=0.13; extra == 'cli'
Requires-Dist: watchfiles>=0.21; extra == 'cli'
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: numpy>=1.26; extra == 'dev'
Requires-Dist: ort-vision-sdk>=0.1; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs-static-i18n>=1.2; extra == 'docs'
Provides-Extra: server
Requires-Dist: fastapi>=0.110; extra == 'server'
Requires-Dist: uvicorn[standard]>=0.29; extra == 'server'
Requires-Dist: websockets>=12; extra == 'server'
Provides-Extra: vision
Requires-Dist: numpy>=1.26; extra == 'vision'
Requires-Dist: ort-vision-sdk>=0.1; extra == 'vision'
Provides-Extra: webpush
Requires-Dist: pywebpush>=1.14; extra == 'webpush'
Description-Content-Type: text/markdown

# tempestweb

📚 **Documentation:** [Português (Brasil)](https://mauriciobenjamin700.github.io/tempestweb/)
· [English (US)](https://mauriciobenjamin700.github.io/tempestweb/en/) — bilingual
docs site (PT-BR default + EN-US), deployed to GitHub Pages.

> Build web apps in **typed Python**. One declarative widget tree, a **DOM**
> renderer, and **three execution modes** that share 100% of the application code:
> **Mode A (WASM)** runs your Python in the browser via Pyodide; **Mode B
> (server)** runs it on the server (FastAPI) and talks to a thin JS client over
> **WebSocket or SSE**; **Mode C (transpile)** transcribes your
> Python to **native JavaScript** — zero Python runtime, static hosting, great
> first-paint/SEO. Installable **PWA**, **offline-first** (service worker +
> IndexedDB), and **WebPush** are first-class — parity with `tempest-react-sdk`.

Sister project to [tempestroid](../tempestroid) — same "one tree, multiple
renderers" architecture. The renderer-agnostic engine (IR, reconciler, state,
style, widgets) is shared; tempestweb adds a **DOM** leaf renderer (pure
JavaScript, no framework, no build step, no TypeScript) and two patch transports.

## Status

Published on PyPI and functional across all three modes — a working counter runs
live under WASM, server, and transpile; the full test gate is green and every
example builds. The transpile mode (C) is now a **mature, first-class mode** —
100% of `tempest_core` widgets, a wide typed-Python subset, and a full PWA story
(installable, offline, WebPush). Only a handful of advanced constructs sit outside
its subset, and the compiler fails early with `file:line` when you hit one. Design
docs:

- [`docs/plan.md`](docs/plan.md) — full design and phase plan.
- [`docs/roadmap.md`](docs/roadmap.md) — phase checklist.
- [`docs/arquitetura.md`](docs/arquitetura.md) — architecture.
- [`docs/contract.md`](docs/contract.md) — the Python↔client wire format.
- [`docs/agents/MANIFEST.md`](docs/agents/MANIFEST.md) — parallel agent task plan.

Want runnable apps? Browse the **[Example Gallery](https://mauriciobenjamin700.github.io/tempestweb/en/examples/)**
([PT-BR](https://mauriciobenjamin700.github.io/tempestweb/examples/)) — 50+
single-concept demos (stopwatch, forms, data table/grid, kanban, chat, theming,
i18n, canvas charts, app shells, native capabilities, observability, PWA/WebPush,
a Mode C tour, and a server-mode walkthrough), each running unchanged across the
execution modes.

Building an admin panel? Skip the chrome with **[ready-made screens](https://mauriciobenjamin700.github.io/tempestweb/en/presets/)**
([PT-BR](https://mauriciobenjamin700.github.io/tempestweb/presets/)) — an admin
shell, a KPI dashboard, a searchable list, forms and an auth screen, described
with typed records instead of assembled widget by widget. They come with the
responsive behaviour inline styles cannot express: a sidebar that collapses to a
drawer, grids that reflow, a table that scrolls under a sticky header, and a
print layout without the chrome. No CSS, no breakpoints of your own.

Building something real? Read the **[App architecture & best practices](https://mauriciobenjamin700.github.io/tempestweb/best-practices/)**
guide ([EN](https://mauriciobenjamin700.github.io/tempestweb/en/best-practices/)) —
the ideal layered structure (routes · pages · components · styles · controllers ·
services · storages · schemas · utils · core), mirroring `tempest-fastapi-sdk`, so
your app doesn't rot into garbage code.

## Get started

```bash
pip install "tempestweb[server,cli]"   # or: uv add "tempestweb[server,cli]"

tempestweb new myapp                   # scaffold app.py + tempestweb.toml
cd myapp
tempestweb dev                         # http://127.0.0.1:8000, hot-reload (wasm)
```

The scaffold's `app.py` exposes the two callables every project needs —
`make_state()` and `view(app)` — and `tempestweb.toml` names the entrypoint
(`app.py` by default, configurable). `tempestweb dev` runs any mode locally with
hot-reload — pick the mode at dev/build time, never in the app:

```bash
tempestweb dev   --mode wasm       --path myapp   # Mode A: Python in the browser
tempestweb dev   --mode server     --path myapp   # Mode B: FastAPI + WebSocket
tempestweb dev   --mode transpile  --path myapp   # Mode C: native JS bundle
tempestweb build --mode transpile  --path myapp   # emit a static, CDN-servable bundle
```

> `dev` serves **all three modes** with watch + reload — including **Mode B
> (server)**, which rebuilds and restarts on every edit. To serve the built app
> **without** a watcher (production-like), use `tempestweb run --mode server` — it's
> what the generated deploy Dockerfile runs. Every command takes the project
> **directory** via `--path` (default: cwd) — not a positional `.py` file. Check
> your install with `tempestweb --version`.

Talking to a FastAPI backend? Generate a typed client from its OpenAPI spec —
`@dataclass` models + service classes, one package per route group, working in
all three modes (the Python analog of `tempest-react-sdk`'s `tempest gen api`):

```bash
tempestweb gen api http://127.0.0.1:8000/openapi.json --out api
```

Full walkthrough: the [Using the CLI](https://mauriciobenjamin700.github.io/tempestweb/en/cli/),
[Generate a client from OpenAPI](https://mauriciobenjamin700.github.io/tempestweb/en/openapi/),
[Installation](https://mauriciobenjamin700.github.io/tempestweb/en/installation/)
and [Tutorial](https://mauriciobenjamin700.github.io/tempestweb/en/tutorial/) guides.

## Code quality

You write typed Python, so the CLI polices that Python too. `tempestweb check` is
the one-command gate — it runs `ruff check` → `ruff format --check` → `mypy` →
`pytest` against your project and stops at the first error:

```bash
tempestweb check                       # the full gate
tempestweb lint / fix / format / fmt-check / type / test   # individual steps
```

The gate layers opinion on top of your own ruff/mypy config via a strictness
level — `[quality] typing_strictness` in `tempestweb.toml` (`lenient` |
`standard` | `strict`, default `standard`, `tempestweb new` scaffolds it). It only
**adds** rules, never loosens yours, and `ANN401` is never enabled — `Any` is a
valid annotation. `--strictness` overrides per invocation. Full details in the
[Code quality](https://mauriciobenjamin700.github.io/tempestweb/en/cli/#code-quality)
guide.

## How it works

```text
   view(app) ──build──▶ Node tree (IR) ──diff──▶ [ Patch ]   ← shared core (tempest-core)
                                                    │          insert/remove/update/reorder/replace
              ╭─────────────────┬───────────────────┤
       Mode A transport   Mode B transport     Mode C: transpile view() → native JS;
       (pyodide.ffi)      (WebSocket | SSE)     the core runs IN JS, patches in-process
              ╰─────────────────┴───────────────────╯
                  client/ (pure JS): apply patches to the DOM
                  + Style→CSS + event capture          ← same client code in every mode
```

The application's `view()` never names a transport — the same
`examples/counter/app.py` runs under `--mode wasm`, `--mode server` and
`--mode transpile` unchanged. Capabilities (`native/`) are typed awaitables with
the same Python API in every mode — Mode A calls the Web API in-process, Mode B
proxies it over a round-trip, Mode C routes to the same JS glue via an in-process
facade (see [`docs/contract.md`](docs/contract.md)). Track T brings **web-platform
parity**: beyond the core (http, audio, share, geolocation, clipboard, storage,
camera, install, offline, notifications), the bridge now covers **Tier 1** (
vibration, badge, wakelock, fullscreen, network, visibility, orientation, quota,
rich clipboard, battery, sensors), **Tier 2** (speech, recorder, filesystem,
bgsync, tabs, idle), and **Tier 3 / Chromium-only** (bluetooth, usb, serial, hid,
nfc, contacts, payment, pip, eyedropper, pointerlock, gamepad, midi, webaudio).
A **native event channel** streams continuous capabilities (geolocation/network/
battery watch, sensors, STT, …) as typed `async for` iterators. See the
[capability reference](https://mauriciobenjamin700.github.io/tempestweb/native-reference/)
([EN](https://mauriciobenjamin700.github.io/tempestweb/en/native-reference/)) and
the [event-channel guide](https://mauriciobenjamin700.github.io/tempestweb/native-events/).

## Static SSR — `render_to_html`

Another render target, alongside the interactive modes: the **same** typed tree
renders to a **static HTML string** on the server — no JavaScript, no DOM, no
runtime. HTML is just another leaf renderer.

```python
from tempest_core import Column, Text, Button, Style
from tempest_core.style import Edge
from tempestweb.html import render_to_html, render_document

tree: Column = Column(
    style=Style(gap=8.0, padding=Edge.all(16)),
    children=[Text(content="Hello"), Button(label="Click")],
)

fragment: str = render_to_html(tree)                 # an HTML fragment
page: str = render_document(tree, title="Home", htmx=True)  # a full document
```

The CSS is **byte-identical** to what the DOM client emits (the `style_to_css`
port mirrors `client/style.js`), and the new `tempest-core` 0.9.0 `Widget.tag` /
`Widget.attrs` fields let you emit semantic, htmx-ready markup
(`Container(tag="nav", attrs={"hx-get": "/x"})`). All text/attributes are escaped.
See the [Static SSR guide](https://mauriciobenjamin700.github.io/tempestweb/ssr/)
([EN](https://mauriciobenjamin700.github.io/tempestweb/en/ssr/)).

## Mode C — transpile to native JS 🚀

The "TypeScript story" for Python: you write the typed-Python app; a compiler
transcribes the **app layer** (state, `view()`, handlers) to **native
JavaScript**, reusing the whole shared JS renderer. **Zero Python runtime** in the
browser — static hosting, small bundle, great first-paint/SEO.

```python
# examples/counter/app.py  (unchanged from Modes A/B)
@dataclass
class CounterState:
    value: int = 0

def view(app: App[CounterState]) -> Widget:
    def increment() -> None:
        app.set_state(lambda s: setattr(s, "value", s.value + 1))
    return Column(children=[
        Text(content=f"Count: {app.state.value}", key="label"),
        Button(label="+", on_click=increment, key="inc"),
    ])
```

```python
from tempestweb.transpile import transpile_file

js: str = transpile_file("examples/counter/app.py")  # -> native ES module
```

The generated module runs on the native runtime (`client/transpile/runtime.js`)
with a JS `diff` locked against a core-derived golden. Coverage is now **100% of
`tempest_core`**: all ~64 widgets, MD3 styling, state-with-methods, navigation
(routes + URL), i18n, theme + responsiveness, native capabilities (http/storage/
cookies/…), field validators and both declarative and imperative animation. The
`tempestweb build/dev --mode transpile` CLI emits a static, CDN-servable bundle
that is a **first-class PWA — installable and offline out of the box** (manifest
+ cache-first service worker precaching the whole shell; customize via `[pwa]` in
`tempestweb.toml`).

See the canonical [`examples/transpile-tour`](examples/transpile-tour/app.py) —
one app exercising the whole surface — and the guide
([PT](https://mauriciobenjamin700.github.io/tempestweb/transpile/) ·
[EN](https://mauriciobenjamin700.github.io/tempestweb/en/transpile/)). It is a
**first-class mode**: only a handful of advanced constructs sit outside the typed
subset (out-of-subset constructs fail loud with `file:line`).

## Scaffold a PWA

```bash
tempestweb new myapp --template pwa    # Mode C: installable, offline PWA
tempestweb build --mode transpile --path myapp
```

The `pwa` template pre-configures `mode = "transpile"` + a `[pwa]` manifest block
and ships a counter with an **Install** button. Omit `--template` for the plain
counter starter that runs unchanged in all three modes.

## WebPush (end-to-end)

Push works client-to-server out of the box. Generate VAPID keys, mount the
router, subscribe from the client:

```bash
tempestweb vapid --env        # -> VAPID_PUBLIC_KEY=… / VAPID_PRIVATE_KEY=…
```

```python
from fastapi import FastAPI
from tempestweb.server import VapidConfig, WebPushService, webpush_router

service = WebPushService(VapidConfig.from_env())
app = FastAPI()
app.include_router(webpush_router(service))   # /webpush/{subscribe,unsubscribe,send}
```

The client subscribes with `native.notifications.subscribe(public_key)` and POSTs
the subscription to `/webpush/subscribe`; `POST /webpush/send` pushes to it. See
the runnable [`examples/webpush-server`](examples/webpush-server/server.py).

## Computer vision (ONNX)

```bash
pip install "tempestweb[vision]"   # pulls ort-vision-sdk + numpy
```

```python
from tempestweb.vision import Detector, to_detection_schemas

det = await Detector.create("./models/yolov8n.onnx", labels="coco")
result = (await det.predict("./images/street.jpg"))[0]
for d in result:
    print(d.name, d.conf, d.box.xyxy)          # Ultralytics-style views
payload = to_detection_schemas(result)          # JSON for a tempest-fastapi-sdk backend
```

`Classifier` / `Detector` / `Segmenter` share the **same input/output contract as
[`ort-vision-sdk`](https://pypi.org/project/ort-vision-sdk/) and
`tempest-fastapi-sdk`'s vision layer**, but run the model over the `native.onnx`
bridge (onnxruntime-web) so inference works in the browser — no `onnxruntime`
wheel needed. Preprocessing, postprocessing and the `.boxes`/`.probs`/`.masks`
result objects are ort-vision-sdk's, unchanged; only the model run crosses the
(async) bridge, so construction and `predict` are awaited. See the
[Computer vision guide](https://mauriciobenjamin700.github.io/tempestweb/en/vision/).

## Deploy (server mode)

```bash
tempestweb deploy --server-name app.example.com --tls    # -> deploy/
cd deploy && docker compose up --build
```

Generates a tailored `nginx.conf` (WebSocket upgrade, streaming timeouts, sticky
`ip_hash`, optional TLS), a `Dockerfile`, `docker-compose.yml` and a `DEPLOY.md`.
Harden the app with a `SecurityConfig` (auth, CORS, limits, rate limiting,
headers) — see the [Security](https://mauriciobenjamin700.github.io/tempestweb/en/security/)
and [Deploy](https://mauriciobenjamin700.github.io/tempestweb/en/deploy/) guides.
Static modes (A/C) need no server — publish the build to any CDN.

## Develop

```bash
uv venv && uv pip install -e ".[dev,server,cli]"
make check          # ruff + mypy + pytest + JS (jsdom) tests
```

## Layout

| Path | What |
|---|---|
| `tempest-core` (dependency) | Renderer-agnostic engine — IR/reconciler/state/style/widgets (`import tempest_core`), extracted from tempestroid. |
| `tempestweb/components/` | Native fields + forms (EmailField, PasswordField, LoginForm, …) plus the re-exported tempest-core library — 54 Material 3 components (Card, DataTable, Tabs, Drawer, Alert, BarChart/LineChart, …). |
| `tempestweb/transports/` | The one seam between modes (`base.py` Protocol, `wasm.py`, `websocket.py`, `sse.py`). |
| `tempestweb/html/` | Static SSR leaf renderer — `render_to_html` / `render_document` / `style_to_css` (Python port of `client/style.js`). |
| `tempestweb/transpile/` | **Mode C:** `ast`-based Python→JS compiler for the app layer. Paired with the native runtime in `client/transpile/` (`diff.js` · `widgets.js` · `runtime.js`). |
| `tempestweb/server/` | FastAPI + WebSocket/SSE host (Mode B). |
| `tempestweb/native/` | Web API capability adapters (Tracks N + T) — core (http, audio, share, geo, clipboard, storage, camera) plus Tier 1-3 web-platform parity (vibration, wakelock, fullscreen, network, sensors, bluetooth, usb, midi, …) and a streaming event channel (T-EV) consumed with `async for`. |
| `tempestweb/observability/` | Telemetry, logger, error boundary, feature flags, auth — adapter pattern (Track O). |
| `tempestweb/pwa/` | Web App Manifest + icon emitter (Track P). |
| `tempestweb/cli/` | `tempestweb new/dev/build/run/sync/gen`. |
| `client/` | Pure-JS DOM renderer (incl. Canvas draw-command execution for charts), Style→CSS, event capture; `pwa/` `sw/` `offline/` `push/` `native/` subdirs. |
| `tests/fixtures/` | Golden wire-format fixtures derived from the core. |

## Conventions

Python: double quotes, full typing (mypy `--strict`), Google docstrings in English,
async-first. Client: **plain JavaScript only** — no TypeScript, no framework, no
build step. See [`CLAUDE.md`](CLAUDE.md).
