Source code for litestar_vite.inertia.plugin
from __future__ import annotations
from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, AsyncGenerator
from anyio.from_thread import start_blocking_portal
from litestar.plugins import InitPluginProtocol
if TYPE_CHECKING:
from anyio.from_thread import BlockingPortal
from litestar import Litestar
from litestar.config.app import AppConfig
from litestar_vite.inertia.config import InertiaConfig
[docs]
def set_js_routes(app: Litestar) -> None:
"""Generate the route structure of the application on startup."""
from litestar_vite.inertia.routes import generate_js_routes
js_routes = generate_js_routes(app)
app.state.js_routes = js_routes
[docs]
class InertiaPlugin(InitPluginProtocol):
"""Inertia plugin."""
__slots__ = ("_portal", "config")
[docs]
def __init__(self, config: InertiaConfig) -> None:
"""Initialize ``Inertia``.
Args:
config: Inertia configuration.
"""
self.config = config
[docs]
@asynccontextmanager
async def lifespan(self, app: Litestar) -> AsyncGenerator[None, None]:
"""Lifespan to ensure the event loop is available."""
with start_blocking_portal() as portal:
self._portal = portal
yield
@property
def portal(self) -> BlockingPortal:
"""Get the portal."""
return self._portal
[docs]
def on_app_init(self, app_config: AppConfig) -> AppConfig:
"""Configure application for use with Vite.
Args:
app_config: The :class:`AppConfig <litestar.config.app.AppConfig>` instance.
"""
from litestar.exceptions import ImproperlyConfiguredException
from litestar.middleware import DefineMiddleware
from litestar.middleware.session import SessionMiddleware
from litestar.security.session_auth.middleware import MiddlewareWrapper
from litestar.utils.predicates import is_class_and_subclass
from litestar_vite.inertia.exception_handler import exception_to_http_response
from litestar_vite.inertia.helpers import DeferredProp, StaticProp
from litestar_vite.inertia.middleware import InertiaMiddleware
from litestar_vite.inertia.request import InertiaRequest
from litestar_vite.inertia.response import InertiaBack, InertiaResponse
for mw in app_config.middleware:
if isinstance(mw, DefineMiddleware) and is_class_and_subclass(
mw.middleware,
(MiddlewareWrapper, SessionMiddleware),
):
break
else:
msg = "The Inertia plugin require a session middleware."
raise ImproperlyConfiguredException(msg)
app_config.exception_handlers.update({Exception: exception_to_http_response}) # pyright: ignore[reportUnknownMemberType]
app_config.request_class = InertiaRequest
app_config.response_class = InertiaResponse
app_config.middleware.append(InertiaMiddleware)
app_config.on_startup.append(set_js_routes)
app_config.signature_types.extend([InertiaRequest, InertiaResponse, InertiaBack, StaticProp, DeferredProp])
app_config.type_encoders = {
StaticProp: lambda val: val.render(),
DeferredProp: lambda val: val.render(),
**(app_config.type_encoders or {}),
}
app_config.type_decoders = [
(lambda x: x is StaticProp, lambda t, v: t(v)),
(lambda x: x is DeferredProp, lambda t, v: t(v)),
*(app_config.type_decoders or []),
]
app_config.lifespan.append(self.lifespan) # pyright: ignore[reportUnknownMemberType]
return app_config