"""The one ASGI app the gateway listens with. Every HTTP frontend is mounted under its ``path`` (``/anthropic``, ``/mcp``, ``/md``, ``/api``, ``/admin``); ``/healthz`` answers for the whole process and ``/`` redirects to the landing frontend (the admin console) when one is configured. """ from __future__ import annotations from typing import TYPE_CHECKING from starlette.applications import Starlette from starlette.responses import JSONResponse, RedirectResponse from starlette.routing import Mount, Route if TYPE_CHECKING: from collections.abc import Iterable from starlette.requests import Request from beaver_gateway.frontends.base import Frontend __all__ = ["build_root_app"] def build_root_app(frontends: Iterable[Frontend]) -> Starlette: mounted = [fe for fe in frontends if fe.path and fe.app() is not None] landing = next((fe for fe in mounted if fe.landing), None) paths = [fe.path for fe in mounted] async def healthz(_request: Request) -> JSONResponse: return JSONResponse({"status": "ok", "frontends": paths}) async def index(_request: Request) -> JSONResponse | RedirectResponse: if landing is not None: return RedirectResponse(f"{landing.path}/", status_code=307) return JSONResponse({"frontends": paths}) routes: list[Route | Mount] = [ Route("/healthz", healthz, methods=["GET"]), Route("/", index, methods=["GET"]), ] for fe in mounted: app = fe.app() assert app is not None # noqa: S101 - filtered above; narrows for ty assert fe.path is not None # noqa: S101 routes.append(Mount(fe.path, app=app, name=fe.name or fe.path.strip("/"))) return Starlette(routes=routes)