# ai_mouse/server/deps.py """Shared dependencies for the ai-mouse server package.""" from __future__ import annotations import logging from dataclasses import dataclass, field from pathlib import Path from typing import Optional logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # Data directory # --------------------------------------------------------------------------- _HERE = Path(__file__).resolve().parent _DATA_DIR = _HERE.parent.parent / "data" def get_data_dir() -> Path: """Return the resolved data directory (sites/ai_mouse/data/).""" return _DATA_DIR def validate_path(path: Path, base: Path) -> Path: """Resolve *path* and ensure it lives under *base*. Raises ValueError on traversal.""" resolved = path.resolve() base_resolved = base.resolve() if not str(resolved).startswith(str(base_resolved)): raise ValueError(f"Path traversal detected: {path}") return resolved # --------------------------------------------------------------------------- # Session state # --------------------------------------------------------------------------- @dataclass class SessionState: """Mutable singleton holding collectors initialised at runtime.""" collector: Optional[object] = field(default=None) scroll_collector: Optional[object] = field(default=None) _state = SessionState() def get_state() -> SessionState: """Return the module-level session state singleton.""" return _state