strict base64 encode and decode helpers

Python
"""Encode and decode base64 text or bytes with strict, explainable errors."""
import base64
import binascii


def encode(data: str | bytes, *, encoding: str = "utf-8", urlsafe: bool = False) -> str:
    """Return ASCII base64 for text (UTF-8 default) or raw bytes."""
    raw = data.encode(encoding) if isinstance(data, str) else bytes(data)
    encoded = base64.urlsafe_b64encode(raw) if urlsafe else base64.b64encode(raw)
    return encoded.decode("ascii")


def decode(value: str, *, urlsafe: bool = False) -> bytes:
    """Decode base64, ignoring whitespace and restoring missing padding."""
    cleaned = "".join(value.split())
    if not cleaned:
        raise ValueError("base64 input is empty")
    if urlsafe:
        cleaned = cleaned.translate(str.maketrans("-_", "+/"))
    cleaned += "=" * (-len(cleaned) % 4)
    try:
        return base64.b64decode(cleaned, validate=True)
    except (binascii.Error, ValueError) as exc:
        raise ValueError(f"invalid base64 input: {exc}") from exc


def decode_text(value: str, *, encoding: str = "utf-8") -> str:
    """Decode base64 to text, reporting when the bytes are not valid text."""
    try:
        return decode(value).decode(encoding)
    except UnicodeDecodeError as exc:
        raise ValueError(f"payload is not valid {encoding}") from exc


if __name__ == "__main__":
    token = encode("hello bits", urlsafe=True)
    print(token, decode_text(token))  # aGVsbG8gYml0cw== hello bits
    print(decode_text(encode("café")))  # café