Inertia Helpers

litestar_vite.inertia.helpers.lazy(key: str, value_or_callable: None) StaticProp[str, None][source]
litestar_vite.inertia.helpers.lazy(key: str, value_or_callable: T) StaticProp[str, T]
litestar_vite.inertia.helpers.lazy(key: str, value_or_callable: Callable[[...], None] = None) DeferredProp[str, None]
litestar_vite.inertia.helpers.lazy(key: str, value_or_callable: Callable[[...], Coroutine[Any, Any, None]] = None) DeferredProp[str, None]
litestar_vite.inertia.helpers.lazy(key: str, value_or_callable: Callable[[...], T | Coroutine[Any, Any, T]] = None) DeferredProp[str, T]

Create a lazy prop only included during partial reloads.

Lazy props are excluded from the initial page load and only sent when explicitly requested via partial reload (X-Inertia-Partial-Data header). This optimizes initial page load by deferring non-critical data.

There are two use cases for lazy():

1. Static Value (bandwidth optimization):

The value is computed eagerly but only sent during partial reloads. Use when the value is cheap to compute but you want to reduce initial payload.

>>> lazy("user_count", len(users))
2. Callable (bandwidth + CPU optimization):

The callable is only invoked during partial reloads. Use when the value is expensive to compute.

>>> lazy("permissions", lambda: Permission.all())

Warning

False Lazy Pitfall

Be careful not to accidentally call the function when passing it.

Wrong:

lazy("data", expensive_fn())

Correct:

lazy("data", expensive_fn)

This is a Python evaluation order issue, not a framework limitation.

Parameters:
  • key – The key to store the value under in the props dict.

  • value_or_callable – Either a static value (computed eagerly, sent lazily) or a callable (computed and sent lazily). If None, creates a lazy prop with None value.

Returns:

StaticProp if value_or_callable is not callable, DeferredProp otherwise.

Example:

from litestar_vite.inertia import lazy, InertiaResponse

@get("/dashboard", component="Dashboard")
async def dashboard() -> InertiaResponse:
    props = {
        "user": current_user,
        "user_count": lazy("user_count", 42),
        "permissions": lazy("permissions", lambda: Permission.all()),
        "notifications": lazy("notifications", fetch_notifications),
    }
    return InertiaResponse(props)

See also

litestar_vite.inertia.helpers.defer(key: str, callback: Callable[[...], T | Coroutine[Any, Any, T]], group: str = 'default') DeferredProp[str, T][source]

Create a deferred prop with optional grouping (v2 feature).

Deferred props are loaded lazily after the initial page render. Props in the same group are fetched together in a single request.

Parameters:
  • key – The key to store the value under.

  • callback – A callable (sync or async) that returns the value.

  • group – The group name for batched loading. Defaults to “default”.

Returns:

A DeferredProp instance.

Example:

defer("permissions", lambda: Permission.all())

defer("teams", lambda: Team.all(), group="attributes")
defer("projects", lambda: Project.all(), group="attributes")
class litestar_vite.inertia.helpers.PropFilter[source]

Bases: object

Configuration for prop filtering during partial reloads.

Used with only() and except_() helpers to explicitly control which props are sent during partial reload requests.

include

Set of prop keys to include (only send these).

Type:

set[str] | None

exclude

Set of prop keys to exclude (send all except these).

Type:

set[str] | None

should_include(key: str) bool[source]

Return True when a prop key should be included.

Returns:

True if the prop key should be included, otherwise False.

__init__(include: set[str] | None = None, exclude: set[str] | None = None) None
litestar_vite.inertia.helpers.only(*keys: str) PropFilter[source]

Create a filter that only includes the specified prop keys.

Use this to explicitly limit which props are sent during partial reloads. Only the specified props will be included in the response.

Parameters:

*keys – The prop keys to include.

Returns:

A PropFilter configured to include only the specified keys.

Example:

from litestar_vite.inertia import only, InertiaResponse

@get("/users", component="Users")
async def list_users(
    request: InertiaRequest,
    user_service: UserService,
) -> InertiaResponse:
    return InertiaResponse(
        {
            "users": user_service.list(),
            "teams": team_service.list(),
            "stats": stats_service.get(),
        },
        prop_filter=only("users"),
    )

Note

This is a server-side helper. The client should use Inertia’s router.reload({ only: ['users'] }) for client-initiated filtering.

litestar_vite.inertia.helpers.except_(*keys: str) PropFilter[source]

Create a filter that excludes the specified prop keys.

