Source code for litestar_vite.inertia.request
from __future__ import annotations
from functools import cached_property
from typing import TYPE_CHECKING
from urllib.parse import unquote
from litestar import Request
from litestar.connection.base import (
AuthT,
StateT,
UserT,
empty_receive,
empty_send,
)
from litestar_vite.inertia._utils import InertiaHeaders
__all__ = ("InertiaDetails", "InertiaRequest")
if TYPE_CHECKING:
from litestar.types import Receive, Scope, Send
[docs]
class InertiaDetails:
"""InertiaDetails holds all the values sent by Inertia client in headers and provide convenient properties."""
[docs]
def __init__(self, request: Request[UserT, AuthT, StateT]) -> None:
"""Initialize :class:`InertiaDetails`"""
self.request = request
def _get_header_value(self, name: InertiaHeaders) -> str | None:
"""Parse request header
Check for uri encoded header and unquotes it in readable format.
"""
if value := self.request.headers.get(name.value.lower()):
is_uri_encoded = self.request.headers.get(f"{name.value.lower()}-uri-autoencoded") == "true"
return unquote(value) if is_uri_encoded else value
return None
def _get_route_component(self) -> str | None:
"""Get the route component.
Checks for the `component` key within the route configuration.
"""
rh = self.request.scope.get("route_handler") # pyright: ignore[reportUnknownMemberType]
if rh:
return rh.opt.get("component")
return None
[docs]
def __bool__(self) -> bool:
"""Check if request is sent by an Inertia client."""
return self._get_header_value(InertiaHeaders.ENABLED) == "true"
@cached_property
def route_component(self) -> str | None:
"""Partial Data Reload."""
return self._get_route_component()
@cached_property
def partial_component(self) -> str | None:
"""Partial Data Reload."""
return self._get_header_value(InertiaHeaders.PARTIAL_COMPONENT)
@cached_property
def partial_data(self) -> str | None:
"""Partial Data Reload."""
return self._get_header_value(InertiaHeaders.PARTIAL_DATA)
@cached_property
def referer(self) -> str | None:
"""Partial Data Reload."""
return self._get_header_value(InertiaHeaders.REFERER)
@cached_property
def is_partial_render(self) -> bool:
"""Is Partial Data Reload."""
return bool(self.partial_component == self.route_component and self.partial_data)
@cached_property
def partial_keys(self) -> list[str]:
"""Is Partial Data Reload."""
return self.partial_data.split(",") if self.partial_data is not None else []
[docs]
class InertiaRequest(Request[UserT, AuthT, StateT]):
"""Inertia Request class to work with Inertia client."""
__slots__ = ("inertia",)
[docs]
def __init__(self, scope: Scope, receive: Receive = empty_receive, send: Send = empty_send) -> None:
"""Initialize :class:`InertiaRequest`"""
super().__init__(scope=scope, receive=receive, send=send)
self.inertia = InertiaDetails(self)
@property
def is_inertia(self) -> bool:
"""True if the request contained inertia headers."""
return bool(self.inertia)
@property
def inertia_enabled(self) -> bool:
"""True if the route handler contains an inertia enabled configuration."""
return bool(self.inertia.route_component is not None)
@property
def is_partial_render(self) -> bool:
"""True if the route handler contains an inertia enabled configuration."""
return self.inertia.is_partial_render
@property
def partial_keys(self) -> set[str]:
"""True if the route handler contains an inertia enabled configuration."""
return set(self.inertia.partial_keys)