hypern 0.3.13__cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl → 0.3.15__cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.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.
hypern/application.py CHANGED
@@ -10,7 +10,7 @@ import psutil
10
10
  from typing_extensions import Annotated, Doc
11
11
 
12
12
  from hypern.args_parser import ArgsConfig
13
- from hypern.datastructures import Contact, Info, License
13
+ from hypern.datastructures import SwaggerConfig
14
14
  from hypern.enum import HTTPMethod
15
15
  from hypern.hypern import DatabaseConfig, FunctionInfo, MiddlewareConfig, Router, Server, WebsocketRouter, Scheduler
16
16
  from hypern.hypern import Route as InternalRoute
@@ -91,121 +91,11 @@ class Hypern:
91
91
  """
92
92
  ),
93
93
  ] = None,
94
- title: Annotated[
95
- str,
94
+ swagger_config: Annotated[
95
+ SwaggerConfig | None,
96
96
  Doc(
97
97
  """
98
- The title of the API.
99
-
100
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
101
-
102
- Read more in the
103
- """
104
- ),
105
- ] = "Hypern",
106
- summary: Annotated[
107
- str | None,
108
- Doc(
109
- """"
110
- A short summary of the API.
111
-
112
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
113
- """
114
- ),
115
- ] = None,
116
- description: Annotated[
117
- str,
118
- Doc(
119
- """
120
- A description of the API. Supports Markdown (using
121
- [CommonMark syntax](https://commonmark.org/)).
122
-
123
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
124
- """
125
- ),
126
- ] = "",
127
- version: Annotated[
128
- str,
129
- Doc(
130
- """
131
- The version of the API.
132
-
133
- **Note** This is the version of your application, not the version of
134
- the OpenAPI specification nor the version of Application being used.
135
-
136
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
137
- """
138
- ),
139
- ] = "0.0.1",
140
- contact: Annotated[
141
- Contact | None,
142
- Doc(
143
- """
144
- A dictionary with the contact information for the exposed API.
145
-
146
- It can contain several fields.
147
-
148
- * `name`: (`str`) The name of the contact person/organization.
149
- * `url`: (`str`) A URL pointing to the contact information. MUST be in
150
- the format of a URL.
151
- * `email`: (`str`) The email address of the contact person/organization.
152
- MUST be in the format of an email address.
153
- """
154
- ),
155
- ] = None,
156
- openapi_url: Annotated[
157
- str | None,
158
- Doc(
159
- """
160
- The URL where the OpenAPI schema will be served from.
161
-
162
- If you set it to `None`, no OpenAPI schema will be served publicly, and
163
- the default automatic endpoints `/docs` and `/redoc` will also be
164
- disabled.
165
- """
166
- ),
167
- ] = "/openapi.json",
168
- docs_url: Annotated[
169
- str | None,
170
- Doc(
171
- """
172
- The path to the automatic interactive API documentation.
173
- It is handled in the browser by Swagger UI.
174
-
175
- The default URL is `/docs`. You can disable it by setting it to `None`.
176
-
177
- If `openapi_url` is set to `None`, this will be automatically disabled.
178
- """
179
- ),
180
- ] = "/docs",
181
- license_info: Annotated[
182
- License | None,
183
- Doc(
184
- """
185
- A dictionary with the license information for the exposed API.
186
-
187
- It can contain several fields.
188
-
189
- * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The
190
- license name used for the API.
191
- * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression
192
- for the API. The `identifier` field is mutually exclusive of the `url`
193
- field. Available since OpenAPI 3.1.0
194
- * `url`: (`str`) A URL to the license used for the API. This MUST be
195
- the format of a URL.
196
-
197
- It will be added to the generated OpenAPI (e.g. visible at `/docs`).
198
-
199
- **Example**
200
-
201
- ```python
202
- app = Hypern(
203
- license_info={
204
- "name": "Apache 2.0",
205
- "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
206
- }
207
- )
208
- ```
98
+ A dictionary with the configuration for the Swagger UI documentation.
209
99
  """
210
100
  ),
211
101
  ] = None,
@@ -241,6 +131,7 @@ class Hypern:
241
131
  self.shutdown_handler = None
242
132
  self.database_config = database_config
243
133
  self.thread_config = ThreadConfigurator().get_config()
134
+ self.swagger_config = swagger_config
244
135
 
245
136
  for route in routes or []:
246
137
  self.router.extend_route(route())
@@ -249,25 +140,12 @@ class Hypern:
249
140
  for route in websocket_route.routes:
250
141
  self.websocket_router.add_route(route)
251
142
 
252
- if openapi_url and docs_url:
253
- self.__add_openapi(
254
- info=Info(
255
- title=title,
256
- summary=summary,
257
- description=description,
258
- version=version,
259
- contact=contact,
260
- license=license_info,
261
- ),
262
- openapi_url=openapi_url,
263
- docs_url=docs_url,
264
- )
143
+ if swagger_config:
144
+ self.__add_openapi(config=swagger_config)
265
145
 
266
146
  def __add_openapi(
267
147
  self,
268
- info: Info,
269
- openapi_url: str,
270
- docs_url: str,
148
+ config: SwaggerConfig,
271
149
  ):
272
150
  """
273
151
  Adds OpenAPI schema and documentation routes to the application.
@@ -285,25 +163,19 @@ class Hypern:
285
163
  """
286
164
 
287
165
  def schema(*args, **kwargs):
288
- schemas = SchemaGenerator(
289
- {
290
- "openapi": "3.0.0",
291
- "info": info.model_dump(),
292
- "components": {"securitySchemes": {}},
293
- }
294
- )
166
+ schemas = SchemaGenerator(config=config)
295
167
  return JSONResponse(content=orjson.dumps(schemas.get_schema(self)))
296
168
 
297
169
  def template_render(*args, **kwargs):
298
170
  swagger = SwaggerUI(
299
171
  title="Swagger",
300
- openapi_url=openapi_url,
172
+ openapi_url=config.openapi_url,
301
173
  )
302
174
  template = swagger.get_html_content()
303
175
  return HTMLResponse(template)
304
176
 
305
- self.add_route(HTTPMethod.GET, openapi_url, schema)
306
- self.add_route(HTTPMethod.GET, docs_url, template_render)
177
+ self.add_route(HTTPMethod.GET, config.openapi_url, schema)
178
+ self.add_route(HTTPMethod.GET, config.docs_url, template_render)
307
179
 
308
180
  def inject(self, key: str, value: Any):
309
181
  """
hypern/auth/__init__.py CHANGED
@@ -0,0 +1,6 @@
1
+ # hypern/auth/__init__.py
2
+ from .jwt import JWTAuth, JWTConfig
3
+ from .middleware import AuthMiddleware
4
+ from .decorators import requires_auth
5
+
6
+ __all__ = ["JWTAuth", "JWTConfig", "AuthMiddleware", "requires_auth"]
@@ -0,0 +1,41 @@
1
+ import asyncio
2
+ from functools import wraps
3
+ from typing import Any, Callable, List, Optional
4
+
5
+ from hypern.hypern import Request, Response
6
+ from hypern.response import JSONResponse
7
+
8
+
9
+ def requires_auth(roles: Optional[List[str]] = None):
10
+ """
11
+ A decorator to enforce authentication and authorization on an endpoint.
12
+
13
+ Args:
14
+ roles (Optional[List[str]]): A list of roles that are allowed to access the endpoint. If None, any authenticated user can access.
15
+
16
+ Returns:
17
+ Callable: The decorated function with authentication and authorization checks.
18
+
19
+ The decorator checks if the request has an 'auth' attribute. If not, it returns a 401 Unauthorized response.
20
+ If roles are specified, it checks if the user's role is in the allowed roles. If not, it returns a 403 Forbidden response.
21
+ If the function being decorated is a coroutine, it awaits the function call.
22
+ """
23
+
24
+ def decorator(func: Callable) -> Callable:
25
+ @wraps(func)
26
+ async def wrapper(self, request: Request, *args: Any, **kwargs: Any) -> Response:
27
+ request.auth = {}
28
+ if not hasattr(request, "auth"):
29
+ return JSONResponse({"error": "Authentication required"}, status_code=401)
30
+
31
+ if roles and "role" in request.auth:
32
+ if request.auth["role"] not in roles:
33
+ return JSONResponse({"error": "Insufficient permissions"}, status_code=403)
34
+ # check function is awaitable
35
+ if asyncio.iscoroutinefunction(func):
36
+ return await func(self, request, *args, **kwargs)
37
+ return func(self, request, *args, **kwargs)
38
+
39
+ return wrapper
40
+
41
+ return decorator
hypern/auth/jwt.py ADDED
@@ -0,0 +1,37 @@
1
+ # hypern/auth/jwt.py
2
+ from datetime import datetime, timedelta, timezone
3
+ from typing import Any, Dict, Optional
4
+
5
+ import jwt
6
+ from pydantic import BaseModel
7
+
8
+
9
+ class JWTConfig(BaseModel):
10
+ secret_key: str
11
+ algorithm: str = "HS256"
12
+ access_token_expire_minutes: int = 30
13
+ refresh_token_expire_days: int = 7
14
+
15
+
16
+ class JWTAuth:
17
+ def __init__(self, config: JWTConfig):
18
+ self.config = config
19
+
20
+ def create_access_token(self, data: Dict[str, Any]) -> str:
21
+ expire = datetime.now(tz=timezone.utc) + timedelta(minutes=self.config.access_token_expire_minutes)
22
+ to_encode = data.copy()
23
+ to_encode.update({"exp": expire, "type": "access"})
24
+ return jwt.encode(to_encode, self.config.secret_key, algorithm=self.config.algorithm)
25
+
26
+ def create_refresh_token(self, data: Dict[str, Any]) -> str:
27
+ expire = datetime.now(tz=timezone.utc) + timedelta(days=self.config.refresh_token_expire_days)
28
+ to_encode = data.copy()
29
+ to_encode.update({"exp": expire, "type": "refresh"})
30
+ return jwt.encode(to_encode, self.config.secret_key, algorithm=self.config.algorithm)
31
+
32
+ def verify_token(self, token: str) -> Optional[Dict[str, Any]]:
33
+ try:
34
+ payload = jwt.decode(token, self.config.secret_key, algorithms=[self.config.algorithm])
35
+ return payload
36
+ except jwt.PyJWTError:
37
+ return None
@@ -0,0 +1,31 @@
1
+ # hypern/auth/middleware.py
2
+ from typing import List, Optional
3
+
4
+ from hypern.hypern import Request
5
+ from hypern.response import JSONResponse
6
+ from hypern.middleware.base import Middleware
7
+
8
+ from .jwt import JWTAuth
9
+
10
+
11
+ class AuthMiddleware(Middleware):
12
+ def __init__(self, jwt_auth: JWTAuth, exclude_paths: Optional[List[str]] = None):
13
+ self.jwt_auth = jwt_auth
14
+ self.exclude_paths = exclude_paths or []
15
+
16
+ async def before_request(self, request: Request):
17
+ if request.path in self.exclude_paths:
18
+ return None
19
+
20
+ auth_header = request.headers.get("Authorization")
21
+ if not auth_header or not auth_header.startswith("Bearer "):
22
+ return JSONResponse({"error": "Invalid authentication"}, status_code=401)
23
+
24
+ token = auth_header.split(" ")[1]
25
+ payload = self.jwt_auth.verify_token(token)
26
+
27
+ if not payload:
28
+ return JSONResponse({"error": "Invalid token"}, status_code=401)
29
+
30
+ request.auth = payload
31
+ return None
@@ -0,0 +1,36 @@
1
+ from typing import Dict
2
+ from dataclasses import dataclass
3
+
4
+
5
+ @dataclass
6
+ class OAuth2Provider:
7
+ name: str
8
+ client_id: str
9
+ client_secret: str
10
+ authorize_url: str
11
+ token_url: str
12
+ scopes: Dict[str, str]
13
+
14
+
15
+ class OAuth2Providers:
16
+ @staticmethod
17
+ def github(client_id: str, client_secret: str) -> OAuth2Provider:
18
+ return OAuth2Provider(
19
+ name="GitHub",
20
+ client_id=client_id,
21
+ client_secret=client_secret,
22
+ authorize_url="https://github.com/login/oauth/authorize",
23
+ token_url="https://github.com/login/oauth/access_token",
24
+ scopes={"user": "Read user information", "repo": "Access repositories"},
25
+ )
26
+
27
+ @staticmethod
28
+ def google(client_id: str, client_secret: str) -> OAuth2Provider:
29
+ return OAuth2Provider(
30
+ name="Google",
31
+ client_id=client_id,
32
+ client_secret=client_secret,
33
+ authorize_url="https://accounts.google.com/o/oauth2/v2/auth",
34
+ token_url="https://oauth2.googleapis.com/token",
35
+ scopes={"profile": "Read user profile", "email": "Read user email"},
36
+ )
hypern/datastructures.py CHANGED
@@ -1,5 +1,6 @@
1
- from typing import Optional
1
+ from typing import Optional, Dict
2
2
  from pydantic import BaseModel, AnyUrl
3
+ from dataclasses import dataclass, field
3
4
 
4
5
 
5
6
  class BaseModelWithConfig(BaseModel):
@@ -19,9 +20,59 @@ class License(BaseModelWithConfig):
19
20
 
20
21
 
21
22
  class Info(BaseModelWithConfig):
22
- title: str
23
+ title: str = "Swagger Document"
24
+ version: str = "0.0.1"
23
25
  summary: Optional[str] = None
24
26
  description: Optional[str] = None
25
27
  contact: Optional[Contact] = None
26
28
  license: Optional[License] = None
27
- version: str
29
+
30
+
31
+ @dataclass
32
+ class OAuth2Flow:
33
+ authorizationUrl: Optional[str] = None
34
+ tokenUrl: Optional[str] = None
35
+ refreshUrl: Optional[str] = None
36
+ scopes: Dict[str, str] = field(default_factory=dict)
37
+
38
+
39
+ @dataclass
40
+ class OAuth2Config:
41
+ flows: Dict[str, OAuth2Flow]
42
+ description: str = "OAuth2 authentication"
43
+
44
+
45
+ @dataclass
46
+ class SwaggerConfig:
47
+ info: Info
48
+ oauth2_config: Optional[OAuth2Config] = None
49
+ openapi_url: str = "/openapi.json"
50
+ docs_url: str = "/docs"
51
+
52
+ def get_security_schemes(self) -> Dict:
53
+ if not self.oauth2_config:
54
+ return {}
55
+
56
+ security_schemes = {"oauth2": {"type": "oauth2", "description": self.oauth2_config.description, "flows": {}}}
57
+
58
+ for flow_name, flow in self.oauth2_config.flows.items():
59
+ flow_config = {}
60
+ if flow.authorizationUrl:
61
+ flow_config["authorizationUrl"] = flow.authorizationUrl
62
+ if flow.tokenUrl:
63
+ flow_config["tokenUrl"] = flow.tokenUrl
64
+ if flow.refreshUrl:
65
+ flow_config["refreshUrl"] = flow.refreshUrl
66
+ flow_config["scopes"] = flow.scopes
67
+ security_schemes["oauth2"]["flows"][flow_name] = flow_config
68
+
69
+ return security_schemes
70
+
71
+ def get_openapi_schema(self) -> Dict:
72
+ schema = {
73
+ "openapi": "3.0.3",
74
+ "info": self.info.model_dump(),
75
+ "components": {"securitySchemes": self.get_security_schemes()},
76
+ "security": [{"oauth2": []}] if self.oauth2_config else [],
77
+ }
78
+ return schema
hypern/hypern.pyi CHANGED
@@ -294,6 +294,7 @@ class Request:
294
294
  remote_addr: str
295
295
  timestamp: float
296
296
  context_id: str
297
+ auth: Dict[str, Any]
297
298
 
298
299
  def json(self) -> Dict[str, Any]: ...
299
300
  def set_body(self, body: BodyData) -> None: ...
hypern/openapi/schemas.py CHANGED
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from hypern.hypern import BaseSchemaGenerator, Route as InternalRoute
5
+ from hypern.datastructures import SwaggerConfig
5
6
  import typing
6
7
  import orjson
7
8
 
@@ -13,8 +14,8 @@ class EndpointInfo(typing.NamedTuple):
13
14
 
14
15
 
15
16
  class SchemaGenerator(BaseSchemaGenerator):
16
- def __init__(self, base_schema: dict[str, typing.Any]) -> None:
17
- self.base_schema = base_schema
17
+ def __init__(self, config: SwaggerConfig) -> None:
18
+ self.config = config
18
19
 
19
20
  def get_endpoints(self, routes: list[InternalRoute]) -> list[EndpointInfo]:
20
21
  """
@@ -35,7 +36,7 @@ class SchemaGenerator(BaseSchemaGenerator):
35
36
  return endpoints_info
36
37
 
37
38
  def get_schema(self, app) -> dict[str, typing.Any]:
38
- schema = dict(self.base_schema)
39
+ schema = self.config.get_openapi_schema()
39
40
  schema.setdefault("paths", {})
40
41
  for route in app.router.routes:
41
42
  parsed = self.parse_docstring(route.doc)
hypern/routing/parser.py CHANGED
@@ -8,7 +8,6 @@ import orjson
8
8
  from pydantic import BaseModel, ValidationError
9
9
  from pydash import get
10
10
 
11
- from hypern.auth.authorization import Authorization
12
11
  from hypern.exceptions import BadRequestException
13
12
  from hypern.exceptions import ValidationException
14
13
  from hypern.hypern import Request
@@ -84,11 +83,6 @@ class InputHandler:
84
83
  kwargs[name] = await self.parse_pydantic_model(name, ptype)
85
84
  continue
86
85
 
87
- # Handle Authorization
88
- if isinstance(ptype, type) and issubclass(ptype, Authorization):
89
- kwargs[name] = await ptype().validate(self.request)
90
- continue
91
-
92
86
  # Handle special parameters
93
87
  special_value = await self.handle_special_params(name)
94
88
  if special_value is not None:
hypern/routing/route.py CHANGED
@@ -8,8 +8,6 @@ import yaml # type: ignore
8
8
  from pydantic import BaseModel
9
9
  from pydantic.fields import FieldInfo
10
10
 
11
- from hypern.auth.authorization import Authorization
12
-
13
11
  from hypern.enum import HTTPMethod
14
12
  from hypern.hypern import FunctionInfo, Request
15
13
 
@@ -176,11 +174,6 @@ class Route:
176
174
  }
177
175
  self.functional_handlers = []
178
176
 
179
- def _process_authorization(self, item: type, docs: Dict) -> None:
180
- if isinstance(item, type) and issubclass(item, Authorization):
181
- auth_obj = item()
182
- docs["security"] = [{auth_obj.name: []}]
183
-
184
177
  def _process_model_params(self, key: str, item: type, docs: Dict) -> None:
185
178
  if not (isinstance(item, type) and issubclass(item, BaseModel)):
186
179
  return
@@ -210,7 +203,6 @@ class Route:
210
203
  _docs: Dict = {"summary": summary, "tags": self.tags, "responses": [], "name": self.name}
211
204
 
212
205
  for key, item in _inputs_dict.items():
213
- self._process_authorization(item, _docs)
214
206
  self._process_model_params(key, item, _docs)
215
207
 
216
208
  self._process_response(signature.return_annotation, _docs)
@@ -1,24 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypern
3
- Version: 0.3.13
3
+ Version: 0.3.15
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
7
- Requires-Dist: sqlalchemy[asyncio] ==2.0.31
8
- Requires-Dist: pyjwt ==2.8.0
9
- Requires-Dist: pydash ==8.0.3
10
- Requires-Dist: sentry-sdk ==2.11.0
11
- Requires-Dist: celery ==5.4.0
12
- Requires-Dist: psycopg ==3.2.3
13
- Requires-Dist: pyyaml ==6.0.2
14
- Requires-Dist: orjson ==3.10.11
15
- Requires-Dist: multiprocess ==0.70.17
16
- Requires-Dist: uvloop ==0.21.0 ; sys_platform != 'win32' and platform_python_implementation == 'CPython' and platform_machine != 'armv7l'
17
- Requires-Dist: watchdog ==6.0.0
18
- Requires-Dist: psutil ==6.1.0
19
- Requires-Dist: msgpack ==1.1.0
20
- Requires-Dist: redis ==5.2.1
21
- Requires-Dist: pydantic ==2.10.4
7
+ Requires-Dist: sqlalchemy[asyncio]==2.0.31
8
+ Requires-Dist: pyjwt==2.8.0
9
+ Requires-Dist: pydash==8.0.3
10
+ Requires-Dist: sentry-sdk==2.11.0
11
+ Requires-Dist: celery==5.4.0
12
+ Requires-Dist: psycopg==3.2.3
13
+ Requires-Dist: pyyaml==6.0.2
14
+ Requires-Dist: orjson==3.10.11
15
+ Requires-Dist: multiprocess==0.70.17
16
+ Requires-Dist: uvloop==0.21.0 ; platform_machine != 'armv7l' and platform_python_implementation == 'CPython' and sys_platform != 'win32'
17
+ Requires-Dist: watchdog==6.0.0
18
+ Requires-Dist: psutil==6.1.0
19
+ Requires-Dist: msgpack==1.1.0
20
+ Requires-Dist: redis==5.2.1
21
+ Requires-Dist: pydantic==2.10.4
22
22
  License-File: LICENSE
23
23
  Summary: A Fast Async Python backend with a Rust runtime.
24
24
  Author-email: Martin Dang <vannghiem848@gmail.com>
@@ -1,71 +1,74 @@
1
- hypern-0.3.13.dist-info/METADATA,sha256=w5XKaqmlyZArzd-TJhzABRgXo1WLLQfG2QedTkWVl-8,4007
2
- hypern-0.3.13.dist-info/WHEEL,sha256=sU8_Tc9kxjXV3czvC3KzhaU1_RvW7LJkgvSdRAufvxo,129
3
- hypern-0.3.13.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
- hypern/worker.py,sha256=_m0NV-Srn4NGi65UciOOg3t4Bk6wGm0PMG4_1EYi6Zk,9487
5
- hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1
+ hypern-0.3.15.dist-info/METADATA,sha256=jwBlqCAtibNdltKg6m0bYu7lywh8IeS3JD_JZT2hvdY,3992
2
+ hypern-0.3.15.dist-info/WHEEL,sha256=SW30N8kywnSNNSd8rZHXljiViD5k9KuBxLtnK5N91_Q,129
3
+ hypern-0.3.15.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
+ hypern/hypern.pyi,sha256=1o1ONZ4utz78DB4yi_vas_BGqIveJPYVKCSezntvEgY,8743
6
5
  hypern/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- hypern/gateway/service.py,sha256=kxKTBZN0ZjuNEp8uwFldQWql-g1q1AECXUjKZsICdLg,1649
8
- hypern/gateway/proxy.py,sha256=cgMFJ6znUMWRDgPgnRz7HmPT6UUY6Z09-8HAxkCWGgk,2403
9
- hypern/gateway/gateway.py,sha256=rAZrS9db55tQGUfEfVNIKw6EetBdHAcSXyrC7rLfCZ8,1434
10
- hypern/gateway/aggregator.py,sha256=Z4LnsDlVDtlPlhsSKu8jCD0UsbztXOLu6UAVtkgJwQk,1100
11
- hypern/gateway/__init__.py,sha256=4wyCK49W_sTBCh0hkTdEli6kdRUFu9UBxncV6EXBxwA,229
12
- hypern/routing/queue.py,sha256=Yus-49N4xc7O5S3YYxqL0muFLypu_Zgd0u2SADFh-Uk,7001
6
+ hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ hypern/enum.py,sha256=6sLKuH5fQwc-XpSjf_Z9-lQpi3Id5xqAnl3ihvLF-8Y,551
13
8
  hypern/routing/endpoint.py,sha256=AWLHLQNlSGR8IGU6xM0RP-1kP06OJQzqpbXKSiZEzEo,996
14
- hypern/routing/dispatcher.py,sha256=8_JuxyyOMiCqY3WsqcjSzUTpYjIGbvzGtI8j9T-fIkA,2391
15
- hypern/routing/route.py,sha256=Xbws-l5FooG9s_BLgmjqGfgJvapuMhrHYPN8qPb6iag,10196
16
- hypern/routing/parser.py,sha256=iYaTAcZCeHgx2QpQSbQ7kQPhDOJQw5DJA6HFk2bqlhM,3320
9
+ hypern/routing/queue.py,sha256=Yus-49N4xc7O5S3YYxqL0muFLypu_Zgd0u2SADFh-Uk,7001
17
10
  hypern/routing/__init__.py,sha256=FvmUQlSraZ91q9AFGkgj3ELIep1jiKZLBCDrXIVf5DI,157
11
+ hypern/routing/route.py,sha256=DFBTq_S_Uwjl4DaoXH6cQ_VwqXEw-cEuZp5-4AcL_d8,9865
12
+ hypern/routing/parser.py,sha256=fnrsrZrxODhYNLuGP2WGDJyexve_gmTyuBz3qZCnzeU,3062
13
+ hypern/routing/dispatcher.py,sha256=8_JuxyyOMiCqY3WsqcjSzUTpYjIGbvzGtI8j9T-fIkA,2391
18
14
  hypern/args_parser.py,sha256=hRlZe6VOZUutynVPXzCS8Mpn_Qp36MDDV0hFLNjM5YM,2149
19
- hypern/datastructures.py,sha256=q0jWNQBDVcwxIeD9-s9N266rA7aIYn6nAtN4z0Neogk,616
20
- hypern/database/sqlalchemy/repository.py,sha256=YShEl1DqRXtYwNnn1F3YVfXX-TEdoNRjDEWIO_3Lu2s,9226
21
- hypern/database/sqlalchemy/config.py,sha256=AyeDJnWtq42NFLX65T0w04yhX7l9x8t6lXFq8U4WgfE,2580
22
- hypern/database/sqlalchemy/__init__.py,sha256=U_9q6L3V7VIRN-neeN5mVb1z6wKf7_GjWptgUl8-xxI,150
23
- hypern/database/sqlx/query.py,sha256=_SRoXXXdVZ_kRLcvrYCtxmIbpb1GE3BpBg4rseHhctc,32442
24
- hypern/database/sqlx/migrate.py,sha256=gHoZFUPop7OGp_cVic8pKiVnnV1-j2oUAJ9lXVfBBAA,9479
25
- hypern/database/sqlx/model.py,sha256=5liN9IP6cKZhW2SZqQE5ynFNCPVkGL9_xoyPu5PAyjQ,3927
26
- hypern/database/sqlx/__init__.py,sha256=1GJLdJfh1Dgy6o1tyl6Aus431rhrX4shhE53M9FLQl0,609
27
- hypern/database/sqlx/field.py,sha256=C7vxo6VvCeOWxG3-GFrwe23xC4AiZ3fGqOzZTDbkC8c,8875
28
- hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- hypern/application.py,sha256=TlMbzJc3F0ZTymAzA-hOtxXYmEuhGeckB0iIirYBxnI,17595
30
15
  hypern/i18n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- hypern/processpool.py,sha256=N7KFG2ZJm-YlF-QzfUfQsorWsV3yav_HsyDLVWDGEJk,3623
32
- hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
16
+ hypern/worker.py,sha256=_m0NV-Srn4NGi65UciOOg3t4Bk6wGm0PMG4_1EYi6Zk,9487
17
+ hypern/reload.py,sha256=Y2pjHHh8Zv0z-pRkBPLezKiowRblb1ZJ7yI_oE55D4U,1523
18
+ hypern/application.py,sha256=4Ba-nnyAT0Ri0RY0OQz6ynedcO1xOWKdbjKgsTgCyis,13279
33
19
  hypern/logging/__init__.py,sha256=lzYSz0382eIM3CvP0sZ6RbEEwYZwfeJEJh9cxQA6Rws,49
34
- hypern/exceptions/errors.py,sha256=mt6ZXUGHFZ_FfyP7sZFj4XT6amb5G-1Fa_26rH7BSWc,842
20
+ hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
21
+ hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ hypern/caching/backend.py,sha256=Tj66YSepGUvpXrwC04gSdJzs45IepHA2hNlMtnRVB6c,798
23
+ hypern/caching/redis_backend.py,sha256=nRkAq07B248iFljn9TxE4tadYUeM8RqqERZWzEpfk7E,5767
24
+ hypern/caching/strategies.py,sha256=VU0FpYmIK6rEjjJSwRXPrprYdo0d2u1s9OxB3OAvs3g,7080
25
+ hypern/caching/__init__.py,sha256=I7X3bmdEHeHs80kjAI1s0mMlVD7RKmw9I-QupaTAIWo,346
26
+ hypern/config.py,sha256=Ksn2LnHU0yhtGUjnac9bNjqtxl7IcPKmMdbDfZYm7Jo,7911
27
+ hypern/processpool.py,sha256=N7KFG2ZJm-YlF-QzfUfQsorWsV3yav_HsyDLVWDGEJk,3623
28
+ hypern/__init__.py,sha256=LsEtm_FRdyAx0Eh51hjPXr_SH9BCyyIzNeBGTN76rRM,778
29
+ hypern/exceptions/http.py,sha256=N98kHaQtH4x9EW6Gavrcr-Ll_-HDvsDSaRAX1sNuN4A,3150
35
30
  hypern/exceptions/base.py,sha256=_tt42Tuy_7oXR-THhJ00lZFsCJMKWbArJyTlF-kcgH4,1955
36
- hypern/exceptions/common.py,sha256=p9cx3PC6Azn0WAz7jCH02DEoLRLCCvKqNrL-dGhMGSQ,215
31
+ hypern/exceptions/errors.py,sha256=mt6ZXUGHFZ_FfyP7sZFj4XT6amb5G-1Fa_26rH7BSWc,842
37
32
  hypern/exceptions/__init__.py,sha256=t4GhxGHjOPgPQ34f0MycMjoRGw5u3TRb3OcTDYc4Orw,936
33
+ hypern/exceptions/common.py,sha256=p9cx3PC6Azn0WAz7jCH02DEoLRLCCvKqNrL-dGhMGSQ,215
38
34
  hypern/exceptions/formatters.py,sha256=51krRQIUq3uvwvcQm81mYPifdp2r2ckwC98pXI5v_P8,2330
39
- hypern/exceptions/http.py,sha256=N98kHaQtH4x9EW6Gavrcr-Ll_-HDvsDSaRAX1sNuN4A,3150
40
- hypern/ws/channel.py,sha256=TWaqowshz3WZRdg7ApBdFtVAlZW0OsVqoOHoFtXaZrk,3103
41
- hypern/ws/route.py,sha256=8YPTf1fsF46oCyqoXePC3mEbhjNVFDp8rqyWSsBHhBA,777
42
- hypern/ws/room.py,sha256=9u6gLq1WY4hn9_yEniavaY0yetFbQzgya_g6VPN-cgg,2522
43
- hypern/ws/heartbeat.py,sha256=PIrYWnQn8VxQjfDXDmtMymMl-wN5MQ_Q6oHfAjPWznU,2787
44
- hypern/ws/__init__.py,sha256=iUYERiHxs7HCmHj7CS5iG2XewKAJgW7w8kqxSORu_N8,127
45
- hypern/config.py,sha256=Ksn2LnHU0yhtGUjnac9bNjqtxl7IcPKmMdbDfZYm7Jo,7911
46
- hypern/openapi/schemas.py,sha256=Hg8G4aPZ1xXJTKFWhx8BgwRsDt2yw-v0N6LVjJ_qBHU,1547
47
- hypern/openapi/swagger.py,sha256=E5fHYUfFa77zQsCyQGf_vnqJVpl4_KI5qsKFHdgJEdw,61
48
- hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
49
- hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- hypern/enum.py,sha256=6sLKuH5fQwc-XpSjf_Z9-lQpi3Id5xqAnl3ihvLF-8Y,551
51
- hypern/middleware/limit.py,sha256=oWNt-XqYdORJuJMgg8pLYoEpHVm1cZBOPatxk8g7Nao,8075
52
- hypern/middleware/cache.py,sha256=b4hRh1smFwhJE789hZ0p4TlkQ8ZjYR-7fXg9rI7uvbc,7406
35
+ hypern/datastructures.py,sha256=OqJSklqNWb06jY_x7bJSIRzN6Cj-OewVUXqwhsX8AHY,2251
53
36
  hypern/middleware/compress.py,sha256=2eyxkYMgmsL6klbcTqr7WK0rFTo0grU0ZKQF15pVUBI,3041
54
37
  hypern/middleware/base.py,sha256=IXmEe7x_X5YykBsxTpko6ApsvNmVqfZ7IHBgJSSEWnY,356
55
38
  hypern/middleware/cors.py,sha256=q8Ts_znqApdUJYSJyLlRIbYKxxTQy6WNnJD6Kqbl32I,1759
39
+ hypern/middleware/i18n.py,sha256=s82nQo6kKClZ0s3G3jsy87VRfwxpBDbASB_ErjRL3O0,15
40
+ hypern/middleware/limit.py,sha256=oWNt-XqYdORJuJMgg8pLYoEpHVm1cZBOPatxk8g7Nao,8075
41
+ hypern/middleware/cache.py,sha256=b4hRh1smFwhJE789hZ0p4TlkQ8ZjYR-7fXg9rI7uvbc,7406
56
42
  hypern/middleware/__init__.py,sha256=sPmefKAy8-XeSg6BhkZBjqV8zgreeNLxikyyM6aDFT8,476
57
43
  hypern/middleware/security.py,sha256=hPYsilqhF9mRCX7DzOQw4AKh0y5k5FL0cM_zQdb9tiA,7491
58
- hypern/middleware/i18n.py,sha256=s82nQo6kKClZ0s3G3jsy87VRfwxpBDbASB_ErjRL3O0,15
59
- hypern/reload.py,sha256=Y2pjHHh8Zv0z-pRkBPLezKiowRblb1ZJ7yI_oE55D4U,1523
60
- hypern/caching/redis_backend.py,sha256=nRkAq07B248iFljn9TxE4tadYUeM8RqqERZWzEpfk7E,5767
61
- hypern/caching/strategies.py,sha256=VU0FpYmIK6rEjjJSwRXPrprYdo0d2u1s9OxB3OAvs3g,7080
62
- hypern/caching/__init__.py,sha256=I7X3bmdEHeHs80kjAI1s0mMlVD7RKmw9I-QupaTAIWo,346
63
- hypern/caching/backend.py,sha256=Tj66YSepGUvpXrwC04gSdJzs45IepHA2hNlMtnRVB6c,798
64
- hypern/hypern.pyi,sha256=GSVs2lNIlIU6k8KL2VNOBO8jafEEqzmsmJF6PHNtwAA,8718
65
- hypern/auth/authorization.py,sha256=b8N_MiBmSJBVR45SsOI2iMGmXYOlNKbsMsrMwXApxtk,30
66
- hypern/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
- hypern/__init__.py,sha256=LsEtm_FRdyAx0Eh51hjPXr_SH9BCyyIzNeBGTN76rRM,778
44
+ hypern/database/sqlx/field.py,sha256=C7vxo6VvCeOWxG3-GFrwe23xC4AiZ3fGqOzZTDbkC8c,8875
45
+ hypern/database/sqlx/model.py,sha256=5liN9IP6cKZhW2SZqQE5ynFNCPVkGL9_xoyPu5PAyjQ,3927
46
+ hypern/database/sqlx/query.py,sha256=_SRoXXXdVZ_kRLcvrYCtxmIbpb1GE3BpBg4rseHhctc,32442
47
+ hypern/database/sqlx/__init__.py,sha256=1GJLdJfh1Dgy6o1tyl6Aus431rhrX4shhE53M9FLQl0,609
48
+ hypern/database/sqlx/migrate.py,sha256=gHoZFUPop7OGp_cVic8pKiVnnV1-j2oUAJ9lXVfBBAA,9479
49
+ hypern/database/sqlalchemy/repository.py,sha256=YShEl1DqRXtYwNnn1F3YVfXX-TEdoNRjDEWIO_3Lu2s,9226
50
+ hypern/database/sqlalchemy/config.py,sha256=AyeDJnWtq42NFLX65T0w04yhX7l9x8t6lXFq8U4WgfE,2580
51
+ hypern/database/sqlalchemy/__init__.py,sha256=U_9q6L3V7VIRN-neeN5mVb1z6wKf7_GjWptgUl8-xxI,150
52
+ hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
+ hypern/auth/decorators.py,sha256=GE6301SA3E-jbIOUWilN4qQItEAhsOxuuO5DiODekaM,1683
54
+ hypern/auth/middleware.py,sha256=fxzam9puG22m8GfPLUGl1PH20CXD8CMXWuD070VCjVw,1004
55
+ hypern/auth/jwt.py,sha256=0WWGvx4SGxBjwVLZuJHu-VBBtGTDsYzFrC6qblTpA8M,1382
56
+ hypern/auth/__init__.py,sha256=jkZdBU_MPOlY2telFamf42JxvAyiLS6rZEY5bMfgFIQ,210
57
+ hypern/auth/providers.py,sha256=lgpsELn2FjkYnwiJ5NusCqs8j0DmT8wGQOuwh0AC0xM,1144
58
+ hypern/openapi/swagger.py,sha256=E5fHYUfFa77zQsCyQGf_vnqJVpl4_KI5qsKFHdgJEdw,61
59
+ hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
60
+ hypern/openapi/schemas.py,sha256=Vln43RVQrjdzTHQrgO8kx28K_YNUygClEHs0VLDXl_0,1582
61
+ hypern/ws/heartbeat.py,sha256=PIrYWnQn8VxQjfDXDmtMymMl-wN5MQ_Q6oHfAjPWznU,2787
62
+ hypern/ws/channel.py,sha256=TWaqowshz3WZRdg7ApBdFtVAlZW0OsVqoOHoFtXaZrk,3103
63
+ hypern/ws/__init__.py,sha256=iUYERiHxs7HCmHj7CS5iG2XewKAJgW7w8kqxSORu_N8,127
64
+ hypern/ws/room.py,sha256=9u6gLq1WY4hn9_yEniavaY0yetFbQzgya_g6VPN-cgg,2522
65
+ hypern/ws/route.py,sha256=8YPTf1fsF46oCyqoXePC3mEbhjNVFDp8rqyWSsBHhBA,777
66
+ hypern/gateway/gateway.py,sha256=rAZrS9db55tQGUfEfVNIKw6EetBdHAcSXyrC7rLfCZ8,1434
67
+ hypern/gateway/proxy.py,sha256=cgMFJ6znUMWRDgPgnRz7HmPT6UUY6Z09-8HAxkCWGgk,2403
68
+ hypern/gateway/aggregator.py,sha256=Z4LnsDlVDtlPlhsSKu8jCD0UsbztXOLu6UAVtkgJwQk,1100
69
+ hypern/gateway/service.py,sha256=kxKTBZN0ZjuNEp8uwFldQWql-g1q1AECXUjKZsICdLg,1649
70
+ hypern/gateway/__init__.py,sha256=4wyCK49W_sTBCh0hkTdEli6kdRUFu9UBxncV6EXBxwA,229
68
71
  hypern/response/response.py,sha256=qa-jmce1PpMezn0GRO6hR5SV0O-y8BspBAm6MdPcreQ,4699
69
72
  hypern/response/__init__.py,sha256=9z99BDgASpG404GK8LGkOsXgac0wFwH_cQOTI5Ju-1U,223
70
- hypern/hypern.cpython-312-arm-linux-gnueabihf.so,sha256=WjIBCQOE12nGluEr-muwLj1VqHad7y5Rh5SWhhELmCE,8758344
71
- hypern-0.3.13.dist-info/RECORD,,
73
+ hypern/hypern.cpython-312-arm-linux-gnueabihf.so,sha256=duXnYGM0MTExdv33doeJu5aN7X1smf_h7b4sHDyFYC8,8733784
74
+ hypern-0.3.15.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.1)
2
+ Generator: maturin (1.8.3)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l
@@ -1,2 +0,0 @@
1
- class Authorization:
2
- pass