# Genro ASGI

**A minimal ASGI server and application toolkit** for building web services with routing, authentication, sessions, and middleware — configurable via `config.yaml`.

[![PyPI version](https://img.shields.io/pypi/v/genro-asgi.svg)](https://pypi.org/project/genro-asgi/)
[![Python Support](https://img.shields.io/pypi/pyversions/genro-asgi.svg)](https://pypi.org/project/genro-asgi/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Documentation](https://readthedocs.org/projects/genro-asgi/badge/?version=latest)](https://genro-asgi.readthedocs.io)

## What it does

- **Serves web applications** mounted on URL prefixes (`/api/`, `/shop/`, etc.) with config-driven loading
- **Authenticates requests** via bearer tokens, basic auth, or JWT — O(1) credential lookup, lazy auth for zero overhead on unprotected routes
- **Manages sessions** with in-memory store, cookie-based reconnection, and user avatars (identity + tags + extensible Bag data)
- **Applies middleware** at two levels: global (CORS, errors, auth) and per-app (session, cache) with independent chains
- **Routes requests** via `genro-routes` with decorator-based routing and auth tag filtering
- **Serves static files** with `StaticRouter` and hierarchical resource loading with fallback chains
- **Handles WebSocket** with the WSX extension protocol for structured request/response messaging
- **Exposes MCP endpoints** via `McpApplication` for AI tool integration (Streamable HTTP transport)
- **Configures plugins at runtime** via the `/_plugin_config/` web UI with persistence to JSON

## Installation

```bash
pip install genro-asgi            # core
pip install genro-asgi[json]      # + orjson for fast JSON
pip install genro-asgi[dev]       # + test/lint tools
```

## Quick Start

```python
from genro_asgi import AsgiServer

server = AsgiServer(server_dir=".")
server.run()  # Starts uvicorn, reads config.yaml
```

**config.yaml**:

```yaml
server:
  host: "127.0.0.1"
  port: 8000

middleware:
  cors: on
  auth: on

auth_middleware:
  bearer:
    api_key:
      token: "sk_live_abc123"
      tags: "api,read"

apps:
  shop:
    module: "shop_app:Application"
    middleware:
      session: on
```

## Architecture at a glance

The server is an instance with its own state — no global variables. Every component is an isolated instance connected via semantic parent-child references.

**Request flow**:

```
uvicorn → AsgiServer → global middleware (errors → cors → auth)
  → Dispatcher → per-app middleware (session, cache, ...)
    → handler(**query) → Response → ASGI send
```

### Core components

| Component | Purpose |
|-----------|---------|
| **AsgiServer** | ASGI entry point, loads config, mounts apps, composes BasicAuthMixin |
| **Dispatcher** | Resolves handler via router, applies per-app middleware chains |
| **BasicAuthMixin** | Server-side auth: `server.authenticate(scope)`, `server.verify_credentials()` |
| **SessionMiddleware** | Per-app session lifecycle: cookie extraction, reconnection, Set-Cookie |
| **Session / Avatar** | Session with meta + Bag data + Avatar (identity, tags, extensible data) |
| **MemorySessionStore** | In-memory session store with dump/restore for persistence |
| **HandlerExecutor** | ASGI app executing pre-resolved nodes in per-app chains |
| **AsgiApplication** | Base class for mountable applications |
| **McpApplication** | MCP Streamable HTTP transport for AI tools |
| **StaticRouter** | Filesystem-backed static file serving |
| **LocalStorage** | Filesystem storage with mount system |

### Middleware

| Middleware | Order | Default | Scope |
|-----------|-------|---------|-------|
| ErrorMiddleware | 100 | on | global |
| CORSMiddleware | 300 | off | global |
| AuthMiddleware | 400 | off | global |
| SessionMiddleware | 450 | off | per-app |
| CacheMiddleware | 900 | off | per-app |
| CompressionMiddleware | 900 | off | global |
| LoggingMiddleware | 200 | off | global |

## Documentation

Full documentation: https://genro-asgi.readthedocs.io

- [Architecture overview](https://genro-asgi.readthedocs.io/en/latest/architecture/00-overview.html)
- [API reference](https://genro-asgi.readthedocs.io/en/latest/api/index.html)

## Development

```bash
git clone https://github.com/genropy/genro-asgi.git
cd genro-asgi
pip install -e .[dev]

pytest                    # run tests
ruff check .              # lint
mypy src                  # type check
```

## License

Copyright 2025-2026 **Softwell S.r.l.**

Licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). See `NOTICE` for additional attribution.

## Links

- **GitHub**: https://github.com/genropy/genro-asgi
- **PyPI**: https://pypi.org/project/genro-asgi/
- **Documentation**: https://genro-asgi.readthedocs.io
