instaui 0.1.1__py3-none-any.whl → 0.1.3__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 (39) hide show
  1. instaui/components/component.py +1 -1
  2. instaui/components/element.py +37 -17
  3. instaui/components/html/checkbox.py +0 -7
  4. instaui/components/html/select.py +1 -1
  5. instaui/components/vfor.py +1 -1
  6. instaui/consts.py +4 -0
  7. instaui/dependencies/component_dependency.py +16 -0
  8. instaui/dependencies/plugin_dependency.py +28 -0
  9. instaui/fastapi_server/debug_mode_router.py +0 -1
  10. instaui/fastapi_server/dependency_router.py +21 -0
  11. instaui/fastapi_server/resource.py +34 -0
  12. instaui/fastapi_server/server.py +147 -95
  13. instaui/html_tools.py +19 -105
  14. instaui/page_info.py +1 -11
  15. instaui/runtime/_app.py +9 -20
  16. instaui/runtime/resource.py +13 -48
  17. instaui/static/insta-ui.esm-browser.prod.js +3663 -3663
  18. instaui/static/insta-ui.ico +0 -0
  19. instaui/static/insta-ui.iife.js +29 -29
  20. instaui/static/templates/debug/sse.html +2 -2
  21. instaui/static/templates/web.html +32 -76
  22. instaui/static/templates/zero.html +48 -32
  23. instaui/systems/file_system.py +3 -14
  24. instaui/template/web_template.py +40 -46
  25. instaui/template/zero_template.py +95 -15
  26. instaui/ui/__init__.py +4 -5
  27. instaui/ui_functions/ui_page.py +3 -18
  28. instaui/vars/path_var.py +2 -1
  29. instaui/zero/func.py +115 -0
  30. instaui/zero/scope.py +12 -1
  31. instaui/zero/test.html +44 -0
  32. {instaui-0.1.1.dist-info → instaui-0.1.3.dist-info}/METADATA +1 -1
  33. {instaui-0.1.1.dist-info → instaui-0.1.3.dist-info}/RECORD +35 -32
  34. instaui/dependencies/__init__.py +0 -15
  35. instaui/dependencies/component_registrar.py +0 -82
  36. instaui/dependencies/installer.py +0 -5
  37. instaui/fastapi_server/config_router.py +0 -60
  38. {instaui-0.1.1.dist-info → instaui-0.1.3.dist-info}/LICENSE +0 -0
  39. {instaui-0.1.1.dist-info → instaui-0.1.3.dist-info}/WHEEL +0 -0
@@ -22,7 +22,7 @@ class Component(Jsonable):
22
22
 
