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.
Files changed (55) hide show
  1. litestar_vite/_codegen/__init__.py +26 -0
  2. litestar_vite/_codegen/inertia.py +407 -0
  3. litestar_vite/{codegen/_openapi.py → _codegen/openapi.py} +11 -58
  4. litestar_vite/{codegen/_routes.py → _codegen/routes.py} +43 -110
  5. litestar_vite/{codegen/_ts.py → _codegen/ts.py} +19 -19
  6. litestar_vite/_handler/__init__.py +8 -0
  7. litestar_vite/{handler/_app.py → _handler/app.py} +29 -117
  8. litestar_vite/cli.py +254 -155
  9. litestar_vite/codegen.py +39 -0
  10. litestar_vite/commands.py +6 -0
  11. litestar_vite/{config/__init__.py → config.py} +726 -99
  12. litestar_vite/deploy.py +3 -14
  13. litestar_vite/doctor.py +6 -8
  14. litestar_vite/executor.py +1 -45
  15. litestar_vite/handler.py +9 -0
  16. litestar_vite/html_transform.py +5 -148
  17. litestar_vite/inertia/__init__.py +0 -24
  18. litestar_vite/inertia/_utils.py +0 -5
  19. litestar_vite/inertia/exception_handler.py +16 -22
  20. litestar_vite/inertia/helpers.py +18 -546
  21. litestar_vite/inertia/plugin.py +11 -77
  22. litestar_vite/inertia/request.py +0 -48
  23. litestar_vite/inertia/response.py +17 -113
  24. litestar_vite/inertia/types.py +0 -19
  25. litestar_vite/loader.py +7 -7
  26. litestar_vite/plugin.py +2184 -0
  27. litestar_vite/templates/angular/package.json.j2 +1 -2
  28. litestar_vite/templates/angular-cli/package.json.j2 +1 -2
  29. litestar_vite/templates/base/package.json.j2 +1 -2
  30. litestar_vite/templates/react-inertia/package.json.j2 +1 -2
  31. litestar_vite/templates/vue-inertia/package.json.j2 +1 -2
  32. {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/METADATA +5 -5
  33. {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/RECORD +36 -49
  34. litestar_vite/codegen/__init__.py +0 -48
  35. litestar_vite/codegen/_export.py +0 -229
  36. litestar_vite/codegen/_inertia.py +0 -619
  37. litestar_vite/codegen/_utils.py +0 -141
  38. litestar_vite/config/_constants.py +0 -97
  39. litestar_vite/config/_deploy.py +0 -70
  40. litestar_vite/config/_inertia.py +0 -241
  41. litestar_vite/config/_paths.py +0 -63
  42. litestar_vite/config/_runtime.py +0 -235
  43. litestar_vite/config/_spa.py +0 -93
  44. litestar_vite/config/_types.py +0 -94
  45. litestar_vite/handler/__init__.py +0 -9
  46. litestar_vite/inertia/precognition.py +0 -274
  47. litestar_vite/plugin/__init__.py +0 -687
  48. litestar_vite/plugin/_process.py +0 -185
  49. litestar_vite/plugin/_proxy.py +0 -689
  50. litestar_vite/plugin/_proxy_headers.py +0 -244
  51. litestar_vite/plugin/_static.py +0 -37
  52. litestar_vite/plugin/_utils.py +0 -489
  53. /litestar_vite/{handler/_routing.py → _handler/routing.py} +0 -0
  54. {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/WHEEL +0 -0
  55. {litestar_vite-0.15.0.dist-info → litestar_vite-0.15.0rc2.dist-info}/licenses/LICENSE +0 -0
@@ -18,15 +18,8 @@ from litestar import get
18
18
  from litestar.exceptions import ImproperlyConfiguredException, SerializationException
19
19
  from litestar.serialization import decode_json, encode_json
20
20
 
21
- from litestar_vite.config import InertiaConfig
22
- from litestar_vite.handler._routing import spa_handler_dev, spa_handler_prod
23
- from litestar_vite.html_transform import (
24
- inject_head_script,
25
- inject_page_script,
26
- inject_vite_dev_scripts,
27
- set_data_attribute,
28
- transform_asset_urls,
29
- )
21
+ from litestar_vite._handler.routing import spa_handler_dev, spa_handler_prod
22
+ from litestar_vite.html_transform import inject_head_script, set_data_attribute, transform_asset_urls
30
23
 
31
24
  if TYPE_CHECKING:
32
25
  from litestar.connection import Request
@@ -164,29 +157,25 @@ class AppHandler:
164
157
 
165
158
  if self._spa_config.inject_csrf and csrf_token:
166
159
  script = f'window.{self._spa_config.csrf_var_name} = "{csrf_token}";'
167
- html = inject_head_script(html, script, escape=False, nonce=self._config.csp_nonce)
160
+ html = inject_head_script(html, script, escape=False)
168
161
 
169
162
  if page_data is not None:
170
163
  json_data = encode_json(page_data).decode("utf-8")
171
- # Check InertiaConfig for use_script_element (Inertia-specific setting)
172
- inertia = self._config.inertia
173
- use_script_element = isinstance(inertia, InertiaConfig) and inertia.use_script_element
174
- if use_script_element:
175
- # v2.3+ Inertia protocol: Use script element for better performance (~37% smaller)
176
- html = inject_page_script(html, json_data, nonce=self._config.csp_nonce)
177
- else:
178
- # Legacy: Use data-page attribute
179
- html = set_data_attribute(html, self._spa_config.app_selector, "data-page", json_data)
164
+ html = set_data_attribute(html, self._spa_config.app_selector, "data-page", json_data)
180
165
 
181
166
  return html
182
167
 
183
168
  async def _load_index_html_async(self) -> None:
184
- """Load and cache index.html asynchronously."""
169
+ """Load and cache index.html asynchronously.
170
+
171
+ Raises:
172
+ ImproperlyConfiguredException: If index.html cannot be located.
173
+ """
185
174
  resolved_path: Path | None = None
186
175
  for candidate in self._config.candidate_index_html_paths():
187
- candidate_path = anyio.Path(candidate)
188
- if await candidate_path.exists():
189
- resolved_path = candidate
176
+ candidate_path = Path(candidate)
177
+ if candidate_path.exists():
178
+ resolved_path = candidate_path
190
179
  break
191
180
 
192
181
  if resolved_path is None:
@@ -200,7 +189,11 @@ class AppHandler:
200
189
  self._cached_bytes = html.encode("utf-8")
201
190
 
202
191
  def _load_index_html_sync(self) -> None:
203
- """Load and cache index.html synchronously."""
192
+ """Load and cache index.html synchronously.
193
+
194
+ Raises:
195
+ ImproperlyConfiguredException: If index.html cannot be located.
196
+ """
204
197
  resolved_path: Path | None = None
205
198
  for candidate in self._config.candidate_index_html_paths():
206
199
  candidate_path = Path(candidate)
@@ -293,92 +286,10 @@ class AppHandler:
293
286
  """
294
287
  if not self._manifest:
295
288
  return html
296
- return transform_asset_urls(html, self._manifest, asset_url=self._config.asset_url, base_url=None)
297
-
298
- def _inject_dev_scripts(self, html: str) -> str:
299
- """Inject Vite dev scripts for hybrid mode HTML served by Litestar.
300
-
301
- Returns:
302
- The HTML with Vite dev scripts injected.
303
- """
304
- resource_dir = self._config.resource_dir
305
- try:
306
- resource_dir_str = str(resource_dir.relative_to(self._config.root_dir))
307
- except ValueError:
308
- resource_dir_str = resource_dir.name
309
- return inject_vite_dev_scripts(
310
- html,
311
- "",
312
- asset_url=self._config.asset_url,
313
- is_react=self._config.is_react,
314
- csp_nonce=self._config.csp_nonce,
315
- resource_dir=resource_dir_str,
289
+ return transform_asset_urls(
290
+ html, self._manifest, asset_url=self._config.asset_url, base_url=self._config.base_url
316
291
  )
317
292
 
318
- async def _transform_html_with_vite(self, html: str, url: str) -> str:
319
- """Transform HTML using the Vite dev server pipeline.
320
-
321
- Returns:
322
- The transformed HTML.
323
- """
324
- if self._http_client is None or self._vite_url is None:
325
- msg = "HTTP client not initialized. Ensure initialize_async() was called for dev mode."
326
- raise ImproperlyConfiguredException(msg)
327
- endpoint = f"{self._vite_url.rstrip('/')}/__litestar__/transform-index"
328
- response = await self._http_client.post(endpoint, json={"url": url, "html": html}, timeout=5.0)
329
- response.raise_for_status()
330
- return response.text
331
-
332
- def _transform_html_with_vite_sync(self, html: str, url: str) -> str:
333
- """Transform HTML using the Vite dev server pipeline (sync).
334
-
335
- Returns:
336
- The transformed HTML.
337
- """
338
- if self._http_client_sync is None or self._vite_url is None:
339
- msg = "HTTP client not initialized. Ensure initialize_sync() was called for dev mode."
340
- raise ImproperlyConfiguredException(msg)
341
- endpoint = f"{self._vite_url.rstrip('/')}/__litestar__/transform-index"
342
- response = self._http_client_sync.post(endpoint, json={"url": url, "html": html}, timeout=5.0)
343
- response.raise_for_status()
344
- return response.text
345
-
346
- async def _get_dev_html(self, request: "Request[Any, Any, Any]") -> str:
347
- """Resolve dev HTML for SPA or hybrid modes.
348
-
349
- Returns:
350
- The HTML to serve in development.
351
- """
352
- if self._config.mode == "hybrid":
353
- if self._cached_html is None:
354
- await self._load_index_html_async()
355
- base_html = self._cached_html or ""
356
- request_url = request.url.path or "/"
357
- try:
358
- return await self._transform_html_with_vite(base_html, request_url)
359
- except Exception as exc: # noqa: BLE001
360
- logger.warning("Falling back to manual Vite script injection: %s", exc)
361
- return self._inject_dev_scripts(base_html)
362
- return await self._proxy_to_dev_server(request)
363
-
364
- def _get_dev_html_sync(self, page_url: str | None = None) -> str:
365
- """Resolve dev HTML synchronously for SPA or hybrid modes.
366
-
367
- Returns:
368
- The HTML to serve in development.
369
- """
370
- if self._config.mode == "hybrid":
371
- if self._cached_html is None:
372
- self._load_index_html_sync()
373
- base_html = self._cached_html or ""
374
- request_url = page_url or "/"
375
- try:
376
- return self._transform_html_with_vite_sync(base_html, request_url)
377
- except Exception as exc: # noqa: BLE001
378
- logger.warning("Falling back to manual Vite script injection: %s", exc)
379
- return self._inject_dev_scripts(base_html)
380
- return self._proxy_to_dev_server_sync()
381
-
382
293
  def _get_csrf_token(self, request: "Request[Any, Any, Any]") -> "str | None":
383
294
  """Extract CSRF token from the request scope.
384
295
 
@@ -415,7 +326,7 @@ class AppHandler:
415
326
  csrf_token = self._get_csrf_token(request) if needs_csrf else None
416
327
 
417
328
  if self._config.is_dev_mode and self._config.hot_reload:
418
- html = await self._get_dev_html(request)
329
+ html = await self._proxy_to_dev_server(request)
419
330
  if needs_transform:
420
331
  html = self._transform_html(html, page_data, csrf_token)
421
332
  return html
@@ -448,6 +359,9 @@ class AppHandler:
448
359
 
449
360
  Returns:
450
361
  The rendered HTML.
362
+
363
+ Raises:
364
+ ImproperlyConfiguredException: If dev-mode HTTP clients are not initialized or Vite URL is unresolved.
451
365
  """
452
366
  if not self._initialized:
453
367
  logger.warning(
@@ -459,16 +373,11 @@ class AppHandler:
459
373
  needs_transform = self._spa_config is not None or page_data is not None
460
374
  if not needs_transform:
461
375
  if self._config.is_dev_mode and self._config.hot_reload:
462
- return self._get_dev_html_sync()
376
+ return self._proxy_to_dev_server_sync()
463
377
  return self._cached_html or ""
464
378
 
465
379
  if self._config.is_dev_mode and self._config.hot_reload:
466
- page_url = None
467
- if page_data is not None:
468
- url_value = page_data.get("url")
469
- if isinstance(url_value, str) and url_value:
470
- page_url = url_value
471
- html = self._get_dev_html_sync(page_url)
380
+ html = self._proxy_to_dev_server_sync()
472
381
  return self._transform_html(html, page_data, csrf_token)
473
382
 
474
383
  base_html = self._cached_html or ""
@@ -478,7 +387,10 @@ class AppHandler:
478
387
  """Get cached index.html bytes (production).
479
388
 
480
389
  Returns:
481
- Cached HTML bytes. .
390
+ Cached HTML bytes.
391
+
392
+ Raises:
393
+ ImproperlyConfiguredException: If index.html cannot be located.
482
394
  """
483
395
  if not self._initialized:
484
396
  logger.warning(