Exosphere.ATProto.CBOR (Exosphere v0.6.0)

Copy Markdown View Source

DAG-CBOR encoding and decoding with Exosphere.ATProto normalization.

DAG-CBOR is a restricted subset of CBOR used for content-addressed data. This module wraps the :cbor library with Exosphere.ATProto-specific handling for:

  • CID links (CBOR tag 42, encoded as byte strings)
  • Canonical map key ordering (RFC 8949 length-first: shorter keys first, ties broken bytewise)
  • No floating point numbers (Exosphere.ATProto disallows floats)
  • Bytes and link representation

Examples

iex> Exosphere.ATProto.CBOR.encode(%{"hello" => "world"})
{:ok, <<...>>}

iex> Exosphere.ATProto.CBOR.decode(cbor_bytes)
{:ok, %{"hello" => "world"}}

CID links are encoded with CBOR tag 42 and decoded as Exosphere.ATProto.CID structs:

iex> cid = Exosphere.ATProto.CID.decode!("bafyreidykglsfhoixmivffc5uwhcgshx4j465xwqntbmu43nb2dzqwfvae")
iex> Exosphere.ATProto.CBOR.encode(%{"ref" => cid})
{:ok, <<...>>}  # Contains tag 42 with CID bytes

Summary

Functions

Decode DAG-CBOR binary to an Elixir term.

Decode DAG-CBOR binary, raising on error.

Encode a term to DAG-CBOR binary format.

Encode a term to DAG-CBOR, raising on error.

Hash the DAG-CBOR encoding of a term using SHA-256.

Transform a raw :cbor-decoded term into Exosphere structures.

Types

decode_error()

@type decode_error() ::
  {:error,
   :invalid_cbor
   | :cbor_function_clause_error
   | :cbor_match_error
   | :cbor_decoder_error
   | :cannot_decode_non_binary_values}

encode_error()

@type encode_error() :: {:error, :floats_not_allowed | Exception.t()}

Functions

decode(binary)

@spec decode(binary()) :: {:ok, term()} | decode_error()

Decode DAG-CBOR binary to an Elixir term.

CID links (tag 42) are decoded as Exosphere.ATProto.CID structs.

Examples

iex> Exosphere.ATProto.CBOR.decode(<<...>>)
{:ok, %{"hello" => "world"}}

iex> Exosphere.ATProto.CBOR.decode(<<0xFF>>)
{:error, :invalid_cbor}

decode!(binary)

@spec decode!(binary()) :: term()

Decode DAG-CBOR binary, raising on error.

encode(term)

@spec encode(term()) :: {:ok, binary()} | encode_error()

Encode a term to DAG-CBOR binary format.

Encoding is always canonical / deterministic: map keys are sorted using RFC 8949 length-first ordering (shorter keys first, ties broken bytewise) and CID structs are encoded as CBOR tag 42 wrapping a byte string.

Examples

iex> Exosphere.ATProto.CBOR.encode(%{"bb" => 1, "a" => 2})
{:ok, binary}  # Keys sorted as "a" (len 1), then "bb" (len 2)

iex> Exosphere.ATProto.CBOR.encode(3.14)
{:error, :floats_not_allowed}

encode!(term)

@spec encode!(term()) :: binary()

Encode a term to DAG-CBOR, raising on error.

hash(term)

@spec hash(term()) :: {:ok, binary()} | encode_error()

Hash the DAG-CBOR encoding of a term using SHA-256.

This is used for generating CIDs of data objects.

Examples

iex> Exosphere.ATProto.CBOR.hash(%{"hello" => "world"})
{:ok, <<sha256_bytes::binary-32>>}

transform_links(term)

@spec transform_links(term()) :: term()

Transform a raw :cbor-decoded term into Exosphere structures.

Converts CID links (tag 42) into Exosphere.ATProto.CID structs and unwraps CBOR byte strings (which the :cbor library decodes as %CBOR.Tag{tag: :bytes}) back into raw binaries.

This is shared by decode/1, Exosphere.ATProto.Firehose.Frame, and Exosphere.ATProto.CAR so all three handle real (byte-string) CID links identically. A malformed CID link is converted to nil rather than raising.