23
23
  self.tag = (
24
24
  "div"
25
- if tag is None
25
+ if tag is None or tag == ""
26
26
  else (
27
27
  tag._to_element_binding_config()
28
28
  if isinstance(tag, ElementBindingMixin)
@@ -13,6 +13,7 @@ from typing import (
13
13
  Optional,
14
14
  Tuple,
15
15
  Union,
16
+ cast,
16
17
  overload,
17
18
  TYPE_CHECKING,
18
19
  )
@@ -21,11 +22,11 @@ from collections import defaultdict
21
22
  from instaui.runtime._app import get_app_slot
22
23
  from instaui.runtime._app import get_current_scope
23
24
  from instaui.vars.element_ref import ElementRef
24
-
25
-
26
25
  from instaui.vars.vfor_item import VForItem
27
26
  from instaui.components.directive import Directive
28
- from instaui.dependencies import ComponentRegistrationInfo, register_component
27
+ from instaui.dependencies.component_dependency import (
28
+ ComponentDependencyInfo,
29
+ )
29
30
  from .slot import SlotManager, Slot
30
31
  from instaui import consts
31
32
  from instaui.components.component import Component
@@ -69,14 +70,14 @@ PROPS_PATTERN = re.compile(
69
70
 
70
71
 
71
72
  class Element(Component):
72
- component: ClassVar[Optional[ComponentRegistrationInfo]] = None
73
+ dependency: ClassVar[Optional[ComponentDependencyInfo]] = None
73
74
  _default_props: ClassVar[Dict[str, Any]] = {}
74
75
  _default_classes: ClassVar[List[str]] = []
75
76
  _default_style: ClassVar[Dict[str, str]] = {}
76
77
 
77
78
  def __init__(self, tag: Optional[Union[str, ElementBindingMixin]] = None):
78
- if self.component:
79
- tag = self.component.name
79
+ if self.dependency:
80
+ tag = self.dependency.tag_name or ""
80
81
 
81
82
  super().__init__(tag)
82
83
 
@@ -101,19 +102,28 @@ class Element(Component):
101
102
  def __init_subclass__(
102
103
  cls,
103
104
  *,
104
- component: Union[str, Path, None] = None,
105
+ esm: Union[str, Path, None] = None,
106
+ externals: Optional[List[Union[str, Path]]] = None,
107
+ css: Union[List[Union[str, Path]], None] = None,
105
108
  ) -> None:
106
109
  super().__init_subclass__()
107
110
 
108
- if component:
109
- if isinstance(component, str):
110
- component = Path(component)
111
- if not component.is_absolute():
112
- component = Path(inspect.getfile(cls)).parent / component
111
+ if esm:
112
+ esm = _make_dependency_path(esm, cls)
113
+
114
+ if externals:
115
+ externals = [_make_dependency_path(e, cls) for e in externals]
116
+
117
+ if css:
118
+ css = [_make_dependency_path(c, cls) for c in css]
113
119
 
114
- # TODO: Lazy load component registration
115
- cls.component = register_component(
116
- component.stem, esm=component, shared=True
120
+ tag_name = f"instaui-{esm.stem}"
121
+
122
+ cls.dependency = ComponentDependencyInfo(
123
+ tag_name=tag_name,
124
+ esm=esm,
125
+ externals=cast(List[Path], externals or []),
126
+ css=cast(List[Path], css or []),
117
127
  )
118
128
 
119
129
  cls._default_props = copy(cls._default_props)
@@ -365,8 +375,8 @@ class Element(Component):
365
375
  if self._directives:
366
376
  data["dir"] = list(self._directives.keys())
367
377
 
368
- if self.component:
369
- get_app_slot().register_component(self.component)
378
+ if self.dependency:
379
+ get_app_slot().use_component_dependency(self.dependency)
370
380
 
371
381
  if self._element_ref:
372
382
  scope = get_current_scope()
@@ -460,3 +470,13 @@ def _classifyBindableDict(
460
470
  value_data[key] = value
461
471
 
462
472
  return value_data, bind_data
473
+
474
+
475
+ def _make_dependency_path(path: Union[str, Path], cls: type):
476
+ if isinstance(path, str):
477
+ path = Path(path)
478
+
479
+ if not path.is_absolute():
480
+ path = Path(inspect.getfile(cls)).parent / path
481
+
482
+ return path
@@ -31,12 +31,5 @@ class Checkbox(InputEventMixin, ValueElement[Union[bool, str]]):
31
31
  if model_value is not None:
32
32
  self.props({"value": model_value})
33
33
 
34
- # def vmodel(
35
- # self,
36
- # value: Any,
37
- # *modifiers: Literal["trim"] | Literal["number"] | Literal["lazy"],
38
- # ):
39
- # return super().vmodel(value, *modifiers) # type: ignore
40
-
41
34
  def _input_event_mixin_element(self) -> Element:
42
35
  return self
@@ -7,10 +7,10 @@ from typing import (
7
7
  List,
8
8
  Literal,
9
9
  Optional,
10
- Self,
11
10
  Union,
12
11
  overload,
13
12
  )
13
+ from typing_extensions import Self
14
14
 
15
15
  from instaui.vars import Ref
16
16
  from instaui.components.value_element import ValueElement
@@ -60,7 +60,7 @@ class VFor(Component, Generic[_T]):
60
60
  def __enter__(self) -> _T:
61
61
  self.__scope = self.__scope_manager.__enter__()
62
62
  super().__enter__()
63
- return VForItem(self).proxy
63
+ return VForItem(self).proxy # type: ignore
64
64
 
65
65
  def __exit__(self, *_) -> None:
66
66
  self.__scope_manager.__exit__(*_)
instaui/consts.py CHANGED
@@ -8,11 +8,15 @@ _STATIC_DIR = _THIS_DIR.joinpath("static")
8
8
  INDEX_TEMPLATE_PATH = _TEMPLATES_DIR.joinpath("index.html")
9
9
  APP_IIFE_JS_PATH = _STATIC_DIR.joinpath("insta-ui.iife.js")
10
10
  APP_ES_JS_PATH = _STATIC_DIR.joinpath("insta-ui.esm-browser.prod.js")
11
+ APP_ES_JS_MAP_PATH = _STATIC_DIR.joinpath("insta-ui.js.map")
11
12
  APP_CSS_PATH = _STATIC_DIR.joinpath("insta-ui.css")
12
13
  VUE_IIFE_JS_PATH = _STATIC_DIR.joinpath("vue.global.prod.js")
13
14
  VUE_ES_JS_PATH = _STATIC_DIR.joinpath("vue.esm-browser.prod.js")
14
15
  VUE_ES_RUNTIME_JS_PATH = _STATIC_DIR.joinpath("vue.runtime.esm-browser.prod.js")
15
16
  TAILWIND_JS_PATH = _STATIC_DIR.joinpath("tailwindcss.min.js")
17
+ FAVICON_PATH = _STATIC_DIR.joinpath("insta-ui.ico")
18
+
19
+ PAGE_TITLE = "insta-ui"
16
20
 
17
21
  _T_App_Mode = Literal["zero", "web", "webview"]
18
22
  TModifier = Literal["trim", "number", "lazy"]
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass, field
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+
6
+ _TTagName = str
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class ComponentDependencyInfo:
11
+ tag_name: _TTagName = field(hash=True)
12
+ esm: Path = field(hash=False)
13
+ externals: Optional[List[Path]] = field(
14
+ default_factory=list, compare=False, hash=False
15
+ )
16
+ css: List[Path] = field(default_factory=list, compare=False, hash=False)
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass, field
3
+ from pathlib import Path
4
+ from typing import List, Optional
5
+ from instaui.runtime._app import get_app_slot
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class PluginDependencyInfo:
10
+ name: str = field(hash=True)
11
+ esm: Path = field(hash=False)
12
+ externals: Optional[List[Path]] = field(
13
+ default_factory=list, compare=False, hash=False
14
+ )
15
+ css: List[Path] = field(default_factory=list, compare=False, hash=False)
16
+
17
+
18
+ def register_plugin(
19
+ name: str,
20
+ esm: Path,
21
+ *,
22
+ externals: Optional[List[Path]] = None,
23
+ css: Optional[List[Path]] = None,
24
+ ):
25
+ info = PluginDependencyInfo(f"plugin/{name}", esm, externals or [], css or [])
26
+
27
+ get_app_slot().use_plugin_dependency(info)
28
+ return info
@@ -24,7 +24,6 @@ async def event_generator(
24
24
  task_event = asyncio.Event()
25
25
  _task_events[connection_id] = task_event
26
26
 
27
- # yield "event: task\ndata: 0 \n\n\n"
28
27
  try:
29
28
  while not task_event.is_set():
30
29
  if await request.is_disconnected():
@@ -0,0 +1,21 @@
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import FileResponse
3
+
4
+ from instaui.fastapi_server import resource
5
+
6
+
7
+ URL = f"{resource.URL}/{{hash_part:path}}"
8
+
9
+
10
+ def create_router(app: FastAPI):
11
+ _dependency_handler(app)
12
+
13
+
14
+ def _dependency_handler(app: FastAPI):
15
+ @app.get(URL)
16
+ def _(hash_part: str) -> FileResponse:
17
+ local_file = resource.get_by_hash(hash_part)
18
+
19
+ return FileResponse(
20
+ local_file, headers={"Cache-Control": "public, max-age=3600"}
21
+ )
@@ -0,0 +1,34 @@
1
+ from pathlib import Path
2
+ from typing import Dict
3
+ from instaui.systems import file_system
4
+ from instaui.version import __version__ as _INSTA_VERSION
5
+
6
+ URL = f"/_instaui_{_INSTA_VERSION}/resource"
7
+ _THashPart = str
8
+ _HASH_PART_MAP: Dict[_THashPart, Path] = {}
9
+ _FILE_URL_MAP: Dict[Path, _THashPart] = {}
10
+
11
+
12
+ def get_by_hash(hash_part: str) -> Path:
13
+ return _HASH_PART_MAP[hash_part]
14
+
15
+
16
+ def record_resource(path: Path):
17
+ if path in _FILE_URL_MAP:
18
+ return _FILE_URL_MAP[path]
19
+
20
+ hash_part = _generate_hash_part(path)
21
+ _HASH_PART_MAP[hash_part] = path
22
+ url = f"{URL}/{hash_part}"
23
+ _FILE_URL_MAP[path] = url
24
+ return url
25
+
26
+
27
+ def _generate_hash_part(path: Path):
28
+ path = Path(path).resolve()
29
+ is_file = path.is_file()
30
+
31
+ if is_file:
32
+ return f"{file_system.generate_hash_name_from_path(path.parent)}/{path.name}"
33
+
34
+ return file_system.generate_hash_name_from_path(path)
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+ from contextlib import contextmanager
2
3
  import inspect
3
4
  import os
4
5
  import multiprocessing
@@ -8,30 +9,44 @@ import __main__
8
9
 
9
10
  from fastapi import FastAPI
10
11
  from fastapi import Request
11
- from fastapi.responses import FileResponse, HTMLResponse
12
12
  from fastapi.staticfiles import StaticFiles
13
+
14
+ from fastapi.responses import HTMLResponse
13
15
  import uvicorn
14
16
  from uvicorn.supervisors import ChangeReload
17
+ import itertools
15
18
 
16
- from instaui.html_tools import to_json
19
+ from instaui.html_tools import to_config_data
17
20
  from instaui.launch_collector import get_launch_collector
18
21
  from instaui.page_info import PageInfo
19
- from instaui.handlers import config_handler
20
- from instaui.systems import file_system
22
+
21
23
  from instaui import consts
22
- from instaui.runtime._app import get_app_slot
24
+ from instaui.runtime._app import get_app_slot, get_default_app_slot
25
+ from instaui.runtime.dataclass import JsLink, VueAppComponent
23
26
  from instaui.template import web_template
24
- from . import config_router
27
+
28
+
29
+ from . import dependency_router
25
30
  from . import event_router
26
31
  from . import watch_router
27
32
  from . import debug_mode_router
28
33
  from .middlewares import RequestContextMiddleware
29
34
  from ._uvicorn import UvicornServer
30
-
35
+ from . import resource
36
+ from instaui.version import __version__ as _INSTA_VERSION
31
37
 
32
38
  APP_IMPORT_STRING = "instaui.fastapi_server.server:Server._instance.app"
33
39
 
34
40
 
41
+ INSTAUI_STATIC_URL = f"/_instaui_{_INSTA_VERSION}/static"
42
+
43
+ VUE_JS_HASH_LINK = f"{INSTAUI_STATIC_URL}/{consts.VUE_ES_JS_PATH.name}"
44
+ INSTAUI_JS_HASH_LINK = f"{INSTAUI_STATIC_URL}/{consts.APP_ES_JS_PATH.name}"
45
+ APP_CSS_LINK = f"{INSTAUI_STATIC_URL}/{consts.APP_CSS_PATH.name}"
46
+ TAILWIND_JS_HASH_LINK = f"{INSTAUI_STATIC_URL}/{consts.TAILWIND_JS_PATH.name}"
47
+ FAVICON_LINK = f"{INSTAUI_STATIC_URL}/{consts.FAVICON_PATH.name}"
48
+
49
+
35
50
  class Server:
36
51
  _instance: Optional[Server] = None
37
52
 
@@ -44,12 +59,12 @@ class Server:
44
59
  def __init__(self):
45
60
  self.app = FastAPI()
46
61
  self.app.add_middleware(RequestContextMiddleware)
47
- config_router.create_router(self.app)
62
+ dependency_router.create_router(self.app)
48
63
  event_router.create_router(self.app)
49
64
  watch_router.create_router(self.app)
50
65
  debug_mode_router.create_router(self.app)
51
66
 
52
- self._static_dir_url = _add_static_dir(self.app)
67
+ self.add_instaui_static(self.app)
53
68
 
54
69
  for page_info in get_launch_collector()._page_router.values():
55
70
  self.register_page(page_info)
@@ -61,125 +76,145 @@ class Server:
61
76
 
62
77
  self._remove_route(info.path)
63
78
 
64
- key = info.create_key()
65
- config_handler.register_handler(key, info.func)
66
- config_fetch_url = (
67
- config_handler.ASYNC_URL if is_async else config_handler.SYNC_URL
68
- )
79
+ if is_async:
69
80
 
70
- @self.app.get(info.path)
71
- def wrapper(request: Request):
72
- page_loadding_json = None
73
- if info.page_loading:
74
- loadding_result = info.page_loading()
75
- if loadding_result:
76
- return loadding_result
77
- page_loadding_json = to_json()
78
-
79
- html = self._to_web_html(
80
- page_info=info,
81
- config_fetch_url=config_fetch_url,
82
- config_fetch_key=key,
83
- query_path=info.path,
84
- request=request,
85
- page_loadding_json=page_loadding_json,
86
- )
87
- response = HTMLResponse(html)
88
- return response
81
+ @self.app.get(info.path)
82
+ async def _(request: Request):
83
+ self._update_page_info(request, info)
84
+ with _execute_request_lifespans():
85
+ await info.func()
86
+ html = self._to_web_html(
87
+ page_info=info,
88
+ request=request,
89
+ )
90
+
91
+ return HTMLResponse(html)
92
+
93
+ else:
94
+
95
+ @self.app.get(info.path)
96
+ def _(request: Request):
97
+ self._update_page_info(request, info)
98
+ with _execute_request_lifespans():
99
+ info.func()
100
+ html = self._to_web_html(
101
+ page_info=info,
102
+ request=request,
103
+ )
89
104
 
90
- return wrapper
105
+ return HTMLResponse(html)
91
106
 
92
107
  def _to_web_html(
93
108
  self,
94
109
  *,
95
110
  page_info: PageInfo,
96
- query_path: str,
97
- config_json: Optional[str] = None,
98
- config_fetch_url: Optional[str] = None,
99
- config_fetch_key: Optional[str] = None,
100
- page_loadding_json: Optional[str] = None,
101
111
  request: Request,
102
112
  ):
113
+ config_data = to_config_data()
114
+
103
115
  system_slot = get_app_slot()
116
+ default_app_slot = get_default_app_slot()
104
117
  html_resource = system_slot._html_resource
105
- page_info.apply_settings(html_resource)
106
-
107
- html_resource.add_import_map(
108
- "vue", self._static_dir_url + f"/{consts.VUE_ES_JS_PATH.name}"
109
- )
118
+ default_html_resource = default_app_slot._html_resource
110
119
 
111
- html_resource.add_import_map(
112
- "instaui", self._static_dir_url + f"/{consts.APP_ES_JS_PATH.name}"
120
+ favicon_url = FAVICON_LINK
121
+ if html_resource.favicon:
122
+ favicon_url = resource.record_resource(html_resource.favicon)
123
+ else:
124
+ if default_html_resource.favicon:
125
+ favicon_url = resource.record_resource(default_html_resource.favicon)
126
+
127
+ model = web_template.WebTemplateModel(
128
+ vue_js_link=VUE_JS_HASH_LINK,
129
+ instaui_js_link=INSTAUI_JS_HASH_LINK,
130
+ css_links=[
131
+ APP_CSS_LINK,
132
+ ],
133
+ config_dict=config_data,
134
+ favicon_url=favicon_url,
135
+ title=html_resource.title
136
+ or default_html_resource.title
137
+ or consts.PAGE_TITLE,
113
138
  )
114
- html_resource.add_css_link(consts.APP_CSS_PATH)
115
139
 
116
- if html_resource.use_tailwind:
117
- tailwind_url = self._static_dir_url + f"/{consts.TAILWIND_JS_PATH.name}"
118
- html_resource.add_js_link(tailwind_url)
140
+ if html_resource.use_tailwind is None:
141
+ if default_html_resource.use_tailwind:
142
+ model.js_links.append(JsLink(TAILWIND_JS_HASH_LINK))
143
+ else:
144
+ if html_resource.use_tailwind:
145
+ model.js_links.append(JsLink(TAILWIND_JS_HASH_LINK))
119
146
 
120
147
  # register custom components
121
- # TODO: use one get api to get all components
122
- for component in system_slot._js_components:
148
+ for component in system_slot._component_dependencies:
123
149
  if not component.esm:
124
150
  continue
125
- url = self.add_static_file_route(component.esm)
126
- html_resource.add_vue_app_component(name=component.name, url=url)
151
+
152
+ model.vue_app_component.append(
153
+ VueAppComponent(
154
+ name=component.tag_name,
155
+ url=resource.record_resource(component.esm),
156
+ )
157
+ )
127
158
 
128
159
  if component.css:
129
160
  for css_link in component.css:
130
- html_resource.add_css_link(css_link)
161
+ model.css_links.append(resource.record_resource(css_link))
131
162
 
132
163
  # register custom plugins
133
- for plugin in system_slot._plugins:
164
+ for plugin in set(
165
+ itertools.chain(
166
+ system_slot._plugin_dependencies, default_app_slot._plugin_dependencies
167
+ )
168
+ ):
134
169
  if not plugin.esm:
135
170
  continue
136
- url = self.add_static_file_route(plugin.esm)
137
- html_resource.add_vue_app_use(url)
171
+
172
+ model.vue_app_use.append(plugin.name)
173
+
174
+ model.add_extra_import_map(
175
+ plugin.name, resource.record_resource(plugin.esm)
176
+ )
138
177
 
139
178
  if plugin.css:
140
179
  for css_link in plugin.css:
141
- html_resource.add_css_link(css_link)
180
+ model.css_links.append(resource.record_resource(css_link))
142
181
 
143
182
  # css file link to web static link
144
- html_resource._css_links = {
145
- self.add_static_file_route(link) if isinstance(link, Path) else link: None
146
- for link, attrs in html_resource._css_links.items()
147
- }
183
+ for link, attrs in itertools.chain(
184
+ html_resource._css_links.items(), default_html_resource._css_links.items()
185
+ ):
186
+ if isinstance(link, Path):
187
+ model.css_links.append(resource.record_resource(link))
148
188
 
149
189
  # js file link to web static link
150
- for info in html_resource._js_links:
190
+ for info in itertools.chain(
191
+ html_resource._js_links, default_html_resource._js_links
192
+ ):
151
193
  if isinstance(info.link, Path):
152
- info.link = self.add_static_file_route(info.link)
194
+ model.js_links.append(JsLink((resource.record_resource(info.link))))
195
+
196
+ for js_code in itertools.chain(
197
+ html_resource._script_tags, default_html_resource._script_tags
198
+ ):
199
+ model.script_tags.append(js_code)
200
+
201
+ for sylte_code in itertools.chain(
202
+ html_resource._style_tags, default_html_resource._style_tags
203
+ ):
204
+ model.style_tags.append(sylte_code)
153
205
 
154
- prefix = request.headers.get(
206
+ model.prefix = request.headers.get(
155
207
  "X-Forwarded-Prefix", request.scope.get("root_path", "")
156
208
  )
157
209
 
158
- result = web_template.render_web_html(
159
- config_json=config_json,
160
- config_fetch_url=config_fetch_url,
161
- config_fetch_key=config_fetch_key,
162
- query_path_params=str(request.path_params),
163
- query_params=dict(request.query_params),
164
- query_path=query_path,
165
- page_loadding_json=page_loadding_json,
166
- prefix=prefix,
167
- )
168
- get_app_slot().reset_html_resource()
169
- return result
170
-
171
- def add_static_file_route(self, local_file: Path) -> str:
172
- path = file_system.generate_static_url_from_file_path(local_file)
173
- if path in self._registered_static_routes:
174
- return path
175
-
176
- @self.app.get(path)
177
- def _() -> FileResponse:
178
- return FileResponse(
179
- local_file, headers={"Cache-Control": "public, max-age=3600"}
180
- )
210
+ return web_template.render_web_html(model)
211
+
212
+ def _update_page_info(self, request: Request, page_info: PageInfo):
213
+ app = get_app_slot()
181
214
 
182
- return path
215
+ app._page_path = page_info.path
216
+ app._page_params = request.path_params
217
+ app._query_params = dict(request.query_params)
183
218
 
184
219
  def _remove_route(self, path: str) -> None:
185
220
  self.app.routes[:] = [
@@ -235,12 +270,29 @@ class Server:
235
270
  def run_with(self, app):
236
271
  assert isinstance(app, FastAPI), "app must be a FastAPI instance"
237
272
 
238
-
239
- def _add_static_dir(app: FastAPI):
240
- url = file_system.generate_static_url_from_file_path(consts._STATIC_DIR)
241
- app.mount(url, StaticFiles(directory=consts._STATIC_DIR))
242
- return url
273
+ @staticmethod
274
+ def add_instaui_static(app: FastAPI):
275
+ app.mount(
276
+ INSTAUI_STATIC_URL,
277
+ StaticFiles(directory=consts._STATIC_DIR),
278
+ name=INSTAUI_STATIC_URL,
279
+ )
243
280
 
244
281
 
245
282
  def _split_args(args: str):
246
283
  return [a.strip() for a in args.split(",")]
284
+
285
+
286
+ @contextmanager
287
+ def _execute_request_lifespans():
288
+ events = [iter(event()) for event in get_launch_collector().page_request_lifespans]
289
+ for event in events:
290
+ next(event)
291
+
292
+ yield
293
+
294
+ for event in events:
295
+ try:
296
+ next(event)
297
+ except StopIteration:
298
+ pass