"""Inertia.js configuration classes."""
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
from litestar_vite.config._constants import empty_dict_factory, empty_set_factory
__all__ = ("InertiaConfig", "InertiaSSRConfig", "InertiaTypeGenConfig")
[docs]
@dataclass
class InertiaSSRConfig:
"""Server-side rendering settings for Inertia.js.
In development mode, Inertia SSR uses Vite 7+'s ``RunnableDevEnvironment.runner``
inside the already-running Vite dev server over ``/__litestar_ssr__``.
In production mode, Litestar spawns the built SSR bundle as a managed subprocess
communicating over ``stdin``/``stdout`` pipes (`StdioIPCTransport`).
"""
enabled: bool = True
timeout: float = 2.0
target_selector: str = "#app"
"""CSS selector for the element whose outer HTML is replaced by the SSR-rendered body.
Used by ``_render_template`` (template mode) to locate the mount point in the
rendered Jinja HTML. Defaults to ``#app`` to match Inertia's convention.
For ``mode="hybrid"``, ``SPAConfig.app_selector`` is the source of truth and
this field is ignored — SPA config already governs the SPA shell selector.
"""
command: list[str] | None = None
"""Command to start the production stdio SSR worker.
When ``None``, runs Node with the absolute path to ``ssr.js`` under
``PathConfig.ssr_output_dir`` or ``<resource_dir>/bootstrap/ssr``. Relative
output directories resolve against the project root, independently of ``cwd``.
"""
cwd: Path | None = None
"""Working directory for the SSR command. Defaults to ``ViteConfig.root_dir`` when None."""
fallback_to_client: bool = True
"""Whether to fall back gracefully to client-side hydration if SSR rendering fails."""
circuit_breaker_enabled: bool = True
"""Whether to enable the in-memory circuit breaker protecting the SSR rendering pipeline."""
circuit_breaker_failure_threshold: int = 3
"""Number of consecutive failures before the circuit breaker trips to OPEN state."""
circuit_breaker_reset_timeout: float = 30.0
"""Cooldown seconds to wait before probing SSR worker health after tripping."""
[docs]
@dataclass
class InertiaConfig:
"""Configuration for InertiaJS support.
This is the canonical configuration class for Inertia.js integration.
Presence of an InertiaConfig instance indicates Inertia is enabled.
Note:
SPA mode (HTML transformation vs Jinja2 templates) is controlled by
ViteConfig.mode='hybrid'. The app_selector for data-page injection
is configured via SPAConfig.app_selector.
Attributes:
root_template: Name of the root template to use.
component_opt_keys: Identifiers for getting inertia component from route opts.
redirect_unauthorized_to: Path for unauthorized request redirects.
redirect_404: Path for 404 request redirects.
extra_static_page_props: Static props added to every page response.
extra_session_page_props: Session keys to include in page props.
"""
root_template: str = "index.html"
"""Name of the root template to use.
This must be a path that is found by the Vite Plugin template config
"""
component_opt_keys: tuple[str, ...] = ("component", "page")
"""Identifiers to use on routes to get the inertia component to render.
The first key found in the route handler opts will be used. This allows
semantic flexibility - use "component" or "page" depending on preference.
"""
redirect_unauthorized_to: str | None = None
"""Optionally supply a path where unauthorized requests should redirect."""
redirect_404: str | None = None
"""Optionally supply a path where 404 requests should redirect."""
extra_static_page_props: dict[str, Any] = field(default_factory=empty_dict_factory)
"""A dictionary of values to automatically add in to page props on every response."""
extra_session_page_props: set[str] | dict[str, type] = field(default_factory=empty_set_factory)
"""Session props to include in page responses.
Keys are copied when the current request exposes a Litestar session. They are
omitted from sessionless responses. Use ``CookieBackendConfig`` for encrypted,
server-store-free persistence, or ``ServerSideSessionConfig`` with a Litestar
store.
Can be either:
- A set of session key names (types will be 'unknown')
- A dict mapping session keys to Python types (auto-registered with OpenAPI)
"""
shared_page_prop_types: dict[str, Any] | None = None
"""Python types for props pushed at request time with ``share()``.
This declares *types only* and never carries values, unlike
``extra_static_page_props``. It exists because ``share()`` calls in guards and
middleware have no naming site the type generator can read, so without a
declaration those props fall back to a synthesized default type.
Declared annotations are registered against the same OpenAPI schema registry
used for route props, so nested models resolve to the identical generated
TypeScript type rather than a duplicate.
Values are annotations, so containers and unions are accepted alongside plain
models. Anything the schema generator cannot resolve falls back to the
configured fallback type.
Leave as ``None`` to keep the generated defaults.
"""
encrypt_history: bool = False
"""Enable browser history encryption globally (v2 feature).
When True, all Inertia responses will include `encryptHistory: true`
in the page object. The Inertia client will encrypt history state
using browser's crypto API before pushing to history.
This prevents sensitive data from being visible in browser history
after a user logs out. Individual responses can override this setting.
Note: Encryption happens client-side; requires HTTPS in production.
See: https://inertiajs.com/history-encryption
"""
type_gen: "InertiaTypeGenConfig | None" = None
"""Type generation options for Inertia page props.
Controls default types in generated page-props.ts. Set to InertiaTypeGenConfig()
or leave as None for defaults. Use InertiaTypeGenConfig(include_default_auth=False)
to disable default User/AuthData interfaces for non-standard user models.
"""
ssr: InertiaSSRConfig | bool | None = None
"""Enable server-side rendering (SSR) for Inertia responses.
When enabled, full-page HTML responses will be pre-rendered via Vite's
ModuleRunner in development mode or a managed stdio worker in production mode.
Supports:
- True: enable with defaults -> ``InertiaSSRConfig()``
- False/None: disabled -> ``None``
- InertiaSSRConfig: use as-is
"""
use_script_element: bool = True
"""Use a script element instead of data-page attribute for page data.
When True, embeds page data in a ``<script type="application/json" id="app_page" data-page="app">``
element instead of a ``data-page`` attribute on the app element.
Benefits:
- ~37% payload reduction for large pages (no HTML entity escaping)
- Better performance for pages with complex props
Requirements:
- Inertia v3 clients use this transport by default; no extra client ``defaults`` block is required.
- Inertia v2 clients must also enable:
``createInertiaApp({ defaults: { future: { useScriptElementForInitialPage: true } } })``
- If SSR is enabled for an Inertia v2 client, keep the same
``defaults.future.useScriptElementForInitialPage`` option in both the browser entry
and the SSR entry.
- The script element must include the target app element ID in its ``data-page`` attribute so
Inertia can locate the payload element.
- Supported with Inertia v2.3+ and Inertia v3.
Enabled by default for the current Inertia contract. Set to ``False`` to
keep the legacy ``data-page`` attribute bootstrap, which can be useful when
staying on an Inertia v2 client without the ``future`` opt-in.
"""
precognition: bool = False
"""Enable Precognition support for real-time form validation.
When True, registers an exception handler that converts validation errors
to Laravel's Precognition format when the Precognition header is present.
This enables real-time validation without executing handler side effects.
See: https://laravel.com/docs/precognition
"""
[docs]
def __post_init__(self) -> None:
"""Normalize optional sub-configs."""
if self.ssr is True:
self.ssr = InertiaSSRConfig()
elif self.ssr is False:
self.ssr = None
@property
def ssr_config(self) -> InertiaSSRConfig | None:
"""Return the SSR config when enabled, otherwise None.
Returns:
The resolved SSR config when enabled, otherwise None.
"""
if isinstance(self.ssr, InertiaSSRConfig) and self.ssr.enabled:
return self.ssr
return None
[docs]
@dataclass
class InertiaTypeGenConfig:
"""Type generation options for Inertia page props.
Controls which default types are included in the generated page-props.ts file.
This follows Laravel Jetstream patterns - sensible defaults for common auth patterns.
Attributes:
include_default_auth: Include default User and AuthData interfaces.
Default User has: id, email, name. Users extend via module augmentation.
Set to False if your User model doesn't have these fields (uses uuid, username, etc.)
include_default_flash: Include default FlashMessages interface.
Uses { [category: string]: string[] } pattern for flash messages.
"""
include_default_auth: bool = True
"""Include default User and AuthData interfaces.
When True, generates:
- User: { id: string, email: string, name?: string | null }
- AuthData: { isAuthenticated: boolean, user?: User }
Users extend via TypeScript module augmentation.
Set to False if your User model has different required fields.
"""
include_default_flash: bool = True
"""Include default FlashMessages interface.
When True, generates:
- FlashMessages: { [category: string]: string[] }
Standard flash message pattern used by most web frameworks.
"""