Use this to explicitly exclude certain props during partial reloads. All props except the specified ones will be included in the response.

Parameters:

*keys – The prop keys to exclude.

Returns:

A PropFilter configured to exclude the specified keys.

Example:

from litestar_vite.inertia import except_, InertiaResponse

@get("/users", component="Users")
async def list_users(
    request: InertiaRequest,
    user_service: UserService,
) -> InertiaResponse:
    return InertiaResponse(
        {
            "users": user_service.list(),
            "teams": team_service.list(),
            "stats": expensive_stats(),
        },
        prop_filter=except_("stats"),
    )

Note

The function is named except_ with a trailing underscore to avoid conflicting with Python’s except keyword.

class litestar_vite.inertia.helpers.MergeProp[source]

Bases: Generic[PropKeyT, T]

A wrapper for merge prop configuration (v2 feature).

Merge props allow data to be combined with existing props during partial reloads instead of replacing them entirely.

__init__(key: PropKeyT, value: T, strategy: Literal['append', 'prepend', 'deep'] = 'append', match_on: str | list[str] | None = None) None[source]

Initialize a MergeProp.

Parameters:
  • key – The prop key.

  • value – The value to merge.

  • strategy – The merge strategy - ‘append’, ‘prepend’, or ‘deep’.

  • match_on – Optional key(s) to match items on during merge.

litestar_vite.inertia.helpers.merge(key: str, value: T, strategy: Literal['append', 'prepend', 'deep'] = 'append', match_on: str | list[str] | None = None) MergeProp[str, T][source]

Create a merge prop for combining data during partial reloads (v2 feature).

Merge props allow new data to be combined with existing props rather than replacing them entirely. This is useful for infinite scroll, load more buttons, and similar patterns.

Note: Prop merging only works during partial reloads. Full page visits will always replace props entirely.

Parameters:
  • key – The prop key.

  • value – The value to merge.

  • strategy – How to merge the data: - ‘append’: Add new items to the end (default) - ‘prepend’: Add new items to the beginning - ‘deep’: Recursively merge nested objects

  • match_on – Optional key(s) to match items on during merge, useful for updating existing items instead of duplicating.

Returns:

A MergeProp instance.

Example:

merge("posts", new_posts)

merge("messages", new_messages, strategy="prepend")

merge("user_data", updates, strategy="deep")

merge("posts", updated_posts, match_on="id")
litestar_vite.inertia.helpers.scroll_props(page_name: str = 'page', current_page: int = 1, previous_page: int | None = None, next_page: int | None = None) ScrollPropsConfig[source]

Create scroll props configuration for infinite scroll (v2 feature).

Scroll props allow Inertia to manage pagination state for infinite scroll patterns, providing next/previous page information to the client.

Parameters:
  • page_name – The query parameter name for pagination. Defaults to “page”.

  • current_page – The current page number. Defaults to 1.

  • previous_page – The previous page number, or None if at first page.

  • next_page – The next page number, or None if at last page.

Returns:

A ScrollPropsConfig instance for use in InertiaResponse.

Example:

from litestar_vite.inertia import scroll_props, InertiaResponse

@get("/posts", component="Posts")
async def list_posts(page: int = 1) -> InertiaResponse:
    posts = await Post.paginate(page=page, per_page=20)
    return InertiaResponse(
        {"posts": merge("posts", posts.items)},
        scroll_props=scroll_props(
            current_page=page,
            previous_page=page - 1 if page > 1 else None,
            next_page=page + 1 if posts.has_more else None,
        ),
    )
litestar_vite.inertia.helpers.is_merge_prop(value: Any) TypeGuard[MergeProp[Any, Any]][source]

Check if value is a MergeProp.

Parameters:

value – Any value to check

Returns:

True if value is a MergeProp

litestar_vite.inertia.helpers.extract_merge_props(props: dict[str, Any]) tuple[list[str], list[str], list[str], dict[str, list[str]]][source]

Extract merge props metadata for the Inertia v2 protocol.

This extracts all MergeProp instances from the props dict and categorizes them by their merge strategy, returning the appropriate lists for the page response.

Parameters:

props – The props dictionary to scan.

Returns:

A tuple of (merge_props, prepend_props, deep_merge_props, match_props_on) where each list contains the prop keys for that strategy, and match_props_on is a dict mapping prop keys to the keys to match on.

Example:

