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.
Files changed (169) hide show
  1. litestar_vite/__init__.py +54 -4
  2. litestar_vite/__metadata__.py +12 -7
  3. litestar_vite/cli.py +1048 -10
  4. litestar_vite/codegen/__init__.py +48 -0
  5. litestar_vite/codegen/_export.py +229 -0
  6. litestar_vite/codegen/_inertia.py +619 -0
  7. litestar_vite/codegen/_openapi.py +280 -0
  8. litestar_vite/codegen/_routes.py +720 -0
  9. litestar_vite/codegen/_ts.py +235 -0
  10. litestar_vite/codegen/_utils.py +141 -0
  11. litestar_vite/commands.py +73 -0
  12. litestar_vite/config/__init__.py +997 -0
  13. litestar_vite/config/_constants.py +97 -0
  14. litestar_vite/config/_deploy.py +70 -0
  15. litestar_vite/config/_inertia.py +241 -0
  16. litestar_vite/config/_paths.py +63 -0
  17. litestar_vite/config/_runtime.py +235 -0
  18. litestar_vite/config/_spa.py +93 -0
  19. litestar_vite/config/_types.py +94 -0
  20. litestar_vite/deploy.py +366 -0
  21. litestar_vite/doctor.py +1181 -0
  22. litestar_vite/exceptions.py +78 -0
  23. litestar_vite/executor.py +360 -0
  24. litestar_vite/handler/__init__.py +9 -0
  25. litestar_vite/handler/_app.py +612 -0
  26. litestar_vite/handler/_routing.py +130 -0
  27. litestar_vite/html_transform.py +569 -0
  28. litestar_vite/inertia/__init__.py +77 -0
  29. litestar_vite/inertia/_utils.py +119 -0
  30. litestar_vite/inertia/exception_handler.py +178 -0
  31. litestar_vite/inertia/helpers.py +1571 -0
  32. litestar_vite/inertia/middleware.py +54 -0
  33. litestar_vite/inertia/plugin.py +199 -0
  34. litestar_vite/inertia/precognition.py +274 -0
  35. litestar_vite/inertia/request.py +334 -0
  36. litestar_vite/inertia/response.py +802 -0
  37. litestar_vite/inertia/types.py +335 -0
  38. litestar_vite/loader.py +464 -123
  39. litestar_vite/plugin/__init__.py +687 -0
  40. litestar_vite/plugin/_process.py +185 -0
  41. litestar_vite/plugin/_proxy.py +689 -0
  42. litestar_vite/plugin/_proxy_headers.py +244 -0
  43. litestar_vite/plugin/_static.py +37 -0
  44. litestar_vite/plugin/_utils.py +489 -0
  45. litestar_vite/py.typed +0 -0
  46. litestar_vite/scaffolding/__init__.py +20 -0
  47. litestar_vite/scaffolding/generator.py +270 -0
  48. litestar_vite/scaffolding/templates.py +437 -0
  49. litestar_vite/templates/__init__.py +0 -0
  50. litestar_vite/templates/addons/tailwindcss/tailwind.css.j2 +1 -0
  51. litestar_vite/templates/angular/index.html.j2 +12 -0
  52. litestar_vite/templates/angular/openapi-ts.config.ts.j2 +18 -0
  53. litestar_vite/templates/angular/package.json.j2 +36 -0
  54. litestar_vite/templates/angular/src/app/app.component.css.j2 +3 -0
  55. litestar_vite/templates/angular/src/app/app.component.html.j2 +1 -0
  56. litestar_vite/templates/angular/src/app/app.component.ts.j2 +9 -0
  57. litestar_vite/templates/angular/src/app/app.config.ts.j2 +5 -0
  58. litestar_vite/templates/angular/src/main.ts.j2 +9 -0
  59. litestar_vite/templates/angular/src/styles.css.j2 +9 -0
  60. litestar_vite/templates/angular/tsconfig.app.json.j2 +34 -0
  61. litestar_vite/templates/angular/tsconfig.json.j2 +20 -0
  62. litestar_vite/templates/angular/vite.config.ts.j2 +21 -0
  63. litestar_vite/templates/angular-cli/.postcssrc.json.j2 +5 -0
  64. litestar_vite/templates/angular-cli/angular.json.j2 +36 -0
  65. litestar_vite/templates/angular-cli/openapi-ts.config.ts.j2 +18 -0
  66. litestar_vite/templates/angular-cli/package.json.j2 +28 -0
  67. litestar_vite/templates/angular-cli/proxy.conf.json.j2 +18 -0
  68. litestar_vite/templates/angular-cli/src/app/app.component.css.j2 +3 -0
  69. litestar_vite/templates/angular-cli/src/app/app.component.html.j2 +1 -0
  70. litestar_vite/templates/angular-cli/src/app/app.component.ts.j2 +9 -0
  71. litestar_vite/templates/angular-cli/src/app/app.config.ts.j2 +5 -0
  72. litestar_vite/templates/angular-cli/src/index.html.j2 +13 -0
  73. litestar_vite/templates/angular-cli/src/main.ts.j2 +6 -0
  74. litestar_vite/templates/angular-cli/src/styles.css.j2 +10 -0
  75. litestar_vite/templates/angular-cli/tailwind.config.js.j2 +4 -0
  76. litestar_vite/templates/angular-cli/tsconfig.app.json.j2 +16 -0
  77. litestar_vite/templates/angular-cli/tsconfig.json.j2 +26 -0
  78. litestar_vite/templates/angular-cli/tsconfig.spec.json.j2 +9 -0
  79. litestar_vite/templates/astro/astro.config.mjs.j2 +28 -0
  80. litestar_vite/templates/astro/openapi-ts.config.ts.j2 +15 -0
  81. litestar_vite/templates/astro/src/layouts/Layout.astro.j2 +63 -0
  82. litestar_vite/templates/astro/src/pages/index.astro.j2 +36 -0
  83. litestar_vite/templates/astro/src/styles/global.css.j2 +1 -0
  84. litestar_vite/templates/base/.gitignore.j2 +42 -0
  85. litestar_vite/templates/base/openapi-ts.config.ts.j2 +15 -0
  86. litestar_vite/templates/base/package.json.j2 +39 -0
  87. litestar_vite/templates/base/resources/vite-env.d.ts.j2 +1 -0
  88. litestar_vite/templates/base/tsconfig.json.j2 +37 -0
  89. litestar_vite/templates/htmx/src/main.js.j2 +8 -0
  90. litestar_vite/templates/htmx/templates/base.html.j2.j2 +56 -0
  91. litestar_vite/templates/htmx/templates/index.html.j2.j2 +13 -0
  92. litestar_vite/templates/htmx/vite.config.ts.j2 +40 -0
  93. litestar_vite/templates/nuxt/app.vue.j2 +29 -0
  94. litestar_vite/templates/nuxt/composables/useApi.ts.j2 +33 -0
  95. litestar_vite/templates/nuxt/nuxt.config.ts.j2 +31 -0
  96. litestar_vite/templates/nuxt/openapi-ts.config.ts.j2 +15 -0
  97. litestar_vite/templates/nuxt/pages/index.vue.j2 +54 -0
  98. litestar_vite/templates/react/index.html.j2 +13 -0
  99. litestar_vite/templates/react/src/App.css.j2 +56 -0
  100. litestar_vite/templates/react/src/App.tsx.j2 +19 -0
  101. litestar_vite/templates/react/src/main.tsx.j2 +10 -0
  102. litestar_vite/templates/react/vite.config.ts.j2 +39 -0
  103. litestar_vite/templates/react-inertia/index.html.j2 +14 -0
  104. litestar_vite/templates/react-inertia/package.json.j2 +47 -0
  105. litestar_vite/templates/react-inertia/resources/App.css.j2 +68 -0
  106. litestar_vite/templates/react-inertia/resources/main.tsx.j2 +17 -0
  107. litestar_vite/templates/react-inertia/resources/pages/Home.tsx.j2 +18 -0
  108. litestar_vite/templates/react-inertia/resources/ssr.tsx.j2 +19 -0
  109. litestar_vite/templates/react-inertia/vite.config.ts.j2 +59 -0
  110. litestar_vite/templates/react-router/index.html.j2 +12 -0
  111. litestar_vite/templates/react-router/src/App.css.j2 +17 -0
  112. litestar_vite/templates/react-router/src/App.tsx.j2 +7 -0
  113. litestar_vite/templates/react-router/src/main.tsx.j2 +10 -0
  114. litestar_vite/templates/react-router/vite.config.ts.j2 +39 -0
  115. litestar_vite/templates/react-tanstack/index.html.j2 +12 -0
  116. litestar_vite/templates/react-tanstack/openapi-ts.config.ts.j2 +18 -0
  117. litestar_vite/templates/react-tanstack/src/App.css.j2 +17 -0
  118. litestar_vite/templates/react-tanstack/src/main.tsx.j2 +21 -0
  119. litestar_vite/templates/react-tanstack/src/routeTree.gen.ts.j2 +7 -0
  120. litestar_vite/templates/react-tanstack/src/routes/__root.tsx.j2 +9 -0
  121. litestar_vite/templates/react-tanstack/src/routes/books.tsx.j2 +9 -0
  122. litestar_vite/templates/react-tanstack/src/routes/index.tsx.j2 +9 -0
  123. litestar_vite/templates/react-tanstack/vite.config.ts.j2 +39 -0
  124. litestar_vite/templates/svelte/index.html.j2 +13 -0
  125. litestar_vite/templates/svelte/src/App.svelte.j2 +30 -0
  126. litestar_vite/templates/svelte/src/app.css.j2 +45 -0
  127. litestar_vite/templates/svelte/src/main.ts.j2 +8 -0
  128. litestar_vite/templates/svelte/src/vite-env.d.ts.j2 +2 -0
  129. litestar_vite/templates/svelte/svelte.config.js.j2 +5 -0
  130. litestar_vite/templates/svelte/vite.config.ts.j2 +39 -0
  131. litestar_vite/templates/svelte-inertia/index.html.j2 +14 -0
  132. litestar_vite/templates/svelte-inertia/resources/app.css.j2 +21 -0
  133. litestar_vite/templates/svelte-inertia/resources/main.ts.j2 +11 -0
  134. litestar_vite/templates/svelte-inertia/resources/pages/Home.svelte.j2 +43 -0
  135. litestar_vite/templates/svelte-inertia/resources/vite-env.d.ts.j2 +2 -0
  136. litestar_vite/templates/svelte-inertia/svelte.config.js.j2 +5 -0
  137. litestar_vite/templates/svelte-inertia/vite.config.ts.j2 +37 -0
  138. litestar_vite/templates/sveltekit/openapi-ts.config.ts.j2 +15 -0
  139. litestar_vite/templates/sveltekit/src/app.css.j2 +40 -0
  140. litestar_vite/templates/sveltekit/src/app.html.j2 +12 -0
  141. litestar_vite/templates/sveltekit/src/hooks.server.ts.j2 +55 -0
  142. litestar_vite/templates/sveltekit/src/routes/+layout.svelte.j2 +12 -0
  143. litestar_vite/templates/sveltekit/src/routes/+page.svelte.j2 +34 -0
  144. litestar_vite/templates/sveltekit/svelte.config.js.j2 +12 -0
  145. litestar_vite/templates/sveltekit/tsconfig.json.j2 +14 -0
  146. litestar_vite/templates/sveltekit/vite.config.ts.j2 +31 -0
  147. litestar_vite/templates/vue/env.d.ts.j2 +7 -0
  148. litestar_vite/templates/vue/index.html.j2 +13 -0
  149. litestar_vite/templates/vue/src/App.vue.j2 +28 -0
  150. litestar_vite/templates/vue/src/main.ts.j2 +5 -0
  151. litestar_vite/templates/vue/src/style.css.j2 +45 -0
  152. litestar_vite/templates/vue/vite.config.ts.j2 +39 -0
  153. litestar_vite/templates/vue-inertia/env.d.ts.j2 +7 -0
  154. litestar_vite/templates/vue-inertia/index.html.j2 +14 -0
  155. litestar_vite/templates/vue-inertia/package.json.j2 +50 -0
  156. litestar_vite/templates/vue-inertia/resources/main.ts.j2 +18 -0
  157. litestar_vite/templates/vue-inertia/resources/pages/Home.vue.j2 +22 -0
  158. litestar_vite/templates/vue-inertia/resources/ssr.ts.j2 +21 -0
  159. litestar_vite/templates/vue-inertia/resources/style.css.j2 +21 -0
  160. litestar_vite/templates/vue-inertia/vite.config.ts.j2 +59 -0
  161. litestar_vite-0.15.0.dist-info/METADATA +230 -0
  162. litestar_vite-0.15.0.dist-info/RECORD +164 -0
  163. {litestar_vite-0.1.1.dist-info → litestar_vite-0.15.0.dist-info}/WHEEL +1 -1
  164. litestar_vite/config.py +0 -100
  165. litestar_vite/plugin.py +0 -45
  166. litestar_vite/template_engine.py +0 -103
  167. litestar_vite-0.1.1.dist-info/METADATA +0 -68
  168. litestar_vite-0.1.1.dist-info/RECORD +0 -11
  169. {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}/")