"""Quart app factory.""" import logging from pathlib import Path from quart import Quart from .api import all_blueprints from .config import get_config from .frontend import frontend_bp from .services.credential_crypto import CredentialCrypto _CREDENTIAL_KEY_PATH = Path("/images/secrets/credential_key.b64") def create_app() -> Quart: cfg = get_config() logging.basicConfig(level=cfg.log_level) # Bootstrap the credential encryption key file (mode 0600) before # any request can land. FC-3b: file-based system-generated key. CredentialCrypto(_CREDENTIAL_KEY_PATH) app = Quart(__name__) app.secret_key = cfg.secret_key # FC-5: legacy IR ingest JSON can run to tens of MB (hundreds of # thousands of image_tag_associations). Werkzeug's default form # memory cap is 500KB; raise both ceilings so the multipart upload # for /api/migrate/ir_ingest doesn't 413. app.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 1024 # 1 GB app.config["MAX_FORM_MEMORY_SIZE"] = 1024 * 1024 * 1024 # 1 GB for bp in all_blueprints(): app.register_blueprint(bp) # Registered last so /api/* routes win over the SPA catch-all. app.register_blueprint(frontend_bp) @app.after_serving async def _dispose_db_engine() -> None: from .extensions import dispose_engine await dispose_engine() return app