22d738fc74
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
"""accounts — domain exceptions.
|
|
|
|
Raised by the service layer; the BFF maps each to the §6.4 error shape. Keeping them here
|
|
(not in main) keeps the rules in the domain (INV-6).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
|
|
class AccountsError(Exception):
|
|
"""Base for accounts-domain errors."""
|
|
|
|
|
|
class InvalidEmail(AccountsError):
|
|
"""The supplied email is not a plausible address (§6.4 400 invalid_email)."""
|
|
|
|
|
|
class ResendCooldown(AccountsError):
|
|
"""A code was issued for this email under 60s ago (INV-3 → §6.4 429 resend_cooldown)."""
|
|
|
|
def __init__(self, retry_after_s: int) -> None:
|
|
super().__init__(f"resend available in {retry_after_s}s")
|
|
self.retry_after_s = retry_after_s
|
|
|
|
|
|
class CodeMismatch(AccountsError):
|
|
"""The submitted code is wrong (PUC-2a → §6.4 400 code_mismatch)."""
|
|
|
|
def __init__(self, attempts_remaining: int) -> None:
|
|
super().__init__("code did not match")
|
|
self.attempts_remaining = attempts_remaining
|
|
|
|
|
|
class CodeExpired(AccountsError):
|
|
"""No live code for this email — expired, consumed, or never issued (§6.4 400 code_expired)."""
|
|
|
|
|
|
class CodeExhausted(AccountsError):
|
|
"""The code's attempt budget is spent; it is invalidated (INV-3 → §6.4 400 code_exhausted)."""
|
|
|
|
|
|
class DeliveryFailed(AccountsError):
|
|
"""The relay refused the code email; nothing was committed (INV-9 → §6.4 502 delivery_failed)."""
|