"""FastAPI dependency providers. All ``Depends()`` callables that inject shared resources (database connection, settings, services, auth guard) are defined here. Routers import directly from this module — never from ``app.state`` directly — to keep coupling explicit and testable. """ from typing import Annotated import aiosqlite import structlog from fastapi import Depends, HTTPException, Request, status from app.config import Settings log: structlog.stdlib.BoundLogger = structlog.get_logger() async def get_db(request: Request) -> aiosqlite.Connection: """Provide the shared :class:`aiosqlite.Connection` from ``app.state``. Args: request: The current FastAPI request (injected automatically). Returns: The application-wide aiosqlite connection opened during startup. Raises: HTTPException: 503 if the database has not been initialised. """ db: aiosqlite.Connection | None = getattr(request.app.state, "db", None) if db is None: log.error("database_not_initialised") raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Database is not available.", ) return db async def get_settings(request: Request) -> Settings: """Provide the :class:`~app.config.Settings` instance from ``app.state``. Args: request: The current FastAPI request (injected automatically). Returns: The application settings loaded at startup. """ return request.app.state.settings # type: ignore[no-any-return] # Convenience type aliases for route signatures. DbDep = Annotated[aiosqlite.Connection, Depends(get_db)] SettingsDep = Annotated[Settings, Depends(get_settings)]