props = {
    "users": [...],
    "posts": merge("posts", new_posts),
    "messages": merge("messages", new_msgs, strategy="prepend"),
    "data": merge("data", updates, strategy="deep"),
    "items": merge("items", items, match_on="id"),
}
merge_props, prepend_props, deep_merge_props, match_props_on = extract_merge_props(props)

The returned values then contain:

- merge_props: ["posts", "items"]
- prepend_props: ["messages"]
- deep_merge_props: ["data"]
- match_props_on: {"items": ["id"]}
class litestar_vite.inertia.helpers.StaticProp[source]

Bases: Generic[PropKeyT, StaticT]

A wrapper for static property evaluation.

__init__(key: PropKeyT, value: StaticT) None[source]
class litestar_vite.inertia.helpers.DeferredProp[source]

Bases: Generic[PropKeyT, T]

A wrapper for deferred property evaluation.

__init__(key: PropKeyT, value: Callable[[...], T | Coroutine[Any, Any, T] | None] | None = None, group: str = 'default') None[source]
property group: str

The deferred group this prop belongs to.

Returns:

The deferred group name.

litestar_vite.inertia.helpers.is_lazy_prop(value: Any) TypeGuard[DeferredProp[Any, Any] | StaticProp[Any, Any]][source]

Check if value is a deferred property.

Parameters:

value – Any value to check

Returns:

True if value is a deferred property

litestar_vite.inertia.helpers.is_deferred_prop(value: Any) TypeGuard[DeferredProp[Any, Any]][source]

Check if value is specifically a DeferredProp (not StaticProp).

Parameters:

value – Any value to check

Returns:

True if value is a DeferredProp

litestar_vite.inertia.helpers.extract_deferred_props(props: dict[str, Any]) dict[str, list[str]][source]

Extract deferred props metadata for the Inertia v2 protocol.

This extracts all DeferredProp instances from the props dict and groups them by their group name, returning a dict mapping group -> list of prop keys.

Parameters:

props – The props dictionary to scan.

Returns:

A dict mapping group names to lists of prop keys in that group. Empty dict if no deferred props found.

Example:

props = {
    "users": [...],
    "teams": defer("teams", get_teams, group="attributes"),
    "projects": defer("projects", get_projects, group="attributes"),
    "permissions": defer("permissions", get_permissions),
}
result = extract_deferred_props(props)

The result is {"default": ["permissions"], "attributes": ["teams", "projects"]}.
litestar_vite.inertia.helpers.should_render(value: Any, partial_data: set[str] | None = None, partial_except: set[str] | None = None, key: str | None = None) bool[source]

Check if value should be rendered based on partial reload filtering.

For v2 protocol, partial_except takes precedence over partial_data. When a key is provided, filtering applies to all props (not just lazy props).

Parameters:
  • value – Any value to check

  • partial_data – Optional set of keys to include (X-Inertia-Partial-Data)

  • partial_except – Optional set of keys to exclude (X-Inertia-Partial-Except, v2)

  • key – Optional key name for this prop (enables key-based filtering for all props)

Returns:

True if value should be rendered

Return type:

bool

litestar_vite.inertia.helpers.is_or_contains_lazy_prop(value: Any) bool[source]

Check if value is or contains a deferred property.

Parameters:

value – Any value to check

Returns:

True if value is or contains a deferred property

litestar_vite.inertia.helpers.lazy_render(value: T, partial_data: set[str] | None = None, portal: BlockingPortal | None = None, partial_except: set[str] | None = None) T[source]

Filter deferred properties from the value based on partial data.

For v2 protocol, partial_except takes precedence over partial_data.

Parameters:
  • value – The value to filter

  • partial_data – Keys to include (X-Inertia-Partial-Data)

  • portal – Optional portal to use for async rendering

  • partial_except – Keys to exclude (X-Inertia-Partial-Except, v2)

Returns:

The filtered value

litestar_vite.inertia.helpers.get_shared_props(request: ASGIConnection[Any, Any, Any, Any], partial_data: set[str] | None = None, partial_except: set[str] | None = None) dict[str, Any][source]

Return shared session props for a request.

For v2 protocol, partial_except takes precedence over partial_data.

Parameters:
  • request – The ASGI connection.

  • partial_data – Optional set of keys to include (X-Inertia-Partial-Data).

  • partial_except – Optional set of keys to exclude (X-Inertia-Partial-Except, v2).

Returns:

The shared props.

Note

Be sure to call this before self.create_template_context if you would like to include the flash message details.

