from __future__ import annotations import os import path_setup # noqa: F401 from bp import register_pages from services import register_domain_services SX_STANDALONE = os.getenv("SX_STANDALONE") == "true" async def sx_docs_context() -> dict: """SX docs app context processor — fetches cross-service fragments.""" from quart import request, g from shared.infrastructure.context import base_context from shared.infrastructure.cart_identity import current_cart_identity from shared.infrastructure.fragments import fetch_fragments ctx = await base_context() ctx["menu_items"] = [] ident = current_cart_identity() user = getattr(g, "user", None) cart_params = {} if ident.get("user_id"): cart_params["user_id"] = ident["user_id"] if ident.get("session_id"): cart_params["session_id"] = ident["session_id"] auth_params = {"email": user.email} if user else None cart_mini, auth_menu, nav_tree = await fetch_fragments([ ("cart", "cart-mini", cart_params or None), ("account", "auth-menu", auth_params), ("blog", "nav-tree", {"app_name": "sx", "path": request.path}), ], required=False) ctx["cart_mini"] = cart_mini ctx["auth_menu"] = auth_menu ctx["nav_tree"] = nav_tree return ctx async def sx_standalone_context() -> dict: """Minimal context for standalone mode — no cross-service fragments.""" from shared.infrastructure.context import base_context ctx = await base_context() ctx["menu_items"] = [] ctx["cart_mini"] = "" ctx["auth_menu"] = "" ctx["nav_tree"] = "" return ctx def create_app() -> "Quart": from shared.infrastructure.factory import create_base_app extra_kw = {} if SX_STANDALONE: extra_kw["no_oauth"] = True extra_kw["no_db"] = True app = create_base_app( "sx", context_fn=sx_standalone_context if SX_STANDALONE else sx_docs_context, domain_services_fn=register_domain_services, **extra_kw, ) # Minimal shell — no Prism, no SweetAlert, no body.js # sx docs uses custom highlight.py, not Prism; body.js is for legacy apps app.config["SX_SHELL"] = { "head_scripts": [], # no CDN scripts "body_scripts": [], # no body.js "inline_head_js": "", # no pre-boot JS (hover-capable, close-details unused) "inline_css": ( ".sx-indicator{display:none}" ".sx-request .sx-indicator{display:inline-flex}" "@keyframes sxJiggle{0%,100%{transform:translateX(0)}" "25%{transform:translateX(-.5px)}75%{transform:translateX(.5px)}}" "a.sx-request{animation:sxJiggle .3s ease-in-out infinite}" ), # Nav link aria-selected update on client-side routing — pure SX "init_sx": ( '(dom-listen (dom-body) "sx:clientRoute"' ' (fn (e)' ' (let ((p (get (event-detail e) "pathname")))' ' (when p' ' (for-each' ' (fn (a) (dom-set-attr a "aria-selected" "false"))' ' (dom-query-all "nav a[aria-selected]"))' ' (for-each' ' (fn (a) (dom-set-attr a "aria-selected" "true"))' ' (dom-query-all (str "nav a[href=\\"" p "\\"]")))))))' ), } app.url_map.strict_slashes = False from sxc.pages import setup_sx_pages setup_sx_pages() bp = register_pages(url_prefix="/") app.register_blueprint(bp) from shared.sx.pages import auto_mount_pages auto_mount_pages(app, "sx") @app.before_request async def trailing_slash_redirect(): from quart import request, redirect path = request.path if (path != "/" and not path.endswith("/") and request.method == "GET" and not path.startswith(("/static/", "/internal/", "/auth/")) and "/api/" not in path and "." not in path.rsplit("/", 1)[-1]): qs = request.query_string.decode() target = path + "/" + ("?" + qs if qs else "") return redirect(target, 301) @app.errorhandler(404) async def sx_not_found(e): from quart import request, make_response from shared.browser.app.utils.htmx import is_htmx_request from shared.sx.jinja_bridge import get_component_env, _get_request_context from shared.sx.async_eval import async_eval_slot_to_sx from shared.sx.types import Symbol, Keyword from shared.sx.helpers import full_page_sx, oob_page_sx, sx_response from shared.sx.pages import get_page_helpers from shared.sx.page import get_template_context path = request.path content_ast = [ Symbol("~sx-doc"), Keyword("path"), path, [Symbol("~not-found-content"), Keyword("path"), path], ] env = dict(get_component_env()) env.update(get_page_helpers("sx")) ctx = _get_request_context() try: content_sx = await async_eval_slot_to_sx(content_ast, env, ctx) except Exception: from shared.browser.app.errors import _sx_error_page html = _sx_error_page("404", "NOT FOUND", image="/static/errors/404.gif") return await make_response(html, 404) if is_htmx_request(): return sx_response( await oob_page_sx(content=content_sx), status=404, ) else: tctx = await get_template_context() html = await full_page_sx(tctx, header_rows="", content=content_sx) return await make_response(html, 404) return app app = create_app()