import logging from importlib.resources import files from pathlib import Path from typing import Optional, Any import fasthtml.fastapp from fasthtml.components import Link, Script from starlette.responses import Response from myfasthtml.auth.routes import setup_auth_routes from myfasthtml.auth.utils import create_auth_beforeware from myfasthtml.core.AuthProxy import AuthProxy from myfasthtml.core.instances import RootInstance from myfasthtml.core.utils import utils_app logger = logging.getLogger("MyFastHtml") def get_asset_path(filename): """Get asset file path""" return files("myfasthtml") / "assets" / filename # Get assets directory path assets_path = files("myfasthtml") / "assets" assets_dir = Path(str(assets_path)) def get_asset_content(filename): """Get asset file content""" return get_asset_path(filename).read_text() def create_app(daisyui: Optional[bool] = True, vis: Optional[bool] = True, protect_routes: Optional[bool] = True, mount_auth_app: Optional[bool] = False, base_url: Optional[str] = None, **kwargs) -> Any: """ Creates and configures a FastHtml application with optional support for daisyUI themes and authentication routes. :param daisyui: Flag to enable or disable inclusion of daisyUI-related assets for styling. Defaults to False. :param protect_routes: Flag to enable or disable routes protection based on authentication. Defaults to True. :param mount_auth_app: Flag to enable or disable mounting of authentication routes. Defaults to False. :param base_url: Url to use for the application (used by the auth APIs) :param kwargs: Arbitrary keyword arguments forwarded to the application initialization logic. :return: A tuple containing the FastHtml application instance and the associated router. :rtype: Any """ hdrs = [ Link(href="/myfasthtml/myfasthtml.css", rel="stylesheet", type="text/css"), Script(src="/myfasthtml/myfasthtml.js"), ] if daisyui: hdrs += [ Link(href="/myfasthtml/daisyui-5.css", rel="stylesheet", type="text/css"), Link(href="/myfasthtml/daisyui-5-themes.css", rel="stylesheet", type="text/css"), Script(src="/myfasthtml/tailwindcss-browser@4.js"), ] if vis: hdrs += [ Script(src="/myfasthtml/vis-network.min.js"), ] beforeware = create_auth_beforeware() if protect_routes else None app, rt = fasthtml.fastapp.fast_app(before=beforeware, hdrs=tuple(hdrs), **kwargs) # remove the global static files routes original_routes = app.routes[:] app.routes.clear() # Serve assets @app.get("/myfasthtml/{filename:path}.{ext:static}") def serve_assets(filename: str, ext: str): path = filename + "." + ext try: content = get_asset_content(path) if filename.endswith('.css'): return Response(content, media_type="text/css") elif filename.endswith('.js'): return Response(content, media_type="application/javascript") else: return Response(content) except Exception as e: return Response(f"Asset not found: {path}", status_code=404) # and put it back after the myfasthtml static files routes for r in original_routes: app.routes.append(r) # route the commands and the bindings app.mount("/myfasthtml", utils_app) if mount_auth_app: # Setup authentication routes setup_auth_routes(app, rt, base_url=base_url) # create the AuthProxy instance AuthProxy(RootInstance, base_url) # using the auto register mechanism to expose it return app, rt