litestar-vite 0.1.1__py3-none-any.whl → 0.15.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- litestar_vite/__init__.py +54 -4
- litestar_vite/__metadata__.py +12 -7
- litestar_vite/cli.py +1048 -10
- litestar_vite/codegen/__init__.py +48 -0
- litestar_vite/codegen/_export.py +229 -0
- litestar_vite/codegen/_inertia.py +619 -0
- litestar_vite/codegen/_openapi.py +280 -0
- litestar_vite/codegen/_routes.py +720 -0
- litestar_vite/codegen/_ts.py +235 -0
- litestar_vite/codegen/_utils.py +141 -0
- litestar_vite/commands.py +73 -0
- litestar_vite/config/__init__.py +997 -0
- litestar_vite/config/_constants.py +97 -0
- litestar_vite/config/_deploy.py +70 -0
- litestar_vite/config/_inertia.py +241 -0
- litestar_vite/config/_paths.py +63 -0
- litestar_vite/config/_runtime.py +235 -0
- litestar_vite/config/_spa.py +93 -0
- litestar_vite/config/_types.py +94 -0
- litestar_vite/deploy.py +366 -0
- litestar_vite/doctor.py +1181 -0
- litestar_vite/exceptions.py +78 -0
- litestar_vite/executor.py +360 -0
- litestar_vite/handler/__init__.py +9 -0
- litestar_vite/handler/_app.py +612 -0
- litestar_vite/handler/_routing.py +130 -0
- litestar_vite/html_transform.py +569 -0
- litestar_vite/inertia/__init__.py +77 -0
- litestar_vite/inertia/_utils.py +119 -0
- litestar_vite/inertia/exception_handler.py +178 -0
- litestar_vite/inertia/helpers.py +1571 -0
- litestar_vite/inertia/middleware.py +54 -0
- litestar_vite/inertia/plugin.py +199 -0
- litestar_vite/inertia/precognition.py +274 -0
- litestar_vite/inertia/request.py +334 -0
- litestar_vite/inertia/response.py +802 -0
- litestar_vite/inertia/types.py +335 -0
- litestar_vite/loader.py +464 -123
- litestar_vite/plugin/__init__.py +687 -0
- litestar_vite/plugin/_process.py +185 -0
- litestar_vite/plugin/_proxy.py +689 -0
- litestar_vite/plugin/_proxy_headers.py +244 -0
- litestar_vite/plugin/_static.py +37 -0
- litestar_vite/plugin/_utils.py +489 -0
- litestar_vite/py.typed +0 -0
- litestar_vite/scaffolding/__init__.py +20 -0
- litestar_vite/scaffolding/generator.py +270 -0
- litestar_vite/scaffolding/templates.py +437 -0
- litestar_vite/templates/__init__.py +0 -0
- litestar_vite/templates/addons/tailwindcss/tailwind.css.j2 +1 -0
- litestar_vite/templates/angular/index.html.j2 +12 -0
- litestar_vite/templates/angular/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/angular/package.json.j2 +36 -0
- litestar_vite/templates/angular/src/app/app.component.css.j2 +3 -0
- litestar_vite/templates/angular/src/app/app.component.html.j2 +1 -0
- litestar_vite/templates/angular/src/app/app.component.ts.j2 +9 -0
- litestar_vite/templates/angular/src/app/app.config.ts.j2 +5 -0
- litestar_vite/templates/angular/src/main.ts.j2 +9 -0
- litestar_vite/templates/angular/src/styles.css.j2 +9 -0
- litestar_vite/templates/angular/tsconfig.app.json.j2 +34 -0
- litestar_vite/templates/angular/tsconfig.json.j2 +20 -0
- litestar_vite/templates/angular/vite.config.ts.j2 +21 -0
- litestar_vite/templates/angular-cli/.postcssrc.json.j2 +5 -0
- litestar_vite/templates/angular-cli/angular.json.j2 +36 -0
- litestar_vite/templates/angular-cli/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/angular-cli/package.json.j2 +28 -0
- litestar_vite/templates/angular-cli/proxy.conf.json.j2 +18 -0
- litestar_vite/templates/angular-cli/src/app/app.component.css.j2 +3 -0
- litestar_vite/templates/angular-cli/src/app/app.component.html.j2 +1 -0
- litestar_vite/templates/angular-cli/src/app/app.component.ts.j2 +9 -0
- litestar_vite/templates/angular-cli/src/app/app.config.ts.j2 +5 -0
- litestar_vite/templates/angular-cli/src/index.html.j2 +13 -0
- litestar_vite/templates/angular-cli/src/main.ts.j2 +6 -0
- litestar_vite/templates/angular-cli/src/styles.css.j2 +10 -0
- litestar_vite/templates/angular-cli/tailwind.config.js.j2 +4 -0
- litestar_vite/templates/angular-cli/tsconfig.app.json.j2 +16 -0
- litestar_vite/templates/angular-cli/tsconfig.json.j2 +26 -0
- litestar_vite/templates/angular-cli/tsconfig.spec.json.j2 +9 -0
- litestar_vite/templates/astro/astro.config.mjs.j2 +28 -0
- litestar_vite/templates/astro/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/astro/src/layouts/Layout.astro.j2 +63 -0
- litestar_vite/templates/astro/src/pages/index.astro.j2 +36 -0
- litestar_vite/templates/astro/src/styles/global.css.j2 +1 -0
- litestar_vite/templates/base/.gitignore.j2 +42 -0
- litestar_vite/templates/base/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/base/package.json.j2 +39 -0
- litestar_vite/templates/base/resources/vite-env.d.ts.j2 +1 -0
- litestar_vite/templates/base/tsconfig.json.j2 +37 -0
- litestar_vite/templates/htmx/src/main.js.j2 +8 -0
- litestar_vite/templates/htmx/templates/base.html.j2.j2 +56 -0
- litestar_vite/templates/htmx/templates/index.html.j2.j2 +13 -0
- litestar_vite/templates/htmx/vite.config.ts.j2 +40 -0
- litestar_vite/templates/nuxt/app.vue.j2 +29 -0
- litestar_vite/templates/nuxt/composables/useApi.ts.j2 +33 -0
- litestar_vite/templates/nuxt/nuxt.config.ts.j2 +31 -0
- litestar_vite/templates/nuxt/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/nuxt/pages/index.vue.j2 +54 -0
- litestar_vite/templates/react/index.html.j2 +13 -0
- litestar_vite/templates/react/src/App.css.j2 +56 -0
- litestar_vite/templates/react/src/App.tsx.j2 +19 -0
- litestar_vite/templates/react/src/main.tsx.j2 +10 -0
- litestar_vite/templates/react/vite.config.ts.j2 +39 -0
- litestar_vite/templates/react-inertia/index.html.j2 +14 -0
- litestar_vite/templates/react-inertia/package.json.j2 +47 -0
- litestar_vite/templates/react-inertia/resources/App.css.j2 +68 -0
- litestar_vite/templates/react-inertia/resources/main.tsx.j2 +17 -0
- litestar_vite/templates/react-inertia/resources/pages/Home.tsx.j2 +18 -0
- litestar_vite/templates/react-inertia/resources/ssr.tsx.j2 +19 -0
- litestar_vite/templates/react-inertia/vite.config.ts.j2 +59 -0
- litestar_vite/templates/react-router/index.html.j2 +12 -0
- litestar_vite/templates/react-router/src/App.css.j2 +17 -0
- litestar_vite/templates/react-router/src/App.tsx.j2 +7 -0
- litestar_vite/templates/react-router/src/main.tsx.j2 +10 -0
- litestar_vite/templates/react-router/vite.config.ts.j2 +39 -0
- litestar_vite/templates/react-tanstack/index.html.j2 +12 -0
- litestar_vite/templates/react-tanstack/openapi-ts.config.ts.j2 +18 -0
- litestar_vite/templates/react-tanstack/src/App.css.j2 +17 -0
- litestar_vite/templates/react-tanstack/src/main.tsx.j2 +21 -0
- litestar_vite/templates/react-tanstack/src/routeTree.gen.ts.j2 +7 -0
- litestar_vite/templates/react-tanstack/src/routes/__root.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/src/routes/books.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/src/routes/index.tsx.j2 +9 -0
- litestar_vite/templates/react-tanstack/vite.config.ts.j2 +39 -0
- litestar_vite/templates/svelte/index.html.j2 +13 -0
- litestar_vite/templates/svelte/src/App.svelte.j2 +30 -0
- litestar_vite/templates/svelte/src/app.css.j2 +45 -0
- litestar_vite/templates/svelte/src/main.ts.j2 +8 -0
- litestar_vite/templates/svelte/src/vite-env.d.ts.j2 +2 -0
- litestar_vite/templates/svelte/svelte.config.js.j2 +5 -0
- litestar_vite/templates/svelte/vite.config.ts.j2 +39 -0
- litestar_vite/templates/svelte-inertia/index.html.j2 +14 -0
- litestar_vite/templates/svelte-inertia/resources/app.css.j2 +21 -0
- litestar_vite/templates/svelte-inertia/resources/main.ts.j2 +11 -0
- litestar_vite/templates/svelte-inertia/resources/pages/Home.svelte.j2 +43 -0
- litestar_vite/templates/svelte-inertia/resources/vite-env.d.ts.j2 +2 -0
- litestar_vite/templates/svelte-inertia/svelte.config.js.j2 +5 -0
- litestar_vite/templates/svelte-inertia/vite.config.ts.j2 +37 -0
- litestar_vite/templates/sveltekit/openapi-ts.config.ts.j2 +15 -0
- litestar_vite/templates/sveltekit/src/app.css.j2 +40 -0
- litestar_vite/templates/sveltekit/src/app.html.j2 +12 -0
- litestar_vite/templates/sveltekit/src/hooks.server.ts.j2 +55 -0
- litestar_vite/templates/sveltekit/src/routes/+layout.svelte.j2 +12 -0
- litestar_vite/templates/sveltekit/src/routes/+page.svelte.j2 +34 -0
- litestar_vite/templates/sveltekit/svelte.config.js.j2 +12 -0
- litestar_vite/templates/sveltekit/tsconfig.json.j2 +14 -0
- litestar_vite/templates/sveltekit/vite.config.ts.j2 +31 -0
- litestar_vite/templates/vue/env.d.ts.j2 +7 -0
- litestar_vite/templates/vue/index.html.j2 +13 -0
- litestar_vite/templates/vue/src/App.vue.j2 +28 -0
- litestar_vite/templates/vue/src/main.ts.j2 +5 -0
- litestar_vite/templates/vue/src/style.css.j2 +45 -0
- litestar_vite/templates/vue/vite.config.ts.j2 +39 -0
- litestar_vite/templates/vue-inertia/env.d.ts.j2 +7 -0
- litestar_vite/templates/vue-inertia/index.html.j2 +14 -0
- litestar_vite/templates/vue-inertia/package.json.j2 +50 -0
- litestar_vite/templates/vue-inertia/resources/main.ts.j2 +18 -0
- litestar_vite/templates/vue-inertia/resources/pages/Home.vue.j2 +22 -0
- litestar_vite/templates/vue-inertia/resources/ssr.ts.j2 +21 -0
- litestar_vite/templates/vue-inertia/resources/style.css.j2 +21 -0
- litestar_vite/templates/vue-inertia/vite.config.ts.j2 +59 -0
- litestar_vite-0.15.0.dist-info/METADATA +230 -0
- litestar_vite-0.15.0.dist-info/RECORD +164 -0
- {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/WHEEL +1 -1
- litestar_vite/config.py +0 -100
- litestar_vite/plugin.py +0 -45
- litestar_vite/template_engine.py +0 -103
- litestar_vite-0.1.1.dist-info/METADATA +0 -68
- litestar_vite-0.1.1.dist-info/RECORD +0 -11
- {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""Constants and utility functions for configuration."""
|
|
2
|
+
|
|
3
|
+
from importlib.util import find_spec
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
|
|
9
|
+
__all__ = (
|
|
10
|
+
"FSSPEC_INSTALLED",
|
|
11
|
+
"JINJA_INSTALLED",
|
|
12
|
+
"TRUE_VALUES",
|
|
13
|
+
"PaginationContainer",
|
|
14
|
+
"default_content_types",
|
|
15
|
+
"default_storage_options",
|
|
16
|
+
"empty_dict_factory",
|
|
17
|
+
"empty_set_factory",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
TRUE_VALUES = {"True", "true", "1", "yes", "Y", "T"}
|
|
21
|
+
JINJA_INSTALLED = bool(find_spec("jinja2"))
|
|
22
|
+
FSSPEC_INSTALLED = bool(find_spec("fsspec"))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@runtime_checkable
|
|
26
|
+
class PaginationContainer(Protocol):
|
|
27
|
+
"""Protocol for pagination containers that can be unwrapped for Inertia scroll.
|
|
28
|
+
|
|
29
|
+
Any type that has `items` and pagination metadata can implement this protocol.
|
|
30
|
+
The response will extract items and calculate scroll_props automatically.
|
|
31
|
+
|
|
32
|
+
Built-in support:
|
|
33
|
+
- litestar.pagination.OffsetPagination
|
|
34
|
+
- litestar.pagination.ClassicPagination
|
|
35
|
+
- advanced_alchemy.service.OffsetPagination
|
|
36
|
+
|
|
37
|
+
Custom types can implement this protocol::
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class MyPagination:
|
|
41
|
+
items: list[T]
|
|
42
|
+
total: int
|
|
43
|
+
limit: int
|
|
44
|
+
offset: int
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
items: "Sequence[Any]"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def empty_dict_factory() -> dict[str, Any]:
|
|
51
|
+
"""Return an empty ``dict[str, Any]``.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
An empty dictionary.
|
|
55
|
+
"""
|
|
56
|
+
return {}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def empty_set_factory() -> set[str]:
|
|
60
|
+
"""Return an empty ``set[str]``.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
An empty set.
|
|
64
|
+
"""
|
|
65
|
+
return set()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def default_content_types() -> dict[str, str]:
|
|
69
|
+
"""Default content-type mappings keyed by file extension.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Dictionary mapping file extensions to MIME types.
|
|
73
|
+
"""
|
|
74
|
+
return {
|
|
75
|
+
".js": "application/javascript",
|
|
76
|
+
".mjs": "application/javascript",
|
|
77
|
+
".cjs": "application/javascript",
|
|
78
|
+
".css": "text/css",
|
|
79
|
+
".html": "text/html",
|
|
80
|
+
".json": "application/json",
|
|
81
|
+
".svg": "image/svg+xml",
|
|
82
|
+
".png": "image/png",
|
|
83
|
+
".jpg": "image/jpeg",
|
|
84
|
+
".jpeg": "image/jpeg",
|
|
85
|
+
".webp": "image/webp",
|
|
86
|
+
".woff2": "font/woff2",
|
|
87
|
+
".woff": "font/woff",
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def default_storage_options() -> dict[str, Any]:
|
|
92
|
+
"""Return an empty storage options dictionary.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
An empty dictionary.
|
|
96
|
+
"""
|
|
97
|
+
return {}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""CDN deployment configuration."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass, field, replace
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from litestar_vite.config._constants import TRUE_VALUES, default_content_types, default_storage_options
|
|
8
|
+
|
|
9
|
+
__all__ = ("DeployConfig",)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class DeployConfig:
|
|
14
|
+
"""CDN deployment configuration.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
enabled: Enable deployment features.
|
|
18
|
+
storage_backend: fsspec URL for the target location (e.g., ``gcs://bucket/path``).
|
|
19
|
+
storage_options: Provider options forwarded to ``fsspec`` (credentials, region, etc.).
|
|
20
|
+
asset_url: Public URL prefix where deployed assets will be served (e.g., ``https://cdn.example.com/assets/``).
|
|
21
|
+
When set and deployment is enabled, this value is written to ``.litestar.json`` as ``deployAssetUrl`` and
|
|
22
|
+
used by the Vite plugin as the ``base`` during ``vite build``. It does not replace ``PathConfig.asset_url``.
|
|
23
|
+
delete_orphaned: Remove remote files not present in the local bundle.
|
|
24
|
+
include_manifest: Upload ``manifest.json`` alongside assets.
|
|
25
|
+
content_types: Optional content-type overrides keyed by file extension.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
enabled: bool = True
|
|
29
|
+
storage_backend: "str | None" = field(default_factory=lambda: os.getenv("VITE_DEPLOY_STORAGE"))
|
|
30
|
+
storage_options: dict[str, Any] = field(default_factory=default_storage_options)
|
|
31
|
+
asset_url: "str | None" = field(default_factory=lambda: os.getenv("VITE_DEPLOY_ASSET_URL"))
|
|
32
|
+
delete_orphaned: bool = field(default_factory=lambda: os.getenv("VITE_DEPLOY_DELETE", "true") in TRUE_VALUES)
|
|
33
|
+
include_manifest: bool = True
|
|
34
|
+
content_types: dict[str, str] = field(default_factory=default_content_types)
|
|
35
|
+
|
|
36
|
+
def __post_init__(self) -> None:
|
|
37
|
+
"""Apply environment fallbacks."""
|
|
38
|
+
if self.storage_backend is None:
|
|
39
|
+
self.storage_backend = os.getenv("VITE_DEPLOY_STORAGE")
|
|
40
|
+
if self.asset_url is None:
|
|
41
|
+
self.asset_url = os.getenv("VITE_DEPLOY_ASSET_URL")
|
|
42
|
+
|
|
43
|
+
if self.asset_url and self.asset_url != "/" and not self.asset_url.endswith("/"):
|
|
44
|
+
self.asset_url = f"{self.asset_url}/"
|
|
45
|
+
|
|
46
|
+
def with_overrides(
|
|
47
|
+
self,
|
|
48
|
+
storage_backend: "str | None" = None,
|
|
49
|
+
storage_options: "dict[str, Any] | None" = None,
|
|
50
|
+
asset_url: "str | None" = None,
|
|
51
|
+
delete_orphaned: "bool | None" = None,
|
|
52
|
+
) -> "DeployConfig":
|
|
53
|
+
"""Return a copy with overrides applied.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
storage_backend: Override for the storage URL.
|
|
57
|
+
storage_options: Override for backend options.
|
|
58
|
+
asset_url: Override for the public asset URL.
|
|
59
|
+
delete_orphaned: Override deletion behaviour.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
DeployConfig copy with updated fields.
|
|
63
|
+
"""
|
|
64
|
+
return replace(
|
|
65
|
+
self,
|
|
66
|
+
storage_backend=storage_backend or self.storage_backend,
|
|
67
|
+
storage_options=storage_options or self.storage_options,
|
|
68
|
+
asset_url=asset_url or self.asset_url,
|
|
69
|
+
delete_orphaned=self.delete_orphaned if delete_orphaned is None else delete_orphaned,
|
|
70
|
+
)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Inertia.js configuration classes."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from litestar_vite.config._constants import empty_dict_factory, empty_set_factory
|
|
7
|
+
|
|
8
|
+
__all__ = ("InertiaConfig", "InertiaSSRConfig", "InertiaTypeGenConfig")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class InertiaSSRConfig:
|
|
13
|
+
"""Server-side rendering settings for Inertia.js.
|
|
14
|
+
|
|
15
|
+
Inertia SSR runs a separate Node server that renders the initial HTML for an
|
|
16
|
+
Inertia page object. Litestar sends the page payload to the SSR server (by
|
|
17
|
+
default at ``http://127.0.0.1:13714/render``) and injects the returned head
|
|
18
|
+
tags and body markup into the HTML response.
|
|
19
|
+
|
|
20
|
+
Notes:
|
|
21
|
+
- This is *not* Litestar-Vite's framework proxy mode (``mode="framework"``; aliases: ``mode="ssr"`` / ``mode="ssg"``).
|
|
22
|
+
- When enabled, failures to contact the SSR server are treated as errors (no silent fallback).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
enabled: bool = True
|
|
26
|
+
url: str = "http://127.0.0.1:13714/render"
|
|
27
|
+
timeout: float = 2.0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class InertiaConfig:
|
|
32
|
+
"""Configuration for InertiaJS support.
|
|
33
|
+
|
|
34
|
+
This is the canonical configuration class for Inertia.js integration.
|
|
35
|
+
Presence of an InertiaConfig instance indicates Inertia is enabled.
|
|
36
|
+
|
|
37
|
+
Note:
|
|
38
|
+
SPA mode (HTML transformation vs Jinja2 templates) is controlled by
|
|
39
|
+
ViteConfig.mode='hybrid'. The app_selector for data-page injection
|
|
40
|
+
is configured via SPAConfig.app_selector.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
root_template: Name of the root template to use.
|
|
44
|
+
component_opt_keys: Identifiers for getting inertia component from route opts.
|
|
45
|
+
redirect_unauthorized_to: Path for unauthorized request redirects.
|
|
46
|
+
redirect_404: Path for 404 request redirects.
|
|
47
|
+
extra_static_page_props: Static props added to every page response.
|
|
48
|
+
extra_session_page_props: Session keys to include in page props.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
root_template: str = "index.html"
|
|
52
|
+
"""Name of the root template to use.
|
|
53
|
+
|
|
54
|
+
This must be a path that is found by the Vite Plugin template config
|
|
55
|
+
"""
|
|
56
|
+
component_opt_keys: "tuple[str, ...]" = ("component", "page")
|
|
57
|
+
"""Identifiers to use on routes to get the inertia component to render.
|
|
58
|
+
|
|
59
|
+
The first key found in the route handler opts will be used. This allows
|
|
60
|
+
semantic flexibility - use "component" or "page" depending on preference.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
# All equivalent:
|
|
64
|
+
@get("/", component="Home")
|
|
65
|
+
@get("/", page="Home")
|
|
66
|
+
|
|
67
|
+
# Custom keys:
|
|
68
|
+
InertiaConfig(component_opt_keys=("view", "component", "page"))
|
|
69
|
+
"""
|
|
70
|
+
redirect_unauthorized_to: "str | None" = None
|
|
71
|
+
"""Optionally supply a path where unauthorized requests should redirect."""
|
|
72
|
+
redirect_404: "str | None" = None
|
|
73
|
+
"""Optionally supply a path where 404 requests should redirect."""
|
|
74
|
+
extra_static_page_props: "dict[str, Any]" = field(default_factory=empty_dict_factory)
|
|
75
|
+
"""A dictionary of values to automatically add in to page props on every response."""
|
|
76
|
+
extra_session_page_props: "set[str] | dict[str, type]" = field(default_factory=empty_set_factory)
|
|
77
|
+
"""Session props to include in page responses.
|
|
78
|
+
|
|
79
|
+
Can be either:
|
|
80
|
+
- A set of session key names (types will be 'unknown')
|
|
81
|
+
- A dict mapping session keys to Python types (auto-registered with OpenAPI)
|
|
82
|
+
|
|
83
|
+
Example with types (recommended):
|
|
84
|
+
extra_session_page_props={"currentTeam": TeamDetail}
|
|
85
|
+
|
|
86
|
+
Example without types (legacy):
|
|
87
|
+
extra_session_page_props={"currentTeam"}
|
|
88
|
+
"""
|
|
89
|
+
encrypt_history: bool = False
|
|
90
|
+
"""Enable browser history encryption globally (v2 feature).
|
|
91
|
+
|
|
92
|
+
When True, all Inertia responses will include `encryptHistory: true`
|
|
93
|
+
in the page object. The Inertia client will encrypt history state
|
|
94
|
+
using browser's crypto API before pushing to history.
|
|
95
|
+
|
|
96
|
+
This prevents sensitive data from being visible in browser history
|
|
97
|
+
after a user logs out. Individual responses can override this setting.
|
|
98
|
+
|
|
99
|
+
Note: Encryption happens client-side; requires HTTPS in production.
|
|
100
|
+
See: https://inertiajs.com/history-encryption
|
|
101
|
+
"""
|
|
102
|
+
type_gen: "InertiaTypeGenConfig | None" = None
|
|
103
|
+
"""Type generation options for Inertia page props.
|
|
104
|
+
|
|
105
|
+
Controls default types in generated page-props.ts. Set to InertiaTypeGenConfig()
|
|
106
|
+
or leave as None for defaults. Use InertiaTypeGenConfig(include_default_auth=False)
|
|
107
|
+
to disable default User/AuthData interfaces for non-standard user models.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
ssr: "InertiaSSRConfig | bool | None" = None
|
|
111
|
+
"""Enable server-side rendering (SSR) for Inertia responses.
|
|
112
|
+
|
|
113
|
+
When enabled, full-page HTML responses will be pre-rendered by a Node SSR server
|
|
114
|
+
and injected into the SPA HTML before returning to the client.
|
|
115
|
+
|
|
116
|
+
Supports:
|
|
117
|
+
- True: enable with defaults -> ``InertiaSSRConfig()``
|
|
118
|
+
- False/None: disabled -> ``None``
|
|
119
|
+
- InertiaSSRConfig: use as-is
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
use_script_element: bool = False
|
|
123
|
+
"""Use a script element instead of data-page attribute for page data.
|
|
124
|
+
|
|
125
|
+
When True, embeds page data in a ``<script type="application/json" id="app_page">``
|
|
126
|
+
element instead of a ``data-page`` attribute on the app element.
|
|
127
|
+
|
|
128
|
+
Benefits:
|
|
129
|
+
- ~37% payload reduction for large pages (no HTML entity escaping)
|
|
130
|
+
- Better performance for pages with complex props
|
|
131
|
+
|
|
132
|
+
Requirements:
|
|
133
|
+
- Client must also enable: ``createInertiaApp({ useScriptElementForInitialPage: true })``
|
|
134
|
+
- Requires Inertia.js v2.3+
|
|
135
|
+
|
|
136
|
+
Disabled by default for compatibility with existing Inertia clients.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
precognition: bool = False
|
|
140
|
+
"""Enable Precognition support for real-time form validation.
|
|
141
|
+
|
|
142
|
+
When True, registers an exception handler that converts validation errors
|
|
143
|
+
to Laravel's Precognition format when the Precognition header is present.
|
|
144
|
+
This enables real-time validation without executing handler side effects.
|
|
145
|
+
|
|
146
|
+
Usage:
|
|
147
|
+
1. Enable in config: InertiaConfig(precognition=True)
|
|
148
|
+
2. Use @precognition decorator on form handlers
|
|
149
|
+
3. Use laravel-precognition-vue/react on the frontend
|
|
150
|
+
|
|
151
|
+
Note on Rate Limiting:
|
|
152
|
+
Real-time validation can generate many requests. Consider:
|
|
153
|
+
- Frontend debouncing (built into laravel-precognition libraries)
|
|
154
|
+
- Server-side throttling for Precognition requests
|
|
155
|
+
- Laravel has no official rate limiting solution for Precognition
|
|
156
|
+
|
|
157
|
+
See: https://laravel.com/docs/precognition
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def __post_init__(self) -> None:
|
|
161
|
+
"""Normalize optional sub-configs."""
|
|
162
|
+
if self.ssr is True:
|
|
163
|
+
self.ssr = InertiaSSRConfig()
|
|
164
|
+
elif self.ssr is False:
|
|
165
|
+
self.ssr = None
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def ssr_config(self) -> "InertiaSSRConfig | None":
|
|
169
|
+
"""Return the SSR config when enabled, otherwise None.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
The resolved SSR config when enabled, otherwise None.
|
|
173
|
+
"""
|
|
174
|
+
if isinstance(self.ssr, InertiaSSRConfig) and self.ssr.enabled:
|
|
175
|
+
return self.ssr
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@dataclass
|
|
180
|
+
class InertiaTypeGenConfig:
|
|
181
|
+
"""Type generation options for Inertia page props.
|
|
182
|
+
|
|
183
|
+
Controls which default types are included in the generated page-props.ts file.
|
|
184
|
+
This follows Laravel Jetstream patterns - sensible defaults for common auth patterns.
|
|
185
|
+
|
|
186
|
+
Attributes:
|
|
187
|
+
include_default_auth: Include default User and AuthData interfaces.
|
|
188
|
+
Default User has: id, email, name. Users extend via module augmentation.
|
|
189
|
+
Set to False if your User model doesn't have these fields (uses uuid, username, etc.)
|
|
190
|
+
include_default_flash: Include default FlashMessages interface.
|
|
191
|
+
Uses { [category: string]: string[] } pattern for flash messages.
|
|
192
|
+
|
|
193
|
+
Example:
|
|
194
|
+
Standard auth (95% of users) - just extend defaults::
|
|
195
|
+
|
|
196
|
+
# Python: use defaults
|
|
197
|
+
ViteConfig(inertia=InertiaConfig())
|
|
198
|
+
|
|
199
|
+
# TypeScript: extend User interface
|
|
200
|
+
declare module 'litestar-vite-plugin/inertia' {
|
|
201
|
+
interface User {
|
|
202
|
+
avatarUrl?: string
|
|
203
|
+
roles: Role[]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
Custom auth (5% of users) - define from scratch::
|
|
208
|
+
|
|
209
|
+
# Python: disable defaults
|
|
210
|
+
ViteConfig(inertia=InertiaConfig(
|
|
211
|
+
type_gen=InertiaTypeGenConfig(include_default_auth=False)
|
|
212
|
+
))
|
|
213
|
+
|
|
214
|
+
# TypeScript: define your custom User
|
|
215
|
+
declare module 'litestar-vite-plugin/inertia' {
|
|
216
|
+
interface User {
|
|
217
|
+
uuid: string // No id!
|
|
218
|
+
username: string // No email!
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
include_default_auth: bool = True
|
|
224
|
+
"""Include default User and AuthData interfaces.
|
|
225
|
+
|
|
226
|
+
When True, generates:
|
|
227
|
+
- User: { id: string, email: string, name?: string | null }
|
|
228
|
+
- AuthData: { isAuthenticated: boolean, user?: User }
|
|
229
|
+
|
|
230
|
+
Users extend via TypeScript module augmentation.
|
|
231
|
+
Set to False if your User model has different required fields.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
include_default_flash: bool = True
|
|
235
|
+
"""Include default FlashMessages interface.
|
|
236
|
+
|
|
237
|
+
When True, generates:
|
|
238
|
+
- FlashMessages: { [category: string]: string[] }
|
|
239
|
+
|
|
240
|
+
Standard flash message pattern used by most web frameworks.
|
|
241
|
+
"""
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""File system paths configuration."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
__all__ = ("PathConfig",)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class PathConfig:
|
|
12
|
+
"""File system paths configuration.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
root: The root directory of the project. Defaults to current working directory.
|
|
16
|
+
bundle_dir: Location of compiled assets and manifest.json.
|
|
17
|
+
resource_dir: TypeScript/JavaScript source directory (equivalent to ./src in Vue/React).
|
|
18
|
+
static_dir: Static public assets directory (served as-is by Vite).
|
|
19
|
+
manifest_name: Name of the Vite manifest file.
|
|
20
|
+
hot_file: Name of the hot file indicating dev server URL.
|
|
21
|
+
asset_url: Base URL for static asset references (prepended to Vite output).
|
|
22
|
+
ssr_output_dir: SSR output directory (optional).
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
root: "str | Path" = field(default_factory=Path.cwd)
|
|
26
|
+
bundle_dir: "str | Path" = field(default_factory=lambda: Path("public"))
|
|
27
|
+
resource_dir: "str | Path" = field(default_factory=lambda: Path("src"))
|
|
28
|
+
static_dir: "str | Path" = field(default_factory=lambda: Path("public"))
|
|
29
|
+
manifest_name: str = "manifest.json"
|
|
30
|
+
hot_file: str = "hot"
|
|
31
|
+
asset_url: str = field(default_factory=lambda: os.getenv("ASSET_URL", "/static/"))
|
|
32
|
+
ssr_output_dir: "str | Path | None" = None
|
|
33
|
+
|
|
34
|
+
def __post_init__(self) -> None:
|
|
35
|
+
"""Normalize path types to Path objects.
|
|
36
|
+
|
|
37
|
+
This also adjusts defaults to prevent Vite's ``publicDir`` (input) from
|
|
38
|
+
colliding with ``outDir`` (output). ``bundle_dir`` is treated as the build
|
|
39
|
+
output directory. When ``static_dir`` equals ``bundle_dir``, Vite may warn
|
|
40
|
+
and effectively disable public asset copying, so ``static_dir`` defaults to
|
|
41
|
+
``<resource_dir>/public`` in that case.
|
|
42
|
+
"""
|
|
43
|
+
if isinstance(self.root, str):
|
|
44
|
+
object.__setattr__(self, "root", Path(self.root))
|
|
45
|
+
if isinstance(self.bundle_dir, str):
|
|
46
|
+
object.__setattr__(self, "bundle_dir", Path(self.bundle_dir))
|
|
47
|
+
if isinstance(self.resource_dir, str):
|
|
48
|
+
object.__setattr__(self, "resource_dir", Path(self.resource_dir))
|
|
49
|
+
if isinstance(self.static_dir, str):
|
|
50
|
+
object.__setattr__(self, "static_dir", Path(self.static_dir))
|
|
51
|
+
if isinstance(self.ssr_output_dir, str):
|
|
52
|
+
object.__setattr__(self, "ssr_output_dir", Path(self.ssr_output_dir))
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
isinstance(self.bundle_dir, Path)
|
|
56
|
+
and isinstance(self.static_dir, Path)
|
|
57
|
+
and self.static_dir == self.bundle_dir
|
|
58
|
+
):
|
|
59
|
+
object.__setattr__(self, "static_dir", Path(self.resource_dir) / "public")
|
|
60
|
+
|
|
61
|
+
asset_url = self.asset_url
|
|
62
|
+
if asset_url and asset_url != "/" and not asset_url.endswith("/"):
|
|
63
|
+
object.__setattr__(self, "asset_url", f"{asset_url}/")
|