"""Bucket-identity alias for the per-profile storage container.The bucket is the per-profile persistence container that sits above anysingle record domain. Every record-owning domain (transactions,invoices, attachments, modelo records) and every persistence adapterthat materialises those records consumes a bucket identity at itsboundary; promoting the :data:`BucketId` alias to :mod:`core.identity` lets eachconsumer import it without crossing a sibling-domain boundary.The constraint shape — ``min_length=1``, ``max_length=128``, surroundingwhitespace stripped — pins the bucket identity at the pydantic boundaryso a malformed value is rejected on construction rather than leakinginto persisted records or wire payloads."""from__future__importannotationsfromtypingimportAnnotatedfrompydanticimportStringConstraints,TypeAdapter,ValidationErrorBucketId=Annotated[str,StringConstraints(strip_whitespace=True,min_length=1,max_length=128),]"""Bucket identity (profile UUID or a system-scoped sentinel)."""_BUCKET_ID_ADAPTER:TypeAdapter[str]=TypeAdapter(BucketId)
[docs]defcanonical_bucket_id(bucket_id:str)->str:"""Return the canonical spelling of ``bucket_id``. The alias above states what a bucket identity IS; this states it for a value that has not passed a pydantic boundary. Callers that key a cryptographic or persisted address on a bucket need the same answer the storage layer would give, and computing it from a raw string is where the two drift apart: a value the storage layer would refuse outright (blank, or overlength) still produces a usable key, and a whitespace-wrapped spelling of a VALID id yields a different address than its canonical spelling -- two buckets to the address, one bucket to every other layer. It lives here, beside the alias it defers to, because the rule has no owner otherwise: it was previously defined in the storage master-key package with no consumer at all, while four separate call sites each kept a private copy of it. A shared rule with four copies and no canonical home is the shape that lets the copies diverge silently. Args: bucket_id: A bucket identity as supplied by a caller, in any spelling. Returns: The value normalized through :data:`BucketId`, so two spellings of one bucket compose byte-identical addresses and associated data. Raises: ValueError: When the value is not a valid bucket identity. Deliberately the plain builtin: each caller translates it into its own typed refusal, so the shared helper does not impose one surface's error class on every other. """try:return_BUCKET_ID_ADAPTER.validate_python(bucket_id)exceptValidationErrorasexc:raiseValueError("bucket_id is not a canonical bucket identity")fromexc