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/plugin/_process.py
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
"""Vite dev server process management."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import signal
|
|
5
|
-
import subprocess
|
|
6
|
-
import threading
|
|
7
|
-
from contextlib import suppress
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from typing import TYPE_CHECKING, Any
|
|
10
|
-
|
|
11
|
-
from litestar_vite.exceptions import ViteProcessError
|
|
12
|
-
from litestar_vite.plugin._utils import console
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from litestar_vite.executor import JSExecutor
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ViteProcess:
|
|
19
|
-
"""Manages the Vite development server process.
|
|
20
|
-
|
|
21
|
-
This class handles starting and stopping the Vite dev server process,
|
|
22
|
-
with proper thread safety and graceful shutdown. It registers signal
|
|
23
|
-
handlers for SIGTERM and SIGINT to ensure child processes are terminated
|
|
24
|
-
even if Python is killed externally.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
_instances: "list[ViteProcess]" = []
|
|
28
|
-
_signals_registered: bool = False
|
|
29
|
-
_original_handlers: "dict[int, Any]" = {}
|
|
30
|
-
|
|
31
|
-
def __init__(self, executor: "JSExecutor") -> None:
|
|
32
|
-
"""Initialize the Vite process manager.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
executor: The JavaScript executor to use for running Vite.
|
|
36
|
-
"""
|
|
37
|
-
self.process: "subprocess.Popen[Any] | None" = None
|
|
38
|
-
self._lock = threading.Lock()
|
|
39
|
-
self._executor = executor
|
|
40
|
-
|
|
41
|
-
ViteProcess._instances.append(self)
|
|
42
|
-
|
|
43
|
-
if not ViteProcess._signals_registered:
|
|
44
|
-
self._register_signal_handlers()
|
|
45
|
-
ViteProcess._signals_registered = True
|
|
46
|
-
|
|
47
|
-
import atexit
|
|
48
|
-
|
|
49
|
-
atexit.register(ViteProcess._cleanup_all_instances)
|
|
50
|
-
|
|
51
|
-
@classmethod
|
|
52
|
-
def _register_signal_handlers(cls) -> None:
|
|
53
|
-
"""Register signal handlers for graceful shutdown on SIGTERM/SIGINT."""
|
|
54
|
-
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
55
|
-
try:
|
|
56
|
-
original = signal.signal(sig, cls._signal_handler)
|
|
57
|
-
cls._original_handlers[sig] = original
|
|
58
|
-
except (OSError, ValueError):
|
|
59
|
-
pass
|
|
60
|
-
|
|
61
|
-
@classmethod
|
|
62
|
-
def _signal_handler(cls, signum: int, frame: Any) -> None:
|
|
63
|
-
"""Handle termination signals by stopping all Vite processes first."""
|
|
64
|
-
cls._cleanup_all_instances()
|
|
65
|
-
|
|
66
|
-
original = cls._original_handlers.get(signum, signal.SIG_DFL)
|
|
67
|
-
if callable(original) and original not in {signal.SIG_IGN, signal.SIG_DFL}:
|
|
68
|
-
original(signum, frame)
|
|
69
|
-
elif original == signal.SIG_DFL:
|
|
70
|
-
signal.signal(signum, signal.SIG_DFL)
|
|
71
|
-
os.kill(os.getpid(), signum)
|
|
72
|
-
|
|
73
|
-
@classmethod
|
|
74
|
-
def _cleanup_all_instances(cls) -> None:
|
|
75
|
-
"""Stop all tracked ViteProcess instances."""
|
|
76
|
-
for instance in cls._instances:
|
|
77
|
-
with suppress(Exception):
|
|
78
|
-
instance.stop()
|
|
79
|
-
|
|
80
|
-
def start(self, command: list[str], cwd: "Path | str | None") -> None:
|
|
81
|
-
"""Start the Vite process.
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
command: The command to run (e.g., ["npm", "run", "dev"]).
|
|
85
|
-
cwd: The working directory for the process.
|
|
86
|
-
|
|
87
|
-
If the process exits immediately, this method captures stdout/stderr and raises a
|
|
88
|
-
ViteProcessError with diagnostic details.
|
|
89
|
-
|
|
90
|
-
Raises:
|
|
91
|
-
ViteProcessError: If the process fails to start.
|
|
92
|
-
"""
|
|
93
|
-
if cwd is not None and isinstance(cwd, str):
|
|
94
|
-
cwd = Path(cwd)
|
|
95
|
-
|
|
96
|
-
try:
|
|
97
|
-
with self._lock:
|
|
98
|
-
if self.process and self.process.poll() is None:
|
|
99
|
-
return
|
|
100
|
-
|
|
101
|
-
if cwd:
|
|
102
|
-
self.process = self._executor.run(command, cwd)
|
|
103
|
-
if self.process and self.process.poll() is not None:
|
|
104
|
-
stdout, stderr = self.process.communicate()
|
|
105
|
-
out_str = stdout.decode(errors="ignore") if stdout else ""
|
|
106
|
-
err_str = stderr.decode(errors="ignore") if stderr else ""
|
|
107
|
-
console.print(
|
|
108
|
-
"[red]Vite process exited immediately.[/]\n"
|
|
109
|
-
f"[red]Command:[/] {' '.join(command)}\n"
|
|
110
|
-
f"[red]Exit code:[/] {self.process.returncode}\n"
|
|
111
|
-
f"[red]Stdout:[/]\n{out_str or '<empty>'}\n"
|
|
112
|
-
f"[red]Stderr:[/]\n{err_str or '<empty>'}\n"
|
|
113
|
-
"[yellow]Hint: Run `litestar assets doctor` to diagnose configuration issues.[/]"
|
|
114
|
-
)
|
|
115
|
-
msg = f"Vite process failed to start (exit {self.process.returncode})"
|
|
116
|
-
raise ViteProcessError( # noqa: TRY301
|
|
117
|
-
msg, command=command, exit_code=self.process.returncode, stderr=err_str, stdout=out_str
|
|
118
|
-
)
|
|
119
|
-
except Exception as e:
|
|
120
|
-
if isinstance(e, ViteProcessError):
|
|
121
|
-
raise
|
|
122
|
-
console.print(f"[red]Failed to start Vite process: {e!s}[/]")
|
|
123
|
-
msg = f"Failed to start Vite process: {e!s}"
|
|
124
|
-
raise ViteProcessError(msg) from e
|
|
125
|
-
|
|
126
|
-
def stop(self, timeout: float = 5.0) -> None:
|
|
127
|
-
"""Stop the Vite process and all its child processes.
|
|
128
|
-
|
|
129
|
-
Uses process groups to ensure child processes (node, astro, nuxt, vite, etc.)
|
|
130
|
-
are terminated along with the parent npm/npx process.
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
timeout: Seconds to wait for graceful shutdown before killing.
|
|
134
|
-
|
|
135
|
-
Raises:
|
|
136
|
-
ViteProcessError: If the process fails to stop.
|
|
137
|
-
"""
|
|
138
|
-
try:
|
|
139
|
-
with self._lock:
|
|
140
|
-
self._terminate_process_group(timeout)
|
|
141
|
-
except Exception as e:
|
|
142
|
-
console.print(f"[red]Failed to stop Vite process: {e!s}[/]")
|
|
143
|
-
msg = f"Failed to stop Vite process: {e!s}"
|
|
144
|
-
raise ViteProcessError(msg) from e
|
|
145
|
-
|
|
146
|
-
def _terminate_process_group(self, timeout: float) -> None:
|
|
147
|
-
"""Terminate the process group, waiting and killing if needed.
|
|
148
|
-
|
|
149
|
-
When available, uses process group termination to ensure all child processes are stopped
|
|
150
|
-
(e.g., Vite spawning Node/SSR framework processes). The process is started with
|
|
151
|
-
``start_new_session=True`` so the process id is the group id.
|
|
152
|
-
"""
|
|
153
|
-
if not self.process or self.process.poll() is not None:
|
|
154
|
-
return
|
|
155
|
-
pid = self.process.pid
|
|
156
|
-
try:
|
|
157
|
-
os.killpg(pid, signal.SIGTERM)
|
|
158
|
-
except AttributeError:
|
|
159
|
-
self.process.terminate()
|
|
160
|
-
except ProcessLookupError:
|
|
161
|
-
pass
|
|
162
|
-
try:
|
|
163
|
-
self.process.wait(timeout=timeout)
|
|
164
|
-
except subprocess.TimeoutExpired:
|
|
165
|
-
self._force_kill_process_group()
|
|
166
|
-
self.process.wait(timeout=1.0)
|
|
167
|
-
finally:
|
|
168
|
-
self.process = None
|
|
169
|
-
|
|
170
|
-
def _force_kill_process_group(self) -> None:
|
|
171
|
-
"""Force kill the process group if still alive."""
|
|
172
|
-
if not self.process:
|
|
173
|
-
return
|
|
174
|
-
pid = self.process.pid
|
|
175
|
-
try:
|
|
176
|
-
os.killpg(pid, signal.SIGKILL)
|
|
177
|
-
except AttributeError:
|
|
178
|
-
self.process.kill()
|
|
179
|
-
except ProcessLookupError:
|
|
180
|
-
pass
|
|
181
|
-
|
|
182
|
-
def _atexit_stop(self) -> None:
|
|
183
|
-
"""Best-effort stop on interpreter exit."""
|
|
184
|
-
with suppress(Exception):
|
|
185
|
-
self.stop()
|