litestar_vite.inertia.helpers.share(connection: ASGIConnection[Any, Any, Any, Any], key: str, value: Any) None[source]

Share a value in the session.

Parameters:
  • connection – The ASGI connection.

  • key – The key to store the value under.

  • value – The value to store.

litestar_vite.inertia.helpers.error(connection: ASGIConnection[Any, Any, Any, Any], key: str, message: str) None[source]

Set an error message in the session.

Parameters:
  • connection – The ASGI connection.

  • key – The key to store the error under.

  • message – The error message.

litestar_vite.inertia.helpers.flash(connection: ASGIConnection[Any, Any, Any, Any], message: str, category: str = 'info') None[source]

Add a flash message to the session.

Flash messages are stored in the session and passed to the frontend via the flash prop in every Inertia response. They’re automatically cleared after being displayed (pop semantics).

This function works without requiring Litestar’s FlashPlugin or any Jinja2 template configuration, making it ideal for SPA-only Inertia applications.

Parameters:
  • connection – The ASGI connection (Request or WebSocket).

  • message – The message text to display.

  • category – The message category (e.g., “success”, “error”, “warning”, “info”). Defaults to “info”.

Example:

from litestar_vite.inertia import flash

@post("/create")
async def create_item(request: Request) -> InertiaResponse:
    flash(request, "Item created successfully!", "success")
    return InertiaResponse(...)
litestar_vite.inertia.helpers.clear_history(connection: ASGIConnection[Any, Any, Any, Any]) None[source]

Mark that the next response should clear client history encryption keys.

This function sets a session flag that will be consumed by the next InertiaResponse, causing it to include clearHistory: true in the page object. The Inertia client will then regenerate its encryption key, invalidating all previously encrypted history entries.

This should typically be called during logout to ensure sensitive data cannot be recovered from browser history after a user logs out.

Parameters:

connection – The ASGI connection (Request).

Note

Requires session middleware to be configured. See: https://inertiajs.com/history-encryption

Example:

from litestar_vite.inertia import clear_history

@post("/logout")
async def logout(request: Request) -> InertiaRedirect:
    request.session.clear()
    clear_history(request)
    return InertiaRedirect(request, redirect_to="/login")
litestar_vite.inertia.helpers.is_pagination_container(value: Any) bool[source]

Check if a value is a pagination container.

Detects common pagination types from Litestar and Advanced Alchemy: - litestar.pagination.OffsetPagination (items, limit, offset, total) - litestar.pagination.ClassicPagination (items, page_size, current_page, total_pages) - advanced_alchemy.service.OffsetPagination

Also supports any object with an items attribute and pagination metadata.

Parameters:

value – The value to check.

Returns:

True if value appears to be a pagination container.

litestar_vite.inertia.helpers.extract_pagination_scroll_props(value: Any, page_param: str = 'page') tuple[Any, ScrollPropsConfig | None][source]

Extract items and scroll props from a pagination container.

For OffsetPagination, calculates page numbers from limit/offset/total. For ClassicPagination, uses current_page/total_pages directly.

Parameters:
  • value – A pagination container (OffsetPagination, ClassicPagination, etc.).

  • page_param – The query parameter name for pagination (default: “page”).

Returns:

A tuple of (items, scroll_props) where scroll_props is None if value is not a pagination container.

Example:

items, scroll = extract_pagination_scroll_props(pagination)

For OffsetPagination with limit=10, offset=20, total=50 the resulting scroll
props are: ScrollPropsConfig(current_page=3, previous_page=2, next_page=4).
litestar_vite.inertia.helpers.pagination_to_dict(value: Any) dict[str, Any][source]

Convert a pagination container to a dict with items and all metadata.

Dynamically extracts known pagination attributes from any pagination container class. This supports custom pagination implementations as long as they have an items attribute and standard pagination metadata.

The function checks for common pagination attributes like total, limit, offset (for offset pagination), page_size, current_page, total_pages (for classic pagination), and cursor-based attributes. Any found attributes are included in the result dict with camelCase keys.

Parameters:

value – A pagination container with items and metadata attributes.

Returns:

A dict with items and any found pagination metadata (camelCase keys).

Example:

from litestar.pagination import OffsetPagination

pagination = OffsetPagination(items=[1, 2, 3], limit=10, offset=0, total=50)
result = pagination_to_dict(pagination)

The result contains {"items": [1, 2, 3], "total": 50, "limit": 10, "offset": 0}.

Note

This function is used internally by InertiaResponse to preserve pagination metadata when returning pagination containers from routes.