diff --git a/passkey/fastapi/mainapp.py b/passkey/fastapi/mainapp.py index 9a6945e..fc5d23e 100644 --- a/passkey/fastapi/mainapp.py +++ b/passkey/fastapi/mainapp.py @@ -42,6 +42,16 @@ async def lifespan(app: FastAPI): # pragma: no cover - startup path logging.error(f"⚠️ {e}") # Re-raise to fail fast raise + + # In dev mode, Vite serves assets directly; in production, mount static files + # This is deferred to lifespan because PASSKEY_DEVMODE is set after module import + if not frontend.is_dev_mode(): + app.mount( + "/auth/assets/", + StaticFiles(directory=frontend.file("auth", "assets")), + name="assets", + ) + yield # (Optional) add shutdown cleanup here later @@ -54,11 +64,6 @@ app.middleware("http")(auth_host.redirect_middleware) app.mount("/auth/api/admin/", admin.app) app.mount("/auth/api/", api.app) app.mount("/auth/ws/", ws.app) -app.mount( - "/auth/assets/", - StaticFiles(directory=frontend.file("auth", "assets")), - name="assets", -) @app.get("/auth/restricted/") diff --git a/passkey/util/frontend.py b/passkey/util/frontend.py index 02f9f00..2dbe129 100644 --- a/passkey/util/frontend.py +++ b/passkey/util/frontend.py @@ -12,7 +12,7 @@ from threading import Thread import httpx -__all__ = ["path", "file", "read", "run_dev"] +__all__ = ["path", "file", "read", "run_dev", "is_dev_mode"] DEV_SERVER = "http://localhost:4403" @@ -60,7 +60,7 @@ def file(*parts: str) -> Path: return path.joinpath(*parts) -def _is_dev_mode() -> bool: +def is_dev_mode() -> bool: """Check if we're running in dev mode (Vite frontend server).""" return os.environ.get("PASSKEY_DEVMODE") == "1" @@ -78,7 +78,7 @@ async def read(filepath: str) -> tuple[bytes, int, dict[str, str]]: Tuple of (content, status_code, headers) suitable for FastAPI Response(*args) or Sanic raw response. """ - if _is_dev_mode(): + if is_dev_mode(): async with httpx.AsyncClient() as client: resp = await client.get(f"{DEV_SERVER}{filepath}") resp.raise_for_status()