"""Ports — the contracts the application layer depends on. These are Protocols, not implementations. Concrete adapters live in ``app.infrastructure`` (repositories) and ``app.core.security`` (crypto) and are bound to these ports at the composition root (``app.api.deps``). """ import datetime as dt import uuid from typing import Protocol from app.domain.entities import Credentials, User from app.domain.tokens import IssuedToken, TokenClaims, TokenType class UserRepository(Protocol): async def get_by_id(self, user_id: uuid.UUID) -> User | None: ... async def get_credentials_by_username(self, username: str) -> Credentials | None: ... async def add(self, *, username: str, password_hash: str, is_superuser: bool) -> User: ... async def list(self, *, limit: int, offset: int) -> list[User]: ... async def set_password_hash(self, user_id: uuid.UUID, password_hash: str) -> None: ... async def set_superuser(self, user_id: uuid.UUID, is_superuser: bool) -> User: ... async def set_active(self, user_id: uuid.UUID, is_active: bool) -> User: ... async def count(self) -> int: ... class RefreshTokenRepository(Protocol): async def add( self, *, jti: uuid.UUID, user_id: uuid.UUID, token_hash: str, expires_at: dt.datetime, ) -> None: ... async def is_valid(self, jti: uuid.UUID) -> bool: """True iff a row exists for ``jti`` that is neither revoked nor expired.""" ... async def revoke(self, jti: uuid.UUID) -> None: ... async def revoke_all_for_user(self, user_id: uuid.UUID) -> None: ... class PasswordHasher(Protocol): def hash(self, password: str) -> str: ... def verify_and_update(self, password: str, password_hash: str) -> tuple[bool, str | None]: """Verify ``password`` against ``password_hash``. Returns ``(is_valid, updated_hash)`` where ``updated_hash`` is a fresh hash to persist when the stored one uses outdated parameters, else ``None``.""" ... class TokenService(Protocol): def issue(self, *, subject: uuid.UUID, token_type: TokenType) -> IssuedToken: ... def decode(self, encoded: str) -> TokenClaims: """Verify signature + expiry and return claims. Raises :class:`~app.domain.errors.AuthenticationError` on any failure.""" ...