The claim-checked record that flows through every layer.
The envelope is the only thing components share. Compaction, dispatch, and the dashboard read committed envelopes from the store; they never call the edge.
body is the exact raw bytes as received — signature checks need it verbatim.
Keep it as a refcounted binary and pass it by reference.
Summary
Functions
Inverse of to_binary/1,2: reads the unprefixed legacy form (v0) and v1.
Fetch the first value of a request header (case-insensitive).
header/2 for a name that is already lowercase (String.downcase/1): a
compiled signature template, a dedupe or ordering spec, which lower the name
once when they are built, not on every request.
The tenant-scoped key a consumer dedupes this hook on; see docs/delivery.md.
Serialize an envelope to a compact binary for the store.
Types
@type t() :: %Ankusa.Envelope{ body: binary(), content_type: String.t() | nil, dedupe_key: String.t() | nil, headers: [{String.t(), String.t()}], id: String.t(), method: String.t(), path: String.t(), received_at: integer(), seq: non_neg_integer() | nil, size: non_neg_integer(), source_id: String.t(), tenant_id: String.t() | nil, trace: Ankusa.Trace.t() | nil, verification: Ankusa.Verification.t() | nil }
Functions
Inverse of to_binary/1,2: reads the unprefixed legacy form (v0) and v1.
Keys the struct does not know (a field added by a newer node) are ignored,
so a row written by N+1 decodes on N. A version this node does not know is
{:error, :unsupported_envelope_version}; bytes that are no envelope at all
are {:error, :undecodable}. Never raises: callers dead-letter or log.
Fetch the first value of a request header (case-insensitive).
header/2 for a name that is already lowercase (String.downcase/1): a
compiled signature template, a dedupe or ordering spec, which lower the name
once when they are built, not on every request.
The tenant-scoped key a consumer dedupes this hook on; see docs/delivery.md.
Serialize an envelope to a compact binary for the store.
body is kept verbatim; the term is :erlang.term_to_binary/2 with
:deterministic so re-encoding a replayed record is byte-stable.
Versions
0(default): the bare term, as every release up to 0.6 wrote it.1(version: 1):<<"AE", 1, term::binary>>. Nothing writes it by default yet: this release reads both, the next one flips the default, so a rollback from this release to the previous one still reads every row it wrote (seedocs/deployment.md, "Rolling back a minor").