litestar-vite 0.2.0__py3-none-any.whl → 0.2.2__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.

Potentially problematic release.


This version of litestar-vite might be problematic. Click here for more details.

litestar_vite/config.py CHANGED
@@ -17,6 +17,7 @@ if TYPE_CHECKING:
17
17
 
18
18
  __all__ = ("ViteConfig", "ViteTemplateConfig")
19
19
  EngineType = TypeVar("EngineType", bound=TemplateEngineProtocol[Any, Any])
20
+ TRUE_VALUES = {"True", "true", "1", "yes", "Y", "T"}
20
21
 
21
22
 
22
23
  @dataclass
@@ -53,7 +54,7 @@ class ViteConfig:
53
54
  This file contains a single line containing the host, protocol, and port the Vite server is running.
54
55
  """
55
56
  hot_reload: bool = field(
56
- default_factory=lambda: os.getenv("VITE_HOT_RELOAD", "True") in {"True", "1", "yes", "Y", "T"},
57
+ default_factory=lambda: os.getenv("VITE_HOT_RELOAD", "True") in TRUE_VALUES,
57
58
  )
58
59
  """Enable HMR for Vite development server."""
59
60
  ssr_enabled: bool = False
@@ -88,11 +89,11 @@ class ViteConfig:
88
89
  install_command: list[str] = field(default_factory=lambda: ["npm", "install"])
89
90
  """Default command to use for installing Vite."""
90
91
  use_server_lifespan: bool = field(
91
- default_factory=lambda: os.getenv("VITE_USE_SERVER_LIFESPAN", "False") in {"True", "1", "yes", "Y", "T"},
92
+ default_factory=lambda: os.getenv("VITE_USE_SERVER_LIFESPAN", "False") in TRUE_VALUES,
92
93
  )
93
94
  """Utilize the server lifespan hook to run Vite."""
94
95
  dev_mode: bool = field(
95
- default_factory=lambda: os.getenv("VITE_DEV_MODE", "False") in {"True", "1", "yes", "Y", "T"},
96
+ default_factory=lambda: os.getenv("VITE_DEV_MODE", "False") in TRUE_VALUES,
96
97
  )
97
98
  """When True, Vite will run with HMR or watch build"""
98
99
  detect_nodeenv: bool = True
@@ -15,6 +15,7 @@ class InertiaHeaders(str, Enum):
15
15
  PARTIAL_DATA = "X-Inertia-Partial-Data"
16
16
  PARTIAL_COMPONENT = "X-Inertia-Partial-Component"
17
17
  LOCATION = "X-Inertia-Location"
18
+ REFERER = "Referer"
18
19
 
19
20
 
20
21
  def get_enabled_header(enabled: bool = True) -> dict[str, Any]:
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import re
2
3
  from typing import TYPE_CHECKING, Any, cast
3
4
 
@@ -7,6 +8,7 @@ from litestar.connection.base import AuthT, StateT, UserT
7
8
  from litestar.exceptions import (
8
9
  HTTPException,
9
10
  InternalServerException,
11
+ NotAuthorizedException,
10
12
  NotFoundException,
11
13
  PermissionDeniedException,
12
14
  )
@@ -42,7 +44,7 @@ class _HTTPConflictException(HTTPException):
42
44
  status_code = HTTP_409_CONFLICT
43
45
 
44
46
 
45
- def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]:
47
+ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]: # noqa: PLR0911
46
48
  """Handler for all exceptions subclassed from HTTPException."""
47
49
  inertia_enabled = getattr(request, "inertia_enabled", False) or getattr(request, "is_inertia", False)
48
50
  if isinstance(exc, NotFoundError):
@@ -64,7 +66,8 @@ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exce
64
66
  inertia_plugin = cast("InertiaPlugin", request.app.plugins.get("InertiaPlugin"))
65
67
  if extras:
66
68
  content.update({"extra": extras})
67
- flash(request, detail, category="error")
69
+ with contextlib.suppress(Exception):
70
+ flash(request, detail, category="error")
68
71
  if extras and len(extras) >= 1:
69
72
  message = extras[0]
70
73
  default_field = f"root.{message.get('key')}" if message.get("key", None) is not None else "root" # type: ignore
@@ -72,18 +75,23 @@ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exce
72
75
  match = FIELD_ERR_RE.search(error_detail)
73
76
  field = match.group(1) if match else default_field
74
77
  if isinstance(message, dict):
75
- error(request, field, error_detail)
76
- if status_code in {HTTP_422_UNPROCESSABLE_ENTITY, HTTP_400_BAD_REQUEST}:
77
- return InertiaBack(request)
78
- if (
79
- status_code == HTTP_401_UNAUTHORIZED
80
- and inertia_plugin.config.redirect_unauthorized_to is not None
81
- and not request.url.path.startswith(inertia_plugin.config.redirect_unauthorized_to)
78
+ with contextlib.suppress(Exception):
79
+ error(request, field, error_detail)
80
+ if status_code in {HTTP_422_UNPROCESSABLE_ENTITY, HTTP_400_BAD_REQUEST} or isinstance(
81
+ exc,
82
+ PermissionDeniedException,
82
83
  ):
83
- return InertiaRedirect(
84
- request,
85
- redirect_to=inertia_plugin.config.redirect_unauthorized_to,
84
+ return InertiaBack(request)
85
+ if isinstance(exc, PermissionDeniedException):
86
+ return InertiaBack(request)
87
+ if status_code == HTTP_401_UNAUTHORIZED or isinstance(exc, NotAuthorizedException):
88
+ redirect_to = (
89
+ inertia_plugin.config.redirect_unauthorized_to is not None
90
+ and str(request.url) != inertia_plugin.config.redirect_unauthorized_to
86
91
  )
92
+ if redirect_to:
93
+ return InertiaRedirect(request, redirect_to=cast("str", inertia_plugin.config.redirect_unauthorized_to))
94
+ return InertiaBack(request)
87
95
  return InertiaResponse[Any](
88
96
  media_type=preferred_type,
89
97
  content=content,
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
15
15
  StateT,
16
16
  UserT,
17
17
  )
18
- from litestar.types import ASGIApp
18
+ from litestar.types import ASGIApp, Receive, Scope, Send
19
19
 
20
20
 
21
21
  async def redirect_on_asset_version_mismatch(request: Request[UserT, AuthT, StateT]) -> InertiaRedirect | None:
@@ -32,10 +32,6 @@ async def redirect_on_asset_version_mismatch(request: Request[UserT, AuthT, Stat
32
32
  return InertiaRedirect(request, redirect_to=str(request.url))
33
33
 
34
34
 
35
- if TYPE_CHECKING:
36
- from litestar.types import Receive, Scope, Send
37
-
38
-
39
35
  class InertiaMiddleware(AbstractMiddleware):
40
36
  def __init__(self, app: ASGIApp) -> None:
41
37
  super().__init__(app)
@@ -69,6 +69,11 @@ class InertiaDetails:
69
69
  """Partial Data Reload."""
70
70
  return self._get_header_value(InertiaHeaders.PARTIAL_DATA)
71
71
 
72
+ @cached_property
73
+ def referer(self) -> str | None:
74
+ """Partial Data Reload."""
75
+ return self._get_header_value(InertiaHeaders.REFERER)
76
+
72
77
  @cached_property
73
78
  def is_partial_render(self) -> bool:
74
79
  """Is Partial Data Reload."""
@@ -6,7 +6,7 @@ from functools import lru_cache
6
6
  from mimetypes import guess_type
7
7
  from pathlib import PurePath
8
8
  from textwrap import dedent
9
- from typing import TYPE_CHECKING, Any, Dict, Iterable, Mapping, TypeVar, cast
9
+ from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Mapping, TypeVar, cast
10
10
  from urllib.parse import quote
11
11
 
12
12
  from litestar import Litestar, MediaType, Request, Response
@@ -16,6 +16,7 @@ from litestar.response import Redirect
16
16
  from litestar.response.base import ASGIResponse
17
17
  from litestar.serialization import get_serializer
18
18
  from litestar.status_codes import HTTP_200_OK, HTTP_303_SEE_OTHER, HTTP_307_TEMPORARY_REDIRECT, HTTP_409_CONFLICT
19
+ from litestar.types import Empty
19
20
  from litestar.utils.deprecation import warn_deprecation
20
21
  from litestar.utils.empty import value_or_default
21
22
  from litestar.utils.helpers import get_enum_string_value
@@ -33,6 +34,7 @@ if TYPE_CHECKING:
33
34
  from litestar.connection.base import AuthT, StateT, UserT
34
35
  from litestar.types import ResponseCookies, ResponseHeaders, TypeEncodersMap
35
36
 
37
+ from litestar_vite.inertia.request import InertiaRequest
36
38
  from litestar_vite.inertia.routes import Routes
37
39
 
38
40
  from .plugin import InertiaPlugin
@@ -63,10 +65,11 @@ def get_shared_props(request: ASGIConnection[Any, Any, Any, Any]) -> Dict[str, A
63
65
  Be sure to call this before `self.create_template_context` if you would like to include the `flash` message details.
64
66
  """
