"""User accounts + persistent per-user chat history for AgAdvisor. Self-contained package so it can be unit-tested without Streamlit, Hugging Face, or the RAG stack: - ``store`` — SQLite schema + user-scoped CRUD (users, chats, messages, usage) - ``auth`` — bcrypt password hashing, signup/login, brute-force lockout - ``session`` — HMAC-signed session tokens for cookie-based "stay logged in" - ``hf_sync`` — mirror the SQLite DB to a private Hugging Face Dataset (durable storage on ephemeral Spaces); no-ops locally when no token is set - ``ui`` — Streamlit login/sign-up gate (imported lazily; needs streamlit) Submodules are imported lazily via ``__getattr__`` so that using only ``store`` or ``session`` does not pull in optional deps (``bcrypt``) that ``auth`` needs. """ from __future__ import annotations import importlib from typing import Any __all__ = [ "AccountStore", "DuplicateUserError", "AuthError", "signup", "login", "hash_password", "verify_password", "issue_token", "validate_token", ] _EXPORTS = { "AccountStore": ("store", "AccountStore"), "DuplicateUserError": ("store", "DuplicateUserError"), "AuthError": ("auth", "AuthError"), "signup": ("auth", "signup"), "login": ("auth", "login"), "hash_password": ("auth", "hash_password"), "verify_password": ("auth", "verify_password"), "issue_token": ("session", "issue_token"), "validate_token": ("session", "validate_token"), } def __getattr__(name: str) -> Any: # PEP 562 lazy attribute access if name in _EXPORTS: module_name, attr = _EXPORTS[name] module = importlib.import_module(f"{__name__}.{module_name}") return getattr(module, attr) raise AttributeError(f"module {__name__!r} has no attribute {name!r}")