pulse-framework 0.1.38a6__tar.gz → 0.1.38a7__tar.gz
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_framework-0.1.38a6 → pulse_framework-0.1.38a7}/PKG-INFO +1 -1
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/pyproject.toml +1 -1
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/app.py +93 -37
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/layout.py +1 -3
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/README.md +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/channel.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/cmd.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/dependencies.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/folder_lock.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/helpers.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/models.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/packages.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/processes.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/secrets.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cli/uvicorn_log_config.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/codegen.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/imports.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/js.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/route.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/routes_ts.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/utils.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/components/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/components/for_.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/components/if_.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/components/react_router.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/context.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/cookies.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/css.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/decorators.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/env.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/form.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/helpers.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/core.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/effects.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/runtime.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/setup.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/stable.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/hooks/states.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/elements.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/events.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/props.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/svg.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/tags.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/html/tags.pyi +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/messages.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/middleware.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/plugin.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/proxy.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/py.typed +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/query.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/react_component.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/reactive.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/reactive_extensions.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/render_session.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/renderer.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/request.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/routing.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/serializer.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/state.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/types/__init__.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/types/event_handler.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/user_session.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/vdom.py +0 -0
- {pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/version.py +0 -0
|
@@ -5,6 +5,7 @@ This module provides the main App class that users instantiate in their main.py
|
|
|
5
5
|
to define routes and configure their Pulse application.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import asyncio
|
|
8
9
|
import logging
|
|
9
10
|
import os
|
|
10
11
|
from collections import defaultdict
|
|
@@ -141,6 +142,8 @@ class App:
|
|
|
141
142
|
_render_to_user: dict[str, str]
|
|
142
143
|
_sessions_in_request: dict[str, int]
|
|
143
144
|
_socket_to_render: dict[str, str]
|
|
145
|
+
_render_cleanups: dict[str, asyncio.TimerHandle]
|
|
146
|
+
session_timeout: float
|
|
144
147
|
|
|
145
148
|
def __init__(
|
|
146
149
|
self,
|
|
@@ -160,6 +163,7 @@ class App:
|
|
|
160
163
|
api_prefix: str = "/_pulse",
|
|
161
164
|
cors: CORSOptions | None = None,
|
|
162
165
|
fastapi: dict[str, Any] | None = None,
|
|
166
|
+
session_timeout: float = 60.0,
|
|
163
167
|
):
|
|
164
168
|
"""
|
|
165
169
|
Initialize a new Pulse App.
|
|
@@ -215,6 +219,9 @@ class App:
|
|
|
215
219
|
self._sessions_in_request = {}
|
|
216
220
|
# Map websocket sid -> renderId for message routing
|
|
217
221
|
self._socket_to_render = {}
|
|
222
|
+
# Map render_id -> cleanup timer handle for timeout-based expiry
|
|
223
|
+
self._render_cleanups = {}
|
|
224
|
+
self.session_timeout = session_timeout
|
|
218
225
|
|
|
219
226
|
self.codegen = Codegen(
|
|
220
227
|
self.routes,
|
|
@@ -367,7 +374,6 @@ class App:
|
|
|
367
374
|
else:
|
|
368
375
|
# Use deployment-specific CORS settings
|
|
369
376
|
cors_config = cors_options(self.mode, self.server_address)
|
|
370
|
-
print(f"CORS config: {cors_config}")
|
|
371
377
|
self.fastapi.add_middleware(
|
|
372
378
|
CORSMiddleware,
|
|
373
379
|
**cors_config,
|
|
@@ -412,10 +418,9 @@ class App:
|
|
|
412
418
|
self._sessions_in_request.get(session.sid, 0) + 1
|
|
413
419
|
)
|
|
414
420
|
render_id = request.headers.get("x-pulse-render-id")
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
render = None
|
|
421
|
+
render = self._get_render_for_session(render_id, session)
|
|
422
|
+
if render:
|
|
423
|
+
print(f"Reusing render session {render_id}")
|
|
419
424
|
with PulseContext.update(session=session, render=render):
|
|
420
425
|
res: Response = await call_next(request)
|
|
421
426
|
session.handle_response(res)
|
|
@@ -442,7 +447,8 @@ class App:
|
|
|
442
447
|
async def prerender(payload: PrerenderPayload, request: Request): # pyright: ignore[reportUnusedFunction]
|
|
443
448
|
"""
|
|
444
449
|
POST /prerender
|
|
445
|
-
Body: { paths: string[], routeInfo: RouteInfo, ttlSeconds?: number
|
|
450
|
+
Body: { paths: string[], routeInfo: RouteInfo, ttlSeconds?: number }
|
|
451
|
+
Headers: X-Pulse-Render-Id (optional, for render session reuse)
|
|
446
452
|
Returns: { renderId: string, <path>: VDOM, ... }
|
|
447
453
|
"""
|
|
448
454
|
session = PulseContext.get().session
|
|
@@ -454,29 +460,21 @@ class App:
|
|
|
454
460
|
status_code=400, detail="'paths' must be a non-empty list"
|
|
455
461
|
)
|
|
456
462
|
route_info = payload.get("routeInfo")
|
|
457
|
-
ttl = payload.get("ttlSeconds")
|
|
458
|
-
if not isinstance(ttl, (int, float)):
|
|
459
|
-
ttl = 15
|
|
460
463
|
|
|
461
464
|
client_addr: str | None = get_client_address(request)
|
|
462
|
-
#
|
|
463
|
-
|
|
464
|
-
if
|
|
465
|
-
|
|
466
|
-
existing = self.render_sessions.get(render_id)
|
|
467
|
-
if existing is None:
|
|
468
|
-
raise HTTPException(status_code=400, detail="Unknown renderId")
|
|
469
|
-
owner = self._render_to_user.get(render_id)
|
|
470
|
-
if owner != session.sid:
|
|
471
|
-
raise HTTPException(status_code=403, detail="Forbidden renderId")
|
|
472
|
-
render = existing
|
|
473
|
-
cleanup = False
|
|
465
|
+
# Reuse render session from header (set by middleware) or create new one
|
|
466
|
+
render = PulseContext.get().render
|
|
467
|
+
if render is not None:
|
|
468
|
+
render_id = render.id
|
|
474
469
|
else:
|
|
470
|
+
# Create new render session
|
|
475
471
|
render_id = new_sid()
|
|
476
472
|
render = self.create_render(
|
|
477
473
|
render_id, session, client_address=client_addr
|
|
478
474
|
)
|
|
479
|
-
|
|
475
|
+
|
|
476
|
+
# Schedule cleanup timeout (will cancel/reschedule on activity)
|
|
477
|
+
self._schedule_render_cleanup(render_id)
|
|
480
478
|
|
|
481
479
|
initial_result: PrerenderResult = {
|
|
482
480
|
"views": {},
|
|
@@ -536,18 +534,6 @@ class App:
|
|
|
536
534
|
session.handle_response(resp)
|
|
537
535
|
return resp
|
|
538
536
|
|
|
539
|
-
# schedule TTL cleanup if never connected
|
|
540
|
-
def _gc_if_unadopted(rid: str):
|
|
541
|
-
r = self.render_sessions.get(rid)
|
|
542
|
-
if r is None:
|
|
543
|
-
return
|
|
544
|
-
if r.connected:
|
|
545
|
-
return
|
|
546
|
-
self.close_render(rid)
|
|
547
|
-
|
|
548
|
-
if cleanup:
|
|
549
|
-
later(float(ttl), _gc_if_unadopted, render_id)
|
|
550
|
-
|
|
551
537
|
# Call top-level batch prerender middleware to modify final result
|
|
552
538
|
def _return_result() -> PrerenderResult:
|
|
553
539
|
return result
|
|
@@ -620,6 +606,9 @@ class App:
|
|
|
620
606
|
# Map socket sid to renderId for message routing
|
|
621
607
|
self._socket_to_render[sid] = rid
|
|
622
608
|
|
|
609
|
+
# Cancel any pending cleanup since session is now connected
|
|
610
|
+
self._cancel_render_cleanup(rid)
|
|
611
|
+
|
|
623
612
|
with PulseContext.update(session=session, render=render):
|
|
624
613
|
|
|
625
614
|
def _next():
|
|
@@ -635,6 +624,7 @@ class App:
|
|
|
635
624
|
render.report_error("/", "connect", exc)
|
|
636
625
|
res = Ok(None)
|
|
637
626
|
if isinstance(res, Deny):
|
|
627
|
+
print(f"Denying connection, closing RenderSession {rid}")
|
|
638
628
|
# Tear down the created session if denied
|
|
639
629
|
self.close_render(rid)
|
|
640
630
|
|
|
@@ -642,8 +632,12 @@ class App:
|
|
|
642
632
|
def disconnect(sid: str): # pyright: ignore[reportUnusedFunction]
|
|
643
633
|
rid = self._socket_to_render.pop(sid, None)
|
|
644
634
|
if rid is not None:
|
|
645
|
-
|
|
646
|
-
self.
|
|
635
|
+
print(f"Disconnecting WebSocket for RenderSession {rid}")
|
|
636
|
+
render = self.render_sessions.get(rid)
|
|
637
|
+
if render:
|
|
638
|
+
render.connected = False
|
|
639
|
+
# Schedule cleanup after timeout (will keep session alive for reuse)
|
|
640
|
+
self._schedule_render_cleanup(rid)
|
|
647
641
|
|
|
648
642
|
@self.sio.event
|
|
649
643
|
def message(sid: str, data: Serialized): # pyright: ignore[reportUnusedFunction]
|
|
@@ -653,6 +647,8 @@ class App:
|
|
|
653
647
|
render = self.render_sessions.get(rid)
|
|
654
648
|
if render is None:
|
|
655
649
|
return
|
|
650
|
+
# Cancel any pending cleanup for active sessions (connected sessions stay alive)
|
|
651
|
+
self._cancel_render_cleanup(rid)
|
|
656
652
|
# Use renderId mapping to user session
|
|
657
653
|
session = self.user_sessions[self._render_to_user[rid]]
|
|
658
654
|
# Make sure to properly deserialize the message contents
|
|
@@ -668,6 +664,39 @@ class App:
|
|
|
668
664
|
|
|
669
665
|
self.status = AppStatus.initialized
|
|
670
666
|
|
|
667
|
+
def _cancel_render_cleanup(self, rid: str):
|
|
668
|
+
"""Cancel any pending cleanup task for a render session."""
|
|
669
|
+
cleanup_handle = self._render_cleanups.pop(rid, None)
|
|
670
|
+
if cleanup_handle and not cleanup_handle.cancelled():
|
|
671
|
+
cleanup_handle.cancel()
|
|
672
|
+
|
|
673
|
+
def _schedule_render_cleanup(self, rid: str):
|
|
674
|
+
"""Schedule cleanup of a RenderSession after the configured timeout."""
|
|
675
|
+
render = self.render_sessions.get(rid)
|
|
676
|
+
if render is None:
|
|
677
|
+
return
|
|
678
|
+
# Don't schedule cleanup for connected sessions (they stay alive)
|
|
679
|
+
if render.connected:
|
|
680
|
+
return
|
|
681
|
+
|
|
682
|
+
# Cancel any existing cleanup task for this render session
|
|
683
|
+
self._cancel_render_cleanup(rid)
|
|
684
|
+
|
|
685
|
+
# Schedule new cleanup task
|
|
686
|
+
def _cleanup():
|
|
687
|
+
render = self.render_sessions.get(rid)
|
|
688
|
+
if render is None:
|
|
689
|
+
return
|
|
690
|
+
# Only cleanup if not connected (if connected, keep it alive)
|
|
691
|
+
if not render.connected:
|
|
692
|
+
logger.info(
|
|
693
|
+
f"RenderSession {rid} expired after {self.session_timeout}s timeout"
|
|
694
|
+
)
|
|
695
|
+
self.close_render(rid)
|
|
696
|
+
|
|
697
|
+
handle = later(self.session_timeout, _cleanup)
|
|
698
|
+
self._render_cleanups[rid] = handle
|
|
699
|
+
|
|
671
700
|
def _handle_pulse_message(
|
|
672
701
|
self, render: RenderSession, session: UserSession, msg: ClientPulseMessage
|
|
673
702
|
) -> None:
|
|
@@ -802,11 +831,29 @@ class App:
|
|
|
802
831
|
self.user_sessions[sid] = session
|
|
803
832
|
return session
|
|
804
833
|
|
|
834
|
+
def _get_render_for_session(
|
|
835
|
+
self, render_id: str | None, session: UserSession
|
|
836
|
+
) -> RenderSession | None:
|
|
837
|
+
"""
|
|
838
|
+
Get an existing render session for the given session, validating ownership.
|
|
839
|
+
Returns None if render_id is None, render doesn't exist, or doesn't belong to session.
|
|
840
|
+
"""
|
|
841
|
+
if not render_id:
|
|
842
|
+
return None
|
|
843
|
+
render = self.render_sessions.get(render_id)
|
|
844
|
+
if render is None:
|
|
845
|
+
return None
|
|
846
|
+
owner = self._render_to_user.get(render_id)
|
|
847
|
+
if owner != session.sid:
|
|
848
|
+
return None
|
|
849
|
+
return render
|
|
850
|
+
|
|
805
851
|
def create_render(
|
|
806
852
|
self, rid: str, session: UserSession, *, client_address: str | None = None
|
|
807
853
|
):
|
|
808
854
|
if rid in self.render_sessions:
|
|
809
855
|
raise ValueError(f"RenderSession {rid} already exists")
|
|
856
|
+
print(f"Creating RenderSession {rid}")
|
|
810
857
|
render = RenderSession(
|
|
811
858
|
rid,
|
|
812
859
|
self.routes,
|
|
@@ -819,9 +866,13 @@ class App:
|
|
|
819
866
|
return render
|
|
820
867
|
|
|
821
868
|
def close_render(self, rid: str):
|
|
869
|
+
# Cancel any pending cleanup task
|
|
870
|
+
self._cancel_render_cleanup(rid)
|
|
871
|
+
|
|
822
872
|
render = self.render_sessions.pop(rid, None)
|
|
823
873
|
if not render:
|
|
824
874
|
return
|
|
875
|
+
print(f"Closing RenderSession {rid}")
|
|
825
876
|
sid = self._render_to_user.pop(rid)
|
|
826
877
|
session = self.user_sessions[sid]
|
|
827
878
|
render.close()
|
|
@@ -846,7 +897,12 @@ class App:
|
|
|
846
897
|
This method is called automatically during shutdown.
|
|
847
898
|
"""
|
|
848
899
|
|
|
900
|
+
# Cancel all pending cleanup tasks
|
|
901
|
+
for rid in list(self._render_cleanups.keys()):
|
|
902
|
+
self._cancel_render_cleanup(rid)
|
|
903
|
+
|
|
849
904
|
# Close all render sessions
|
|
905
|
+
print("Closing app")
|
|
850
906
|
for rid in list(self.render_sessions.keys()):
|
|
851
907
|
self.close_render(rid)
|
|
852
908
|
|
|
@@ -883,7 +939,7 @@ class App:
|
|
|
883
939
|
return # no active render for this user session
|
|
884
940
|
|
|
885
941
|
# We don't want to wait for this to resolve
|
|
886
|
-
create_task(render.call_api("/set-cookies", method="GET"))
|
|
942
|
+
create_task(render.call_api(f"/{self.api_prefix}/set-cookies", method="GET"))
|
|
887
943
|
sess.scheduled_cookie_refresh = True
|
|
888
944
|
|
|
889
945
|
|
|
@@ -85,9 +85,7 @@ export default function PulseLayout() {
|
|
|
85
85
|
const data = useLoaderData<typeof loader>();
|
|
86
86
|
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
87
87
|
sessionStorage.setItem("__PULSE_RENDER_ID", data.renderId);
|
|
88
|
-
|
|
89
|
-
sessionStorage.setItem("__PULSE_DIRECTIVES", JSON.stringify(data.directives));
|
|
90
|
-
}
|
|
88
|
+
sessionStorage.setItem("__PULSE_DIRECTIVES", JSON.stringify(data.directives));
|
|
91
89
|
}
|
|
92
90
|
return (
|
|
93
91
|
<PulseProvider config={config} prerender={data}>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{pulse_framework-0.1.38a6 → pulse_framework-0.1.38a7}/src/pulse/codegen/templates/routes_ts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|