litestar-vite 0.15.0__py3-none-any.whl → 0.15.0rc2__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/_codegen/__init__.py +26 -0
- litestar_vite/_codegen/inertia.py +407 -0
- litestar_vite/{codegen/_openapi.py → _codegen/openapi.py} +11 -58
- litestar_vite/{codegen/_routes.py → _codegen/routes.py} +43 -110
- litestar_vite/{codegen/_ts.py → _codegen/ts.py} +19 -19
- litestar_vite/_handler/__init__.py +8 -0
- litestar_vite/{handler/_app.py → _handler/app.py} +29 -117
- litestar_vite/cli.py +254 -155
- litestar_vite/codegen.py +39 -0
- litestar_vite/commands.py +6 -0
- litestar_vite/{config/__init__.py → config.py} +726 -99
- litestar_vite/deploy.py +3 -14
- litestar_vite/doctor.py +6 -8
- litestar_vite/executor.py +1 -45
- litestar_vite/handler.py +9 -0
- litestar_vite/html_transform.py +5 -148
- litestar_vite/inertia/__init__.py +0 -24
- litestar_vite/inertia/_utils.py +0 -5
- litestar_vite/inertia/exception_handler.py +16 -22
- litestar_vite/inertia/helpers.py +18 -546
- litestar_vite/inertia/plugin.py +11 -77
- litestar_vite/inertia/request.py +0 -48
- litestar_vite/inertia/response.py +17 -113
- litestar_vite/inertia/types.py +0 -19
- litestar_vite/loader.py +7 -7
- litestar_vite/plugin.py +2184 -0
- litestar_vite/templates/angular/package.json.j2 +1 -2
- litestar_vite/templates/angular-cli/package.json.j2 +1 -2
- litestar_vite/templates/base/package.json.j2 +1 -2
- litestar_vite/templates/react-inertia/package.json.j2 +1 -2
- litestar_vite/templates/vue-inertia/package.json.j2 +1 -2
- {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/METADATA +5 -5
- {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/RECORD +36 -49
- litestar_vite/codegen/__init__.py +0 -48
- litestar_vite/codegen/_export.py +0 -229
- litestar_vite/codegen/_inertia.py +0 -619
- litestar_vite/codegen/_utils.py +0 -141
- litestar_vite/config/_constants.py +0 -97
- litestar_vite/config/_deploy.py +0 -70
- litestar_vite/config/_inertia.py +0 -241
- litestar_vite/config/_paths.py +0 -63
- litestar_vite/config/_runtime.py +0 -235
- litestar_vite/config/_spa.py +0 -93
- litestar_vite/config/_types.py +0 -94
- litestar_vite/handler/__init__.py +0 -9
- litestar_vite/inertia/precognition.py +0 -274
- litestar_vite/plugin/__init__.py +0 -687
- litestar_vite/plugin/_process.py +0 -185
- litestar_vite/plugin/_proxy.py +0 -689
- litestar_vite/plugin/_proxy_headers.py +0 -244
- litestar_vite/plugin/_static.py +0 -37
- litestar_vite/plugin/_utils.py +0 -489
- /litestar_vite/{handler/_routing.py → _handler/routing.py} +0 -0
- {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/WHEEL +0 -0
- {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/licenses/LICENSE +0 -0
litestar_vite/cli.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import contextlib
|
|
2
1
|
import os
|
|
3
2
|
import subprocess
|
|
4
3
|
import sys
|
|
@@ -6,6 +5,7 @@ from pathlib import Path
|
|
|
6
5
|
from textwrap import dedent
|
|
7
6
|
from typing import TYPE_CHECKING, Any
|
|
8
7
|
|
|
8
|
+
import msgspec
|
|
9
9
|
from click import Choice, Context, group, option
|
|
10
10
|
from click import Path as ClickPath
|
|
11
11
|
from litestar.cli._utils import ( # pyright: ignore[reportPrivateImportUsage]
|
|
@@ -14,15 +14,25 @@ from litestar.cli._utils import ( # pyright: ignore[reportPrivateImportUsage]
|
|
|
14
14
|
LitestarGroup,
|
|
15
15
|
console,
|
|
16
16
|
)
|
|
17
|
+
from litestar.exceptions import SerializationException
|
|
18
|
+
from litestar.serialization import decode_json, encode_json, get_serializer
|
|
17
19
|
from rich.panel import Panel
|
|
18
20
|
from rich.prompt import Confirm, Prompt
|
|
19
21
|
|
|
20
|
-
from litestar_vite.codegen import
|
|
21
|
-
from litestar_vite.config import
|
|
22
|
+
from litestar_vite.codegen import generate_inertia_pages_json, generate_routes_json, generate_routes_ts
|
|
23
|
+
from litestar_vite.config import (
|
|
24
|
+
DeployConfig,
|
|
25
|
+
ExternalDevServer,
|
|
26
|
+
InertiaConfig,
|
|
27
|
+
InertiaTypeGenConfig,
|
|
28
|
+
LoggingConfig,
|
|
29
|
+
TypeGenConfig,
|
|
30
|
+
ViteConfig,
|
|
31
|
+
)
|
|
22
32
|
from litestar_vite.deploy import ViteDeployer, format_bytes
|
|
23
33
|
from litestar_vite.doctor import ViteDoctor
|
|
24
34
|
from litestar_vite.exceptions import ViteExecutionError
|
|
25
|
-
from litestar_vite.plugin import VitePlugin, set_environment
|
|
35
|
+
from litestar_vite.plugin import VitePlugin, resolve_litestar_version, set_environment
|
|
26
36
|
from litestar_vite.scaffolding import TemplateContext, generate_project, get_available_templates
|
|
27
37
|
from litestar_vite.scaffolding.templates import FrameworkType, get_template
|
|
28
38
|
|
|
@@ -87,6 +97,19 @@ def _apply_cli_log_level(config: ViteConfig, *, verbose: bool = False, quiet: bo
|
|
|
87
97
|
config.reset_executor()
|
|
88
98
|
|
|
89
99
|
|
|
100
|
+
def _relative_path(path: Path) -> str:
|
|
101
|
+
"""Return path relative to CWD when possible.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
The relative path string when possible, otherwise the absolute path string.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
return str(path.relative_to(Path.cwd()))
|
|
109
|
+
except ValueError:
|
|
110
|
+
return str(path)
|
|
111
|
+
|
|
112
|
+
|
|
90
113
|
def _print_recommended_config(template_name: str, resource_dir: str, bundle_dir: str) -> None:
|
|
91
114
|
"""Print recommended ViteConfig for the scaffolded template.
|
|
92
115
|
|
|
@@ -185,13 +208,9 @@ def _build_deploy_config(
|
|
|
185
208
|
return deploy_config
|
|
186
209
|
|
|
187
210
|
|
|
188
|
-
def _run_vite_build(
|
|
189
|
-
config: ViteConfig, root_dir: Path, console: Any, no_build: bool, app: "Litestar | None" = None
|
|
190
|
-
) -> None:
|
|
211
|
+
def _run_vite_build(config: ViteConfig, root_dir: Path, console: Any, no_build: bool) -> None:
|
|
191
212
|
"""Run Vite build unless skipped.
|
|
192
213
|
|
|
193
|
-
If app is provided, exports schema/routes before building.
|
|
194
|
-
|
|
195
214
|
Raises:
|
|
196
215
|
SystemExit: If the build fails.
|
|
197
216
|
"""
|
|
@@ -199,14 +218,10 @@ def _run_vite_build(
|
|
|
199
218
|
console.print("[dim]Skipping Vite build (--no-build).[/]")
|
|
200
219
|
return
|
|
201
220
|
|
|
202
|
-
# Export schema/routes if app is provided
|
|
203
|
-
if app is not None:
|
|
204
|
-
_generate_schema_and_routes(app, config, console)
|
|
205
|
-
|
|
206
221
|
console.rule("[yellow]Starting Vite build process[/]", align="left")
|
|
207
222
|
if config.set_environment:
|
|
208
|
-
set_environment(config=config, asset_url_override=config.asset_url)
|
|
209
|
-
os.environ
|
|
223
|
+
set_environment(config=config, asset_url_override=config.base_url or config.asset_url)
|
|
224
|
+
os.environ["VITE_BASE_URL"] = config.base_url or config.asset_url or "/"
|
|
210
225
|
try:
|
|
211
226
|
config.executor.execute(config.build_command, cwd=root_dir)
|
|
212
227
|
console.print("[bold green]✓ Build complete[/]")
|
|
@@ -218,36 +233,52 @@ def _run_vite_build(
|
|
|
218
233
|
def _generate_schema_and_routes(app: "Litestar", config: ViteConfig, console: Any) -> None:
|
|
219
234
|
"""Export OpenAPI schema, routes, and Inertia page props prior to running a build.
|
|
220
235
|
|
|
221
|
-
Uses the shared `export_integration_assets` function to guarantee byte-identical
|
|
222
|
-
output between CLI and Plugin.
|
|
223
|
-
|
|
224
236
|
Skips generation when type generation is disabled.
|
|
225
237
|
|
|
238
|
+
When Inertia page-props export is enabled, the generator may add additional component schemas
|
|
239
|
+
for routes that are excluded from OpenAPI. In that case, this function persists the augmented
|
|
240
|
+
OpenAPI document so the TypeScript generator can emit those types.
|
|
241
|
+
|
|
226
242
|
Raises:
|
|
227
243
|
LitestarCLIException: If export fails.
|
|
228
244
|
"""
|
|
229
|
-
from litestar_vite.codegen import export_integration_assets
|
|
230
|
-
|
|
231
245
|
types_config = config.types
|
|
232
246
|
if not isinstance(types_config, TypeGenConfig):
|
|
233
247
|
return
|
|
234
248
|
|
|
235
249
|
console.print("[dim]Preparing OpenAPI schema and routes...[/]")
|
|
250
|
+
_export_openapi_schema(app, types_config)
|
|
251
|
+
_export_routes_metadata(app, types_config)
|
|
236
252
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
console.print(f"[
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
253
|
+
if types_config.generate_routes:
|
|
254
|
+
console.print("[dim]3. Exporting typed routes...[/]")
|
|
255
|
+
try:
|
|
256
|
+
routes_ts_content = generate_routes_ts(app)
|
|
257
|
+
routes_ts_path = types_config.routes_ts_path or (types_config.output / "routes.ts")
|
|
258
|
+
routes_ts_path.parent.mkdir(parents=True, exist_ok=True)
|
|
259
|
+
routes_ts_path.write_text(routes_ts_content, encoding="utf-8")
|
|
260
|
+
console.print(f"[green]✓ Typed routes exported to {_relative_path(routes_ts_path)}[/]")
|
|
261
|
+
except OSError as exc: # pragma: no cover
|
|
262
|
+
msg = f"Failed to export typed routes: {exc}"
|
|
263
|
+
raise LitestarCLIException(msg) from exc
|
|
264
|
+
|
|
265
|
+
if isinstance(config.inertia, InertiaConfig) and types_config.generate_page_props and types_config.page_props_path:
|
|
266
|
+
openapi_schema: dict[str, Any] | None = None
|
|
267
|
+
try:
|
|
268
|
+
if types_config.openapi_path and types_config.openapi_path.exists():
|
|
269
|
+
openapi_schema = decode_json(types_config.openapi_path.read_bytes())
|
|
270
|
+
except (OSError, SerializationException):
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
_export_inertia_pages_metadata(app, types_config, config.inertia, openapi_schema)
|
|
274
|
+
if openapi_schema is not None and types_config.openapi_path is not None:
|
|
275
|
+
try:
|
|
276
|
+
schema_content = msgspec.json.format(encode_json(openapi_schema), indent=2)
|
|
277
|
+
types_config.openapi_path.parent.mkdir(parents=True, exist_ok=True)
|
|
278
|
+
types_config.openapi_path.write_bytes(schema_content)
|
|
279
|
+
except OSError as exc: # pragma: no cover
|
|
280
|
+
msg = f"Failed to update OpenAPI schema: {exc}"
|
|
281
|
+
raise LitestarCLIException(msg) from exc
|
|
251
282
|
|
|
252
283
|
|
|
253
284
|
@group(cls=LitestarGroup, name="assets")
|
|
@@ -585,46 +616,6 @@ def vite_install(app: "Litestar", verbose: "bool", quiet: "bool") -> None:
|
|
|
585
616
|
console.print("[red]Executor not configured.[/]")
|
|
586
617
|
|
|
587
618
|
|
|
588
|
-
@vite_group.command(name="update", help="Update frontend packages.")
|
|
589
|
-
@option(
|
|
590
|
-
"--latest", type=bool, help="Update to latest versions (ignoring semver constraints).", default=False, is_flag=True
|
|
591
|
-
)
|
|
592
|
-
@option("--verbose", type=bool, help="Enable verbose output.", default=False, is_flag=True)
|
|
593
|
-
@option("--quiet", type=bool, help="Suppress non-essential output.", default=False, is_flag=True)
|
|
594
|
-
def vite_update(app: "Litestar", latest: "bool", verbose: "bool", quiet: "bool") -> None:
|
|
595
|
-
"""Update frontend packages.
|
|
596
|
-
|
|
597
|
-
By default, updates packages within their semver constraints defined in package.json.
|
|
598
|
-
Use --latest to update to the newest versions available.
|
|
599
|
-
|
|
600
|
-
Raises:
|
|
601
|
-
SystemExit: If the update fails.
|
|
602
|
-
"""
|
|
603
|
-
if verbose:
|
|
604
|
-
app.debug = True
|
|
605
|
-
|
|
606
|
-
plugin = app.plugins.get(VitePlugin)
|
|
607
|
-
|
|
608
|
-
_apply_cli_log_level(plugin.config, verbose=verbose, quiet=quiet)
|
|
609
|
-
|
|
610
|
-
if not quiet:
|
|
611
|
-
if latest:
|
|
612
|
-
console.rule("[yellow]Updating packages to latest versions[/]", align="left")
|
|
613
|
-
else:
|
|
614
|
-
console.rule("[yellow]Updating packages[/]", align="left")
|
|
615
|
-
|
|
616
|
-
if plugin.config.executor:
|
|
617
|
-
root_dir = Path(plugin.config.root_dir or Path.cwd())
|
|
618
|
-
try:
|
|
619
|
-
plugin.config.executor.update(root_dir, latest=latest)
|
|
620
|
-
console.print("[bold green]✓ Packages updated[/]")
|
|
621
|
-
except ViteExecutionError as e:
|
|
622
|
-
console.print(f"[bold red]✗ Package update failed: {e!s}[/]")
|
|
623
|
-
raise SystemExit(1) from None
|
|
624
|
-
else:
|
|
625
|
-
console.print("[red]Executor not configured.[/]")
|
|
626
|
-
|
|
627
|
-
|
|
628
619
|
@vite_group.command(name="build", help="Building frontend assets with Vite.")
|
|
629
620
|
@option("--verbose", type=bool, help="Enable verbose output.", default=False, is_flag=True)
|
|
630
621
|
@option("--quiet", type=bool, help="Suppress non-essential output.", default=False, is_flag=True)
|
|
@@ -710,9 +701,8 @@ def vite_deploy(
|
|
|
710
701
|
|
|
711
702
|
root_dir = Path(config.root_dir or Path.cwd())
|
|
712
703
|
bundle_dir = config.bundle_dir
|
|
713
|
-
|
|
714
704
|
try:
|
|
715
|
-
_run_vite_build(config, root_dir, console, no_build
|
|
705
|
+
_run_vite_build(config, root_dir, console, no_build)
|
|
716
706
|
except SystemExit as exc:
|
|
717
707
|
console.print(f"[red]{exc}[/]")
|
|
718
708
|
sys.exit(1)
|
|
@@ -751,7 +741,7 @@ def vite_deploy(
|
|
|
751
741
|
|
|
752
742
|
@vite_group.command(
|
|
753
743
|
name="serve",
|
|
754
|
-
help="Serve frontend assets. For
|
|
744
|
+
help="Serve frontend assets. For SSR frameworks (mode='ssr'), runs production Node server. Otherwise runs Vite dev server.",
|
|
755
745
|
)
|
|
756
746
|
@option("--verbose", type=bool, help="Enable verbose output.", default=False, is_flag=True)
|
|
757
747
|
@option("--quiet", type=bool, help="Suppress non-essential output.", default=False, is_flag=True)
|
|
@@ -862,13 +852,12 @@ def export_routes(
|
|
|
862
852
|
|
|
863
853
|
console.rule(f"[yellow]Exporting typed routes to {output}[/]", align="left")
|
|
864
854
|
|
|
865
|
-
|
|
866
|
-
routes_ts_content = generate_routes_ts(app, only=only_list, exclude=exclude_list, global_route=global_route)
|
|
855
|
+
routes_ts_content = generate_routes_ts(app, only=only_list, exclude=exclude_list)
|
|
867
856
|
|
|
868
857
|
try:
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
console.print(f"[green]✓ Typed routes exported to {output}[/]
|
|
858
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
859
|
+
output.write_text(routes_ts_content, encoding="utf-8")
|
|
860
|
+
console.print(f"[green]✓ Typed routes exported to {output}[/]")
|
|
872
861
|
except OSError as e: # pragma: no cover
|
|
873
862
|
msg = f"Failed to write routes to path {output}"
|
|
874
863
|
raise LitestarCLIException(msg) from e
|
|
@@ -888,16 +877,125 @@ def export_routes(
|
|
|
888
877
|
)
|
|
889
878
|
|
|
890
879
|
try:
|
|
891
|
-
content =
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
console.print(f"[green]✓ Routes exported to {output}[/]
|
|
880
|
+
content = msgspec.json.format(encode_json(routes_data), indent=2)
|
|
881
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
882
|
+
output.write_bytes(content)
|
|
883
|
+
console.print(f"[green]✓ Routes exported to {output}[/]")
|
|
895
884
|
console.print(f"[dim] {len(routes_data.get('routes', {}))} routes exported[/]")
|
|
896
885
|
except OSError as e: # pragma: no cover
|
|
897
886
|
msg = f"Failed to write routes to path {output}"
|
|
898
887
|
raise LitestarCLIException(msg) from e
|
|
899
888
|
|
|
900
889
|
|
|
890
|
+
def _export_openapi_schema(app: "Litestar", types_config: Any) -> None:
|
|
891
|
+
"""Export OpenAPI schema to file.
|
|
892
|
+
|
|
893
|
+
Args:
|
|
894
|
+
app: The Litestar application instance.
|
|
895
|
+
types_config: The TypeGenConfig instance.
|
|
896
|
+
|
|
897
|
+
Raises:
|
|
898
|
+
LitestarCLIException: If export fails.
|
|
899
|
+
"""
|
|
900
|
+
console.print("[dim]1. Exporting OpenAPI schema...[/]")
|
|
901
|
+
try:
|
|
902
|
+
serializer = get_serializer(app.type_encoders)
|
|
903
|
+
schema_dict = app.openapi_schema.to_schema()
|
|
904
|
+
schema_content = msgspec.json.format(encode_json(schema_dict, serializer=serializer), indent=2)
|
|
905
|
+
types_config.openapi_path.parent.mkdir(parents=True, exist_ok=True)
|
|
906
|
+
types_config.openapi_path.write_bytes(schema_content)
|
|
907
|
+
console.print(f"[green]✓ Schema exported to {_relative_path(types_config.openapi_path)}[/]")
|
|
908
|
+
except OSError as e:
|
|
909
|
+
msg = f"Failed to export OpenAPI schema: {e}"
|
|
910
|
+
raise LitestarCLIException(msg) from e
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def _export_routes_metadata(app: "Litestar", types_config: Any) -> None:
|
|
914
|
+
"""Export routes metadata to file.
|
|
915
|
+
|
|
916
|
+
Args:
|
|
917
|
+
app: The Litestar application instance.
|
|
918
|
+
types_config: The TypeGenConfig instance.
|
|
919
|
+
|
|
920
|
+
Raises:
|
|
921
|
+
LitestarCLIException: If export fails.
|
|
922
|
+
"""
|
|
923
|
+
console.print("[dim]2. Exporting route metadata...[/]")
|
|
924
|
+
try:
|
|
925
|
+
routes_data = generate_routes_json(app, include_components=True)
|
|
926
|
+
routes_data["litestar_version"] = resolve_litestar_version()
|
|
927
|
+
routes_content = msgspec.json.format(encode_json(routes_data), indent=2)
|
|
928
|
+
types_config.routes_path.parent.mkdir(parents=True, exist_ok=True)
|
|
929
|
+
types_config.routes_path.write_bytes(routes_content)
|
|
930
|
+
console.print(f"[green]✓ Routes exported to {_relative_path(types_config.routes_path)}[/]")
|
|
931
|
+
except OSError as e:
|
|
932
|
+
msg = f"Failed to export routes: {e}"
|
|
933
|
+
raise LitestarCLIException(msg) from e
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
def _export_routes_typescript(app: "Litestar", types_config: Any) -> None:
|
|
937
|
+
"""Export typed routes TypeScript file (Ziggy-style).
|
|
938
|
+
|
|
939
|
+
Args:
|
|
940
|
+
app: The Litestar application instance.
|
|
941
|
+
types_config: The TypeGenConfig instance.
|
|
942
|
+
|
|
943
|
+
Raises:
|
|
944
|
+
LitestarCLIException: If export fails.
|
|
945
|
+
"""
|
|
946
|
+
if not types_config.generate_routes:
|
|
947
|
+
return
|
|
948
|
+
|
|
949
|
+
console.print("[dim] Generating typed routes.ts...[/]")
|
|
950
|
+
try:
|
|
951
|
+
ts_content = generate_routes_ts(app)
|
|
952
|
+
types_config.routes_ts_path.parent.mkdir(parents=True, exist_ok=True)
|
|
953
|
+
types_config.routes_ts_path.write_text(ts_content)
|
|
954
|
+
console.print(f"[green]✓ Typed routes generated at {_relative_path(types_config.routes_ts_path)}[/]")
|
|
955
|
+
except OSError as e:
|
|
956
|
+
msg = f"Failed to generate typed routes: {e}"
|
|
957
|
+
raise LitestarCLIException(msg) from e
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
def _export_inertia_pages_metadata(
|
|
961
|
+
app: "Litestar", types_config: Any, inertia_config: Any, openapi_schema: "dict[str, Any] | None" = None
|
|
962
|
+
) -> None:
|
|
963
|
+
"""Export Inertia page props metadata to file.
|
|
964
|
+
|
|
965
|
+
Args:
|
|
966
|
+
app: The Litestar application instance.
|
|
967
|
+
types_config: The TypeGenConfig instance.
|
|
968
|
+
inertia_config: The InertiaConfig instance.
|
|
969
|
+
openapi_schema: Optional pre-loaded OpenAPI schema.
|
|
970
|
+
|
|
971
|
+
Raises:
|
|
972
|
+
LitestarCLIException: If export fails.
|
|
973
|
+
"""
|
|
974
|
+
console.print("[dim]4. Exporting Inertia page props metadata...[/]")
|
|
975
|
+
inertia_type_gen = inertia_config.type_gen
|
|
976
|
+
if inertia_type_gen is None:
|
|
977
|
+
inertia_type_gen = InertiaTypeGenConfig()
|
|
978
|
+
|
|
979
|
+
try:
|
|
980
|
+
pages_data = generate_inertia_pages_json(
|
|
981
|
+
app,
|
|
982
|
+
openapi_schema=openapi_schema,
|
|
983
|
+
include_default_auth=inertia_type_gen.include_default_auth,
|
|
984
|
+
include_default_flash=inertia_type_gen.include_default_flash,
|
|
985
|
+
inertia_config=inertia_config,
|
|
986
|
+
types_config=types_config,
|
|
987
|
+
)
|
|
988
|
+
pages_content = msgspec.json.format(encode_json(pages_data), indent=2)
|
|
989
|
+
types_config.page_props_path.parent.mkdir(parents=True, exist_ok=True)
|
|
990
|
+
types_config.page_props_path.write_bytes(pages_content)
|
|
991
|
+
num_pages = len(pages_data.get("pages", {}))
|
|
992
|
+
console.print(f"[green]✓ Page props exported to {_relative_path(types_config.page_props_path)}[/]")
|
|
993
|
+
console.print(f"[dim] {num_pages} Inertia page(s) found[/]")
|
|
994
|
+
except OSError as e:
|
|
995
|
+
msg = f"Failed to export Inertia page props: {e}"
|
|
996
|
+
raise LitestarCLIException(msg) from e
|
|
997
|
+
|
|
998
|
+
|
|
901
999
|
def _get_package_executor_cmd(executor: "str | None", package: str) -> "list[str]":
|
|
902
1000
|
"""Build package executor command list.
|
|
903
1001
|
|
|
@@ -924,43 +1022,67 @@ def _get_package_executor_cmd(executor: "str | None", package: str) -> "list[str
|
|
|
924
1022
|
return ["npx", package]
|
|
925
1023
|
|
|
926
1024
|
|
|
927
|
-
def
|
|
928
|
-
""
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
`litestar assets generate-types`. It calls `litestar-vite-typegen` which
|
|
932
|
-
handles both @hey-api/openapi-ts and page-props.ts generation.
|
|
1025
|
+
def _run_openapi_ts(
|
|
1026
|
+
config: Any, verbose: bool, install_command: "list[str] | None" = None, executor: "str | None" = None
|
|
1027
|
+
) -> None:
|
|
1028
|
+
"""Run @hey-api/openapi-ts to generate TypeScript types.
|
|
933
1029
|
|
|
934
1030
|
Args:
|
|
935
1031
|
config: The ViteConfig instance (with .types resolved).
|
|
936
1032
|
verbose: Whether to show verbose output.
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
LitestarCLIException: If type generation fails.
|
|
1033
|
+
install_command: Command used to install JS dependencies.
|
|
1034
|
+
executor: The JS runtime executor (node, bun, deno, yarn, pnpm).
|
|
940
1035
|
"""
|
|
1036
|
+
types_config = config.types
|
|
941
1037
|
root_dir = config.root_dir or Path.cwd()
|
|
942
|
-
|
|
1038
|
+
resource_dir = Path(config.resource_dir)
|
|
1039
|
+
if not resource_dir.is_absolute():
|
|
1040
|
+
resource_dir = root_dir / resource_dir
|
|
943
1041
|
|
|
944
|
-
|
|
945
|
-
pkg_cmd = _get_package_executor_cmd(executor, "litestar-vite-typegen")
|
|
946
|
-
cmd = [*pkg_cmd]
|
|
1042
|
+
console.print("[dim]3. Running @hey-api/openapi-ts...[/]")
|
|
947
1043
|
|
|
948
|
-
|
|
949
|
-
|
|
1044
|
+
install_cmd = install_command or ["npm", "install"]
|
|
1045
|
+
pkg_cmd = _get_package_executor_cmd(executor, "@hey-api/openapi-ts")
|
|
950
1046
|
|
|
951
1047
|
try:
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1048
|
+
check_cmd = [*pkg_cmd, "--version"]
|
|
1049
|
+
subprocess.run(check_cmd, check=True, capture_output=True, cwd=root_dir)
|
|
1050
|
+
|
|
1051
|
+
candidate_configs = [
|
|
1052
|
+
resource_dir / "openapi-ts.config.ts",
|
|
1053
|
+
resource_dir / "hey-api.config.ts",
|
|
1054
|
+
root_dir / "openapi-ts.config.ts",
|
|
1055
|
+
root_dir / "hey-api.config.ts",
|
|
1056
|
+
]
|
|
1057
|
+
config_path = next((p for p in candidate_configs if p.exists()), None)
|
|
1058
|
+
|
|
1059
|
+
if config_path is not None:
|
|
1060
|
+
openapi_cmd = [*pkg_cmd, "--file", str(config_path)]
|
|
1061
|
+
else:
|
|
1062
|
+
openapi_cmd = [*pkg_cmd, "-i", str(types_config.openapi_path), "-o", str(types_config.output)]
|
|
1063
|
+
|
|
1064
|
+
plugins: list[str] = ["@hey-api/typescript", "@hey-api/schemas"]
|
|
1065
|
+
if types_config.generate_sdk:
|
|
1066
|
+
plugins.extend(["@hey-api/sdk"])
|
|
1067
|
+
if types_config.generate_zod:
|
|
1068
|
+
plugins.append("zod")
|
|
1069
|
+
|
|
1070
|
+
if plugins:
|
|
1071
|
+
openapi_cmd.extend(["--plugins", *plugins])
|
|
1072
|
+
|
|
1073
|
+
subprocess.run(openapi_cmd, check=True, cwd=root_dir)
|
|
1074
|
+
console.print(f"[green]✓ Types generated in {types_config.output}[/]")
|
|
1075
|
+
except subprocess.CalledProcessError as e:
|
|
1076
|
+
console.print("[yellow]! @hey-api/openapi-ts failed - install it with:[/]")
|
|
1077
|
+
extra = ["@hey-api/openapi-ts"]
|
|
1078
|
+
if types_config.generate_zod:
|
|
1079
|
+
extra.append("zod")
|
|
1080
|
+
console.print(f"[dim] {' '.join([*install_cmd, '-D', *extra])}[/]")
|
|
1081
|
+
if verbose:
|
|
1082
|
+
console.print(f"[dim]Error: {e!s}[/]")
|
|
957
1083
|
except FileNotFoundError:
|
|
958
1084
|
runtime_name = executor or "Node.js"
|
|
959
|
-
console.print(
|
|
960
|
-
f"[yellow]! litestar-vite-typegen not found - ensure {runtime_name} and litestar-vite-plugin are installed[/]"
|
|
961
|
-
)
|
|
962
|
-
msg = f"Package executor not found - ensure {runtime_name} is installed"
|
|
963
|
-
raise LitestarCLIException(msg) from None
|
|
1085
|
+
console.print(f"[yellow]! Package executor not found - ensure {runtime_name} is installed[/]")
|
|
964
1086
|
|
|
965
1087
|
|
|
966
1088
|
@vite_group.command(name="generate-types", help="Generate TypeScript types from OpenAPI schema and routes.")
|
|
@@ -968,22 +1090,16 @@ def _invoke_typegen_cli(config: Any, verbose: bool) -> None:
|
|
|
968
1090
|
def generate_types(app: "Litestar", verbose: "bool") -> None:
|
|
969
1091
|
"""Generate TypeScript types from OpenAPI schema and routes.
|
|
970
1092
|
|
|
971
|
-
Uses the unified TypeScript CLI (litestar-vite-typegen) to ensure
|
|
972
|
-
identical output between CLI, dev server, and build commands.
|
|
973
|
-
|
|
974
1093
|
This command:
|
|
975
|
-
1. Exports OpenAPI schema
|
|
976
|
-
2.
|
|
977
|
-
|
|
978
|
-
|
|
1094
|
+
1. Exports the OpenAPI schema (uses litestar's built-in schema generation)
|
|
1095
|
+
2. Exports route metadata
|
|
1096
|
+
3. Runs @hey-api/openapi-ts to generate TypeScript types
|
|
1097
|
+
4. If Inertia is enabled: exports page props metadata
|
|
979
1098
|
|
|
980
1099
|
Args:
|
|
981
1100
|
app: The Litestar application instance.
|
|
982
1101
|
verbose: Whether to enable verbose output.
|
|
983
1102
|
"""
|
|
984
|
-
from litestar_vite.codegen import export_integration_assets
|
|
985
|
-
from litestar_vite.plugin._utils import write_runtime_config_file
|
|
986
|
-
|
|
987
1103
|
if verbose:
|
|
988
1104
|
app.debug = True
|
|
989
1105
|
|
|
@@ -997,35 +1113,20 @@ def generate_types(app: "Litestar", verbose: "bool") -> None:
|
|
|
997
1113
|
|
|
998
1114
|
console.rule("[yellow]Generating TypeScript types[/]", align="left")
|
|
999
1115
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
if
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
# Report results with detailed status
|
|
1014
|
-
for file in result.exported_files:
|
|
1015
|
-
console.print(f"[green]✓ Exported {file}[/] [dim](updated)[/]")
|
|
1016
|
-
for file in result.unchanged_files:
|
|
1017
|
-
console.print(f"[dim]✓ {file} (unchanged)[/]")
|
|
1018
|
-
|
|
1019
|
-
if not result.exported_files and not result.unchanged_files:
|
|
1020
|
-
console.print("[yellow]! No files exported (OpenAPI may not be available)[/]")
|
|
1021
|
-
return
|
|
1022
|
-
except (OSError, TypeError, ValueError) as exc:
|
|
1023
|
-
console.print(f"[red]✗ Failed to export type metadata: {exc}[/]")
|
|
1024
|
-
return
|
|
1116
|
+
_export_openapi_schema(app, config.types)
|
|
1117
|
+
_export_routes_metadata(app, config.types)
|
|
1118
|
+
_export_routes_typescript(app, config.types)
|
|
1119
|
+
_run_openapi_ts(config, verbose, config.install_command, config.runtime.executor)
|
|
1120
|
+
if isinstance(config.inertia, InertiaConfig) and config.types.generate_page_props and config.types.page_props_path:
|
|
1121
|
+
openapi_schema: dict[str, Any] | None = None
|
|
1122
|
+
try:
|
|
1123
|
+
if config.types.openapi_path and config.types.openapi_path.exists():
|
|
1124
|
+
openapi_schema = decode_json(config.types.openapi_path.read_bytes())
|
|
1125
|
+
except (OSError, SerializationException):
|
|
1126
|
+
if verbose:
|
|
1127
|
+
console.print("[dim]! Could not load OpenAPI schema for type references[/]")
|
|
1025
1128
|
|
|
1026
|
-
|
|
1027
|
-
# This handles both @hey-api/openapi-ts and page-props.ts generation
|
|
1028
|
-
_invoke_typegen_cli(config, verbose)
|
|
1129
|
+
_export_inertia_pages_metadata(app, config.types, config.inertia, openapi_schema)
|
|
1029
1130
|
|
|
1030
1131
|
|
|
1031
1132
|
@vite_group.command(name="status", help="Check the status of the Vite integration.")
|
|
@@ -1042,13 +1143,11 @@ def vite_status(app: "Litestar") -> None:
|
|
|
1042
1143
|
console.print(f"Assets URL: {config.asset_url}")
|
|
1043
1144
|
console.print(f"Base URL: {config.base_url}")
|
|
1044
1145
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
console.print(f"[green]✓ Manifest found at {found_manifest}[/]")
|
|
1146
|
+
manifest_path = Path(f"{config.bundle_dir}/{config.manifest_name}")
|
|
1147
|
+
if manifest_path.exists():
|
|
1148
|
+
console.print(f"[green]✓ Manifest found at {manifest_path}[/]")
|
|
1049
1149
|
else:
|
|
1050
|
-
|
|
1051
|
-
console.print(f"[red]✗ Manifest not found at {manifest_locations}[/]")
|
|
1150
|
+
console.print(f"[red]✗ Manifest not found at {manifest_path}[/]")
|
|
1052
1151
|
|
|
1053
1152
|
if config.dev_mode:
|
|
1054
1153
|
url = f"{config.protocol}://{config.host}:{config.port}"
|
litestar_vite/codegen.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Public code generation API.
|
|
2
|
+
|
|
3
|
+
The internal implementation lives in ``litestar_vite._codegen``.
|
|
4
|
+
|
|
5
|
+
This module provides a stable import surface for:
|
|
6
|
+
|
|
7
|
+
- Route metadata export (``routes.json`` + Ziggy-compatible TS)
|
|
8
|
+
- Inertia page props metadata export
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from litestar_vite._codegen.inertia import ( # noqa: F401
|
|
12
|
+
InertiaPageMetadata,
|
|
13
|
+
_get_openapi_schema_ref, # pyright: ignore[reportPrivateUsage,reportUnusedImport]
|
|
14
|
+
_get_return_type_name, # pyright: ignore[reportPrivateUsage,reportUnusedImport]
|
|
15
|
+
extract_inertia_pages,
|
|
16
|
+
generate_inertia_pages_json,
|
|
17
|
+
)
|
|
18
|
+
from litestar_vite._codegen.routes import ( # noqa: F401
|
|
19
|
+
RouteMetadata,
|
|
20
|
+
_escape_ts_string, # pyright: ignore[reportPrivateUsage,reportUnusedImport]
|
|
21
|
+
_is_type_required, # pyright: ignore[reportPrivateUsage,reportUnusedImport]
|
|
22
|
+
_ts_type_for_param, # pyright: ignore[reportPrivateUsage,reportUnusedImport]
|
|
23
|
+
extract_route_metadata,
|
|
24
|
+
generate_routes_json,
|
|
25
|
+
generate_routes_ts,
|
|
26
|
+
)
|
|
27
|
+
from litestar_vite._codegen.ts import (
|
|
28
|
+
ts_type_from_openapi as _ts_type_from_openapi, # noqa: F401 # pyright: ignore[reportUnusedImport]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
__all__ = (
|
|
32
|
+
"InertiaPageMetadata",
|
|
33
|
+
"RouteMetadata",
|
|
34
|
+
"extract_inertia_pages",
|
|
35
|
+
"extract_route_metadata",
|
|
36
|
+
"generate_inertia_pages_json",
|
|
37
|
+
"generate_routes_json",
|
|
38
|
+
"generate_routes_ts",
|
|
39
|
+
)
|
litestar_vite/commands.py
CHANGED
|
@@ -12,8 +12,11 @@ from litestar_vite.exceptions import MissingDependencyError
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
|
|
15
|
+
from litestar import Litestar
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
def init_vite(
|
|
19
|
+
app: "Litestar",
|
|
17
20
|
root_path: "Path",
|
|
18
21
|
resource_path: "Path",
|
|
19
22
|
asset_url: "str",
|
|
@@ -21,12 +24,14 @@ def init_vite(
|
|
|
21
24
|
bundle_path: "Path",
|
|
22
25
|
enable_ssr: "bool",
|
|
23
26
|
vite_port: int,
|
|
27
|
+
hot_file: "Path",
|
|
24
28
|
litestar_port: int,
|
|
25
29
|
framework: str = "react",
|
|
26
30
|
) -> None:
|
|
27
31
|
"""Initialize a new Vite project using the scaffolding system.
|
|
28
32
|
|
|
29
33
|
Args:
|
|
34
|
+
app: The Litestar application instance.
|
|
30
35
|
root_path: Root directory for the Vite project.
|
|
31
36
|
resource_path: Directory containing source files.
|
|
32
37
|
asset_url: Base URL for serving assets.
|
|
@@ -34,6 +39,7 @@ def init_vite(
|
|
|
34
39
|
bundle_path: Output directory for built files.
|
|
35
40
|
enable_ssr: Enable server-side rendering.
|
|
36
41
|
vite_port: Port for Vite dev server.
|
|
42
|
+
hot_file: Path to hot reload manifest.
|
|
37
43
|
litestar_port: Port for Litestar server.
|
|
38
44
|
framework: Framework template to use (default: react).
|
|
39
45
|
|