pulse-framework 0.1.39__py3-none-any.whl → 0.1.41__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.
- pulse/__init__.py +14 -4
- pulse/app.py +176 -126
- pulse/channel.py +7 -7
- pulse/cli/cmd.py +81 -45
- pulse/cli/models.py +2 -0
- pulse/cli/processes.py +67 -22
- pulse/cli/uvicorn_log_config.py +1 -1
- pulse/codegen/codegen.py +14 -1
- pulse/codegen/templates/layout.py +10 -2
- pulse/decorators.py +132 -40
- pulse/form.py +9 -9
- pulse/helpers.py +75 -11
- pulse/hooks/core.py +4 -3
- pulse/hooks/states.py +91 -54
- pulse/messages.py +1 -1
- pulse/middleware.py +170 -119
- pulse/plugin.py +0 -3
- pulse/proxy.py +168 -147
- pulse/queries/__init__.py +0 -0
- pulse/queries/common.py +24 -0
- pulse/queries/mutation.py +142 -0
- pulse/queries/query.py +270 -0
- pulse/queries/query_observer.py +365 -0
- pulse/queries/store.py +60 -0
- pulse/reactive.py +146 -50
- pulse/render_session.py +5 -2
- pulse/routing.py +68 -10
- pulse/state.py +8 -7
- pulse/types/event_handler.py +2 -3
- pulse/user_session.py +3 -2
- {pulse_framework-0.1.39.dist-info → pulse_framework-0.1.41.dist-info}/METADATA +1 -1
- {pulse_framework-0.1.39.dist-info → pulse_framework-0.1.41.dist-info}/RECORD +34 -29
- pulse/query.py +0 -408
- {pulse_framework-0.1.39.dist-info → pulse_framework-0.1.41.dist-info}/WHEEL +0 -0
- {pulse_framework-0.1.39.dist-info → pulse_framework-0.1.41.dist-info}/entry_points.txt +0 -0
pulse/middleware.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import asyncio
|
|
4
|
+
from collections.abc import Awaitable, Callable, Sequence
|
|
4
5
|
from typing import Any, Generic, TypeVar, overload, override
|
|
5
6
|
|
|
7
|
+
from pulse.env import env
|
|
6
8
|
from pulse.messages import (
|
|
7
9
|
ClientMessage,
|
|
10
|
+
Prerender,
|
|
8
11
|
PrerenderPayload,
|
|
9
|
-
PrerenderResult,
|
|
10
12
|
ServerInitMessage,
|
|
11
13
|
)
|
|
12
14
|
from pulse.request import PulseRequest
|
|
@@ -26,20 +28,21 @@ class NotFound: ...
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
class Ok(Generic[T]):
|
|
29
|
-
payload: T
|
|
31
|
+
payload: T
|
|
30
32
|
|
|
31
33
|
@overload
|
|
32
34
|
def __init__(self, payload: T) -> None: ...
|
|
33
35
|
@overload
|
|
34
|
-
def __init__(self, payload:
|
|
36
|
+
def __init__(self, payload: None = None) -> None: ...
|
|
35
37
|
def __init__(self, payload: T | None = None) -> None:
|
|
36
|
-
self.payload = payload
|
|
38
|
+
self.payload = payload # pyright: ignore[reportAttributeAccessIssue]
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
class Deny: ...
|
|
40
42
|
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
RoutePrerenderResponse = Ok[ServerInitMessage] | Redirect | NotFound
|
|
45
|
+
PrerenderResponse = Ok[Prerender] | Redirect | NotFound
|
|
43
46
|
ConnectResponse = Ok[None] | Deny
|
|
44
47
|
|
|
45
48
|
|
|
@@ -50,56 +53,65 @@ class PulseMiddleware:
|
|
|
50
53
|
for later use. Return a decision to allow or short-circuit the flow.
|
|
51
54
|
"""
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
dev: bool
|
|
57
|
+
|
|
58
|
+
def __init__(self, dev: bool = False) -> None:
|
|
59
|
+
"""Initialize middleware.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
dev: If True, this middleware is only active in dev environments.
|
|
63
|
+
"""
|
|
64
|
+
self.dev = dev
|
|
65
|
+
|
|
66
|
+
async def prerender(
|
|
54
67
|
self,
|
|
55
68
|
*,
|
|
56
69
|
payload: "PrerenderPayload",
|
|
57
|
-
result: "PrerenderResult",
|
|
58
70
|
request: PulseRequest,
|
|
59
71
|
session: dict[str, Any],
|
|
60
|
-
next: Callable[[],
|
|
61
|
-
) ->
|
|
72
|
+
next: Callable[[], Awaitable[PrerenderResponse]],
|
|
73
|
+
) -> PrerenderResponse:
|
|
62
74
|
"""Handle batch prerender at the top level.
|
|
63
75
|
|
|
64
|
-
Receives the full PrerenderPayload
|
|
65
|
-
(views and directives) before
|
|
76
|
+
Receives the full PrerenderPayload. Call next() to get the PrerenderResult
|
|
77
|
+
and can modify it (views and directives) before returning to the client.
|
|
66
78
|
"""
|
|
67
|
-
return next()
|
|
79
|
+
return await next()
|
|
68
80
|
|
|
69
|
-
def prerender_route(
|
|
81
|
+
async def prerender_route(
|
|
70
82
|
self,
|
|
71
83
|
*,
|
|
72
84
|
path: str,
|
|
73
85
|
request: PulseRequest,
|
|
74
86
|
route_info: RouteInfo,
|
|
75
87
|
session: dict[str, Any],
|
|
76
|
-
next: Callable[[],
|
|
77
|
-
) ->
|
|
78
|
-
return next()
|
|
88
|
+
next: Callable[[], Awaitable[RoutePrerenderResponse]],
|
|
89
|
+
) -> RoutePrerenderResponse:
|
|
90
|
+
return await next()
|
|
79
91
|
|
|
80
|
-
def connect(
|
|
92
|
+
async def connect(
|
|
81
93
|
self,
|
|
82
94
|
*,
|
|
83
95
|
request: PulseRequest,
|
|
84
96
|
session: dict[str, Any],
|
|
85
|
-
next: Callable[[], ConnectResponse],
|
|
97
|
+
next: Callable[[], Awaitable[ConnectResponse]],
|
|
86
98
|
) -> ConnectResponse:
|
|
87
|
-
return next()
|
|
99
|
+
return await next()
|
|
88
100
|
|
|
89
|
-
def message(
|
|
101
|
+
async def message(
|
|
90
102
|
self,
|
|
91
103
|
*,
|
|
92
104
|
data: ClientMessage,
|
|
93
105
|
session: dict[str, Any],
|
|
94
|
-
next: Callable[[], Ok[None]],
|
|
106
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
95
107
|
) -> Ok[None] | Deny:
|
|
96
108
|
"""Handle per-message authorization.
|
|
97
109
|
|
|
98
110
|
Return Deny() to block, Ok(None) to allow.
|
|
99
111
|
"""
|
|
100
|
-
return next()
|
|
112
|
+
return await next()
|
|
101
113
|
|
|
102
|
-
def channel(
|
|
114
|
+
async def channel(
|
|
103
115
|
self,
|
|
104
116
|
*,
|
|
105
117
|
channel_id: str,
|
|
@@ -107,9 +119,9 @@ class PulseMiddleware:
|
|
|
107
119
|
payload: Any,
|
|
108
120
|
request_id: str | None,
|
|
109
121
|
session: dict[str, Any],
|
|
110
|
-
next: Callable[[], Ok[None]],
|
|
122
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
111
123
|
) -> Ok[None] | Deny:
|
|
112
|
-
return next()
|
|
124
|
+
return await next()
|
|
113
125
|
|
|
114
126
|
|
|
115
127
|
class MiddlewareStack(PulseMiddleware):
|
|
@@ -119,56 +131,58 @@ class MiddlewareStack(PulseMiddleware):
|
|
|
119
131
|
middleware returns without calling `next`, the chain short-circuits.
|
|
120
132
|
"""
|
|
121
133
|
|
|
122
|
-
def __init__(self, middlewares: Sequence[PulseMiddleware]):
|
|
134
|
+
def __init__(self, middlewares: Sequence[PulseMiddleware]) -> None:
|
|
135
|
+
super().__init__(dev=False)
|
|
136
|
+
# Filter out dev middlewares when not in dev environment
|
|
137
|
+
if env.pulse_env != "dev":
|
|
138
|
+
middlewares = [mw for mw in middlewares if not mw.dev]
|
|
123
139
|
self._middlewares: list[PulseMiddleware] = list(middlewares)
|
|
124
140
|
|
|
125
141
|
@override
|
|
126
|
-
def prerender(
|
|
142
|
+
async def prerender(
|
|
127
143
|
self,
|
|
128
144
|
*,
|
|
129
145
|
payload: "PrerenderPayload",
|
|
130
|
-
result: "PrerenderResult",
|
|
131
146
|
request: PulseRequest,
|
|
132
147
|
session: dict[str, Any],
|
|
133
|
-
next: Callable[[],
|
|
134
|
-
) ->
|
|
135
|
-
def dispatch(index: int) ->
|
|
148
|
+
next: Callable[[], Awaitable[PrerenderResponse]],
|
|
149
|
+
) -> PrerenderResponse:
|
|
150
|
+
async def dispatch(index: int) -> PrerenderResponse:
|
|
136
151
|
if index >= len(self._middlewares):
|
|
137
|
-
return next()
|
|
152
|
+
return await next()
|
|
138
153
|
mw = self._middlewares[index]
|
|
139
154
|
|
|
140
|
-
def _next() ->
|
|
141
|
-
return dispatch(index + 1)
|
|
155
|
+
async def _next() -> PrerenderResponse:
|
|
156
|
+
return await dispatch(index + 1)
|
|
142
157
|
|
|
143
|
-
return mw.prerender(
|
|
158
|
+
return await mw.prerender(
|
|
144
159
|
payload=payload,
|
|
145
|
-
result=result,
|
|
146
160
|
request=request,
|
|
147
161
|
session=session,
|
|
148
162
|
next=_next,
|
|
149
163
|
)
|
|
150
164
|
|
|
151
|
-
return dispatch(0)
|
|
165
|
+
return await dispatch(0)
|
|
152
166
|
|
|
153
167
|
@override
|
|
154
|
-
def prerender_route(
|
|
168
|
+
async def prerender_route(
|
|
155
169
|
self,
|
|
156
170
|
*,
|
|
157
171
|
path: str,
|
|
158
172
|
request: PulseRequest,
|
|
159
173
|
route_info: RouteInfo,
|
|
160
174
|
session: dict[str, Any],
|
|
161
|
-
next: Callable[[],
|
|
162
|
-
) ->
|
|
163
|
-
def dispatch(index: int) ->
|
|
175
|
+
next: Callable[[], Awaitable[RoutePrerenderResponse]],
|
|
176
|
+
) -> RoutePrerenderResponse:
|
|
177
|
+
async def dispatch(index: int) -> RoutePrerenderResponse:
|
|
164
178
|
if index >= len(self._middlewares):
|
|
165
|
-
return next()
|
|
179
|
+
return await next()
|
|
166
180
|
mw = self._middlewares[index]
|
|
167
181
|
|
|
168
|
-
def _next() ->
|
|
169
|
-
return dispatch(index + 1)
|
|
182
|
+
async def _next() -> RoutePrerenderResponse:
|
|
183
|
+
return await dispatch(index + 1)
|
|
170
184
|
|
|
171
|
-
return mw.prerender_route(
|
|
185
|
+
return await mw.prerender_route(
|
|
172
186
|
path=path,
|
|
173
187
|
route_info=route_info,
|
|
174
188
|
request=request,
|
|
@@ -176,50 +190,56 @@ class MiddlewareStack(PulseMiddleware):
|
|
|
176
190
|
next=_next,
|
|
177
191
|
)
|
|
178
192
|
|
|
179
|
-
return dispatch(0)
|
|
193
|
+
return await dispatch(0)
|
|
180
194
|
|
|
181
195
|
@override
|
|
182
|
-
def connect(
|
|
196
|
+
async def connect(
|
|
183
197
|
self,
|
|
184
198
|
*,
|
|
185
199
|
request: PulseRequest,
|
|
186
200
|
session: dict[str, Any],
|
|
187
|
-
next: Callable[[], ConnectResponse],
|
|
201
|
+
next: Callable[[], Awaitable[ConnectResponse]],
|
|
188
202
|
) -> ConnectResponse:
|
|
189
|
-
def dispatch(index: int) -> ConnectResponse:
|
|
203
|
+
async def dispatch(index: int) -> ConnectResponse:
|
|
190
204
|
if index >= len(self._middlewares):
|
|
191
|
-
return next()
|
|
205
|
+
return await next()
|
|
192
206
|
mw = self._middlewares[index]
|
|
193
207
|
|
|
194
|
-
def _next() -> ConnectResponse:
|
|
195
|
-
return dispatch(index + 1)
|
|
208
|
+
async def _next() -> ConnectResponse:
|
|
209
|
+
return await dispatch(index + 1)
|
|
196
210
|
|
|
197
|
-
return mw.connect(request=request, session=session, next=_next)
|
|
211
|
+
return await mw.connect(request=request, session=session, next=_next)
|
|
198
212
|
|
|
199
|
-
return dispatch(0)
|
|
213
|
+
return await dispatch(0)
|
|
200
214
|
|
|
201
215
|
@override
|
|
202
|
-
def message(
|
|
216
|
+
async def message(
|
|
203
217
|
self,
|
|
204
218
|
*,
|
|
205
219
|
data: ClientMessage,
|
|
206
220
|
session: dict[str, Any],
|
|
207
|
-
next: Callable[[], Ok[None]],
|
|
221
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
208
222
|
) -> Ok[None] | Deny:
|
|
209
|
-
def dispatch(index: int) -> Ok[None] | Deny:
|
|
223
|
+
async def dispatch(index: int) -> Ok[None] | Deny:
|
|
210
224
|
if index >= len(self._middlewares):
|
|
211
|
-
return next()
|
|
225
|
+
return await next()
|
|
212
226
|
mw = self._middlewares[index]
|
|
213
227
|
|
|
214
|
-
def _next() -> Ok[None]:
|
|
215
|
-
|
|
228
|
+
async def _next() -> Ok[None]:
|
|
229
|
+
result = await dispatch(index + 1)
|
|
230
|
+
# If dispatch returns Deny, the middleware should have short-circuited
|
|
231
|
+
# This should only be called when continuing the chain
|
|
232
|
+
if isinstance(result, Deny):
|
|
233
|
+
# This shouldn't happen, but handle it gracefully
|
|
234
|
+
return Ok(None)
|
|
235
|
+
return result
|
|
216
236
|
|
|
217
|
-
return mw.message(session=session, data=data, next=_next)
|
|
237
|
+
return await mw.message(session=session, data=data, next=_next)
|
|
218
238
|
|
|
219
|
-
return dispatch(0)
|
|
239
|
+
return await dispatch(0)
|
|
220
240
|
|
|
221
241
|
@override
|
|
222
|
-
def channel(
|
|
242
|
+
async def channel(
|
|
223
243
|
self,
|
|
224
244
|
*,
|
|
225
245
|
channel_id: str,
|
|
@@ -227,17 +247,23 @@ class MiddlewareStack(PulseMiddleware):
|
|
|
227
247
|
payload: Any,
|
|
228
248
|
request_id: str | None,
|
|
229
249
|
session: dict[str, Any],
|
|
230
|
-
next: Callable[[], Ok[None]],
|
|
250
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
231
251
|
) -> Ok[None] | Deny:
|
|
232
|
-
def dispatch(index: int) -> Ok[None] | Deny:
|
|
252
|
+
async def dispatch(index: int) -> Ok[None] | Deny:
|
|
233
253
|
if index >= len(self._middlewares):
|
|
234
|
-
return next()
|
|
254
|
+
return await next()
|
|
235
255
|
mw = self._middlewares[index]
|
|
236
256
|
|
|
237
|
-
def _next() -> Ok[None]:
|
|
238
|
-
|
|
257
|
+
async def _next() -> Ok[None]:
|
|
258
|
+
result = await dispatch(index + 1)
|
|
259
|
+
# If dispatch returns Deny, the middleware should have short-circuited
|
|
260
|
+
# This should only be called when continuing the chain
|
|
261
|
+
if isinstance(result, Deny):
|
|
262
|
+
# This shouldn't happen, but handle it gracefully
|
|
263
|
+
return Ok(None)
|
|
264
|
+
return result
|
|
239
265
|
|
|
240
|
-
return mw.channel(
|
|
266
|
+
return await mw.channel(
|
|
241
267
|
channel_id=channel_id,
|
|
242
268
|
event=event,
|
|
243
269
|
payload=payload,
|
|
@@ -246,7 +272,7 @@ class MiddlewareStack(PulseMiddleware):
|
|
|
246
272
|
next=_next,
|
|
247
273
|
)
|
|
248
274
|
|
|
249
|
-
return dispatch(0)
|
|
275
|
+
return await dispatch(0)
|
|
250
276
|
|
|
251
277
|
|
|
252
278
|
def stack(*middlewares: PulseMiddleware) -> PulseMiddleware:
|
|
@@ -258,84 +284,108 @@ def stack(*middlewares: PulseMiddleware) -> PulseMiddleware:
|
|
|
258
284
|
return MiddlewareStack(list(middlewares))
|
|
259
285
|
|
|
260
286
|
|
|
261
|
-
class
|
|
262
|
-
"""
|
|
287
|
+
class LatencyMiddleware(PulseMiddleware):
|
|
288
|
+
"""Middleware that adds artificial latency to simulate network conditions.
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
290
|
+
Useful for testing and development to simulate real-world network delays.
|
|
291
|
+
Defaults are realistic for typical web applications.
|
|
292
|
+
|
|
293
|
+
Example:
|
|
294
|
+
```python
|
|
295
|
+
app = ps.App(
|
|
296
|
+
middleware=ps.LatencyMiddleware(
|
|
297
|
+
prerender_ms=100,
|
|
298
|
+
connect_ms=50,
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
```
|
|
266
302
|
"""
|
|
267
303
|
|
|
304
|
+
prerender_ms: float
|
|
305
|
+
prerender_route_ms: float
|
|
306
|
+
connect_ms: float
|
|
307
|
+
message_ms: float
|
|
308
|
+
channel_ms: float
|
|
309
|
+
|
|
310
|
+
def __init__(
|
|
311
|
+
self,
|
|
312
|
+
*,
|
|
313
|
+
prerender_ms: float = 80.0,
|
|
314
|
+
prerender_route_ms: float = 60.0,
|
|
315
|
+
connect_ms: float = 40.0,
|
|
316
|
+
message_ms: float = 25.0,
|
|
317
|
+
channel_ms: float = 20.0,
|
|
318
|
+
) -> None:
|
|
319
|
+
"""Initialize latency middleware.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
prerender_ms: Latency for batch prerender requests (HTTP). Default: 80ms
|
|
323
|
+
prerender_route_ms: Latency for individual route prerenders. Default: 60ms
|
|
324
|
+
connect_ms: Latency for WebSocket connections. Default: 40ms
|
|
325
|
+
message_ms: Latency for WebSocket messages (including API calls). Default: 25ms
|
|
326
|
+
channel_ms: Latency for channel messages. Default: 20ms
|
|
327
|
+
dev: If True, only active in dev environments. Default: True
|
|
328
|
+
"""
|
|
329
|
+
super().__init__(dev=True)
|
|
330
|
+
self.prerender_ms = prerender_ms
|
|
331
|
+
self.prerender_route_ms = prerender_route_ms
|
|
332
|
+
self.connect_ms = connect_ms
|
|
333
|
+
self.message_ms = message_ms
|
|
334
|
+
self.channel_ms = channel_ms
|
|
335
|
+
|
|
268
336
|
@override
|
|
269
|
-
def prerender(
|
|
337
|
+
async def prerender(
|
|
270
338
|
self,
|
|
271
339
|
*,
|
|
272
340
|
payload: "PrerenderPayload",
|
|
273
|
-
result: "PrerenderResult",
|
|
274
341
|
request: PulseRequest,
|
|
275
342
|
session: dict[str, Any],
|
|
276
|
-
next: Callable[[],
|
|
277
|
-
) ->
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
# --- Normalization helpers -------------------------------------------------
|
|
283
|
-
def _normalize_prerender_response(self, res: Any) -> PrerenderResponse:
|
|
284
|
-
if isinstance(res, (Ok, Redirect, NotFound)):
|
|
285
|
-
return res # type: ignore[return-value]
|
|
286
|
-
# Treat any other value as a VDOM payload
|
|
287
|
-
return Ok(res)
|
|
288
|
-
|
|
289
|
-
def _normalize_connect_response(self, res: Any) -> ConnectResponse:
|
|
290
|
-
if isinstance(res, (Ok, Deny)):
|
|
291
|
-
return res # type: ignore[return-value]
|
|
292
|
-
# Treat any other value as allow
|
|
293
|
-
return Ok(None)
|
|
294
|
-
|
|
295
|
-
def _normalize_message_response(self, res: Any) -> Ok[None] | Deny:
|
|
296
|
-
if isinstance(res, (Ok, Deny)):
|
|
297
|
-
return res # type: ignore[return-value]
|
|
298
|
-
# Treat any other value as allow
|
|
299
|
-
return Ok(None)
|
|
343
|
+
next: Callable[[], Awaitable[PrerenderResponse]],
|
|
344
|
+
) -> PrerenderResponse:
|
|
345
|
+
if self.prerender_ms > 0:
|
|
346
|
+
await asyncio.sleep(self.prerender_ms / 1000.0)
|
|
347
|
+
return await next()
|
|
300
348
|
|
|
301
349
|
@override
|
|
302
|
-
def prerender_route(
|
|
350
|
+
async def prerender_route(
|
|
303
351
|
self,
|
|
304
352
|
*,
|
|
305
353
|
path: str,
|
|
306
354
|
request: PulseRequest,
|
|
307
355
|
route_info: RouteInfo,
|
|
308
356
|
session: dict[str, Any],
|
|
309
|
-
next: Callable[[],
|
|
310
|
-
) ->
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return
|
|
357
|
+
next: Callable[[], Awaitable[RoutePrerenderResponse]],
|
|
358
|
+
) -> RoutePrerenderResponse:
|
|
359
|
+
if self.prerender_route_ms > 0:
|
|
360
|
+
await asyncio.sleep(self.prerender_route_ms / 1000.0)
|
|
361
|
+
return await next()
|
|
314
362
|
|
|
315
363
|
@override
|
|
316
|
-
def connect(
|
|
364
|
+
async def connect(
|
|
317
365
|
self,
|
|
318
366
|
*,
|
|
319
367
|
request: PulseRequest,
|
|
320
368
|
session: dict[str, Any],
|
|
321
|
-
next: Callable[[], ConnectResponse],
|
|
369
|
+
next: Callable[[], Awaitable[ConnectResponse]],
|
|
322
370
|
) -> ConnectResponse:
|
|
323
|
-
|
|
324
|
-
|
|
371
|
+
if self.connect_ms > 0:
|
|
372
|
+
await asyncio.sleep(self.connect_ms / 1000.0)
|
|
373
|
+
return await next()
|
|
325
374
|
|
|
326
375
|
@override
|
|
327
|
-
def message(
|
|
376
|
+
async def message(
|
|
328
377
|
self,
|
|
329
378
|
*,
|
|
330
379
|
data: ClientMessage,
|
|
331
380
|
session: dict[str, Any],
|
|
332
|
-
next: Callable[[], Ok[None]],
|
|
381
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
333
382
|
) -> Ok[None] | Deny:
|
|
334
|
-
|
|
335
|
-
|
|
383
|
+
if self.message_ms > 0:
|
|
384
|
+
await asyncio.sleep(self.message_ms / 1000.0)
|
|
385
|
+
return await next()
|
|
336
386
|
|
|
337
387
|
@override
|
|
338
|
-
def channel(
|
|
388
|
+
async def channel(
|
|
339
389
|
self,
|
|
340
390
|
*,
|
|
341
391
|
channel_id: str,
|
|
@@ -343,7 +393,8 @@ class PulseCoreMiddleware(PulseMiddleware):
|
|
|
343
393
|
payload: Any,
|
|
344
394
|
request_id: str | None,
|
|
345
395
|
session: dict[str, Any],
|
|
346
|
-
next: Callable[[], Ok[None]],
|
|
396
|
+
next: Callable[[], Awaitable[Ok[None]]],
|
|
347
397
|
) -> Ok[None] | Deny:
|
|
348
|
-
|
|
349
|
-
|
|
398
|
+
if self.channel_ms > 0:
|
|
399
|
+
await asyncio.sleep(self.channel_ms / 1000.0)
|
|
400
|
+
return await next()
|