65
67
  error_bag = request.headers.get("X-Inertia-Error-Bag", None)
66
- errors = request.session.pop("_errors", {})
67
- props = request.session.pop("_shared", {})
68
+ has_active_session = not (not request.session or request.scope["session"] is Empty)
69
+ errors: dict[str, Any] = request.session.pop("_errors", {}) if has_active_session else {}
70
+ props: dict[str, Any] = request.session.pop("_shared", {}) if has_active_session else {}
68
71
  flash: dict[str, list[str]] = defaultdict(list)
69
- for message in request.session.pop("_messages", []):
72
+ for message in cast("List[Dict[str,Any]]", request.session.pop("_messages", []) if has_active_session else []):
70
73
  flash[message["category"]].append(message["message"])
71
74
 
72
75
  inertia_plugin = cast("InertiaPlugin", request.app.plugins.get("InertiaPlugin"))
@@ -337,8 +340,12 @@ class InertiaBack(Redirect):
337
340
  """Initialize external redirect, Set status code to 409 (required by Inertia),
338
341
  and pass redirect url.
339
342
  """
343
+ referer = request.headers.get("referer", str(request.base_url))
344
+ inertia_enabled = getattr(request, "inertia_enabled", False) or getattr(request, "is_inertia", False)
345
+ if inertia_enabled:
346
+ referer = cast("InertiaRequest[Any, Any, Any]", request).inertia.referer or referer
340
347
  super().__init__(
341
- path=request.headers["Referer"],
348
+ path=request.headers.get("referer", str(request.base_url)),
342
349
  status_code=HTTP_307_TEMPORARY_REDIRECT if request.method == "GET" else HTTP_303_SEE_OTHER,
343
350
  cookies=request.cookies,
344
351
  **kwargs,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: litestar-vite
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Vite plugin for Litestar
5
5
  Project-URL: Changelog, https://cofin.github.io/litestar-vite/latest/changelog
6
6
  Project-URL: Discord, https://discord.gg/X3FJqy8d2j
@@ -30,7 +30,7 @@ Classifier: Topic :: Database :: Database Engines/Servers
30
30
  Classifier: Topic :: Software Development
31
31
  Classifier: Typing :: Typed
32
32
  Requires-Python: >=3.8
33
- Requires-Dist: litestar[jinja]>=2.4.0
33
+ Requires-Dist: litestar[jinja]>=2.7.0
34
34
  Provides-Extra: nodeenv
35
35
  Requires-Dist: nodeenv; extra == 'nodeenv'
36
36
  Description-Content-Type: text/markdown
@@ -2,19 +2,19 @@ litestar_vite/__init__.py,sha256=QEZzbM6LXuSm52rzpzcw3OihR7xxoPCZ6jhWtZH2dZc,402
2
2
  litestar_vite/__metadata__.py,sha256=Eml1c9xezV-GSodmysksrT8jPWqE__x0ENO1wM5g6q0,319
3
3
  litestar_vite/cli.py,sha256=foXJ-xW1bvUEsT7nPo1hbN0FLaDzHWPG4zpmqN__rY0,10976
4
4
  litestar_vite/commands.py,sha256=sfTdFfMcDxnW3_tbmIIBjpHmNdQYKHjSguGxXNP8SVw,4440
5
- litestar_vite/config.py,sha256=Mg86uVtqDG-uVZd2YUZoJYNRIlBBbyJLl8iI-fO1zKo,7527
5
+ litestar_vite/config.py,sha256=J5U0hBa_cD7lm15lg24QqMy3hsZ_1QIIETxwaNZIm84,7523
6
6
  litestar_vite/loader.py,sha256=USrzNDppXgXLvW5WCuIgKPuM6MlECNIssnkwb_p-E8s,8117
7
7
  litestar_vite/plugin.py,sha256=2rwlumH3CFozb_7NGOFwn20BMZ_4JTNHiWh0oyaN-gc,5131
8
8
  litestar_vite/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  litestar_vite/template_engine.py,sha256=ffC4KPtUUNkuC0tJ0bD1Bu7c8lE33vKP0US1fWUYnO8,3853
10
10
  litestar_vite/inertia/__init__.py,sha256=PMOon8tag-20riAkHH3U4VLk7NBwt9lHsOHHSKMQHJQ,695
11
- litestar_vite/inertia/_utils.py,sha256=IAsK4Nrjx2dr9z7rXBLHAu_FG8GvCpo_fpywY7RHwl0,1932
11
+ litestar_vite/inertia/_utils.py,sha256=ijO9Lgka7ZPIAHkby9szbTGoSg0nDShC2bqWT9cDxi0,1956
12
12
  litestar_vite/inertia/config.py,sha256=6cYR4m5oGsJnL_rH6Dt8bQJ804Oq6knj6qDsCVUqNsI,942
13
- litestar_vite/inertia/exception_handler.py,sha256=fXLfUtrooAORd7TWJGx8hDd6_0h_mI3w89CqJz5IMmE,4022
14
- litestar_vite/inertia/middleware.py,sha256=9ADCoCNdQNLDYhQ6ctY4Lo92E_EtgBPqIo2SdOJz9zU,1766
13
+ litestar_vite/inertia/exception_handler.py,sha256=yTgyd5BkOyTvg8HKWgQEzJuOIBnd4uv7LkCBee_pEPw,4433
14
+ litestar_vite/inertia/middleware.py,sha256=NEDcAoT7GMWA9hEGvANZ3MG5_p3MmZX57RF95T71les,1716
15
15
  litestar_vite/inertia/plugin.py,sha256=ebAG9XnDBahttuc7WIUgBd3o_Ys8MdPS273LPNs5H8A,2344
16
- litestar_vite/inertia/request.py,sha256=UReg7_ks6MGa2HbIpDsD2DochckbLA-c-k8Er2mHkVA,3509
17
- litestar_vite/inertia/response.py,sha256=31Hm838c7nJAkKe9joLj-c33UlZpWTFAgQefxLd5vn0,14379
16
+ litestar_vite/inertia/request.py,sha256=hk8m1pmDiMbWhVurRDHfDPD24nMHp56JzUKV6SBDeqA,3665
17
+ litestar_vite/inertia/response.py,sha256=vvpvz-yNTyboIa2dzVMhaMrCxzDTgyM2U_nGEwbN3Po,15051
18
18
  litestar_vite/inertia/routes.py,sha256=QksJm2RUfL-WbuhOieYnPXXWO5GYnPtmsYEm6Ef8Yeo,1782
19
19
  litestar_vite/inertia/types.py,sha256=tLp0pm1N__hcWC875khf6wH1nuFlKS9-VjDqgsRkXnw,702
20
20
  litestar_vite/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -24,7 +24,7 @@ litestar_vite/templates/package.json.j2,sha256=0JWgdTuaSZ25EmCltF_zbqDdpxfvCLeYu
24
24
  litestar_vite/templates/styles.css.j2,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  litestar_vite/templates/tsconfig.json.j2,sha256=q1REIuVyXUHCy4Zi2kgTkmrhdT98vyY89k-WTrImOj8,843
26
26
  litestar_vite/templates/vite.config.ts.j2,sha256=FZ4OJaB8Kjby_nlx4_LCP8eCe1LRi8kW2GspCiVMfDY,1115
27
- litestar_vite-0.2.0.dist-info/METADATA,sha256=DGPtfcXb9Khk4EXmvwXCJAb2T992hzHkR3CLtIHAqG8,6180
28
- litestar_vite-0.2.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
29
- litestar_vite-0.2.0.dist-info/licenses/LICENSE,sha256=HeTiEfEgvroUXZe_xAmYHxtTBgw--mbXyZLsWDYabHc,1069
30
- litestar_vite-0.2.0.dist-info/RECORD,,
27
+ litestar_vite-0.2.2.dist-info/METADATA,sha256=ue7XPxpNkXIidXS7TKrqzeYEMwDjKexrjLHFnxodwO4,6180
28
+ litestar_vite-0.2.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
29
+ litestar_vite-0.2.2.dist-info/licenses/LICENSE,sha256=HeTiEfEgvroUXZe_xAmYHxtTBgw--mbXyZLsWDYabHc,1069
30
+ litestar_vite-0.2.2.dist-info/RECORD,,