Layr8.Attachment (layr8 v0.2.10)

Copy Markdown View Source

A DIDComm v2 attachment.

Attachments carry payloads that travel alongside a message but are not part of the message body — signed credentials, large binaries, file references, etc.

Fields

  • id — unique attachment identifier (within the containing message)
  • description — human-readable description
  • filename — suggested filename for downloaded content
  • media_type — IANA media type of the content. For a Verifiable Grant this is the load-bearing field — see below.
  • format — protocol-specific format identifier
  • lastmod_time — last modification time as a Unix timestamp (integer)
  • byte_count — size of the attached content in bytes
  • data — map carrying the payload; see DIDComm v2 spec §5

data map

The data map may contain one or more of:

  • "base64" — base64url-encoded bytes (no padding)
  • "json" — inline JSON value
  • "jws" — the JWS; the cloud-node's credential extractor reads a compact JWS string from here
  • "hash" — base64url-encoded SHA-256 of the referenced content
  • "links" — list of URLs pointing to the content

Attaching a credential for authorization

Contract: ~/Developments/contracts/sender-cn-vg-attachment.md. In normal use Layr8.Wallet builds these attachments automatically on every send — this section is for hand-built ones.

%Layr8.Attachment{
  id: "urn:uuid:…",              # the credential's own id
  media_type: "application/vc+jwt",
  data: %{"jws" => compact_jws}
}

media_type is the only thing the node's credential extractor filters on, by exact string equality, and it drops every other attachment SILENTLY before looking at the data at all. Two consequences that have each cost a team a day:

  • Putting "application/vc+jwt" in format and something else in media_type attaches nothing, as far as the node is concerned. (These docs used to say to do exactly that.)
  • A Verifiable Presentation (application/vp+jwt) — the standard envelope for a holder showing a credential, and what Layr8.Presentations.sign_presentation/3 produces — is dropped on the same rule. Attach the credential bare.

Either way the denial that follows is byte-for-byte the one you get for attaching nothing at all, which is why the mistake is expensive to find.

data.base64 also works (the extractor falls back to it and base64url-decodes it), but prefer "jws": it is read first and it is what the whole ecosystem writes.

Wire format

%{
  "id" => "...",
  "media_type" => "...",
  "data" => %{"jws" => "..."}
}

Optional fields are omitted when empty/nil.

Summary

Functions

Serializes an Attachment into a DIDComm v2 JSON envelope map.

Parses a DIDComm v2 attachment map into an Attachment struct.

Types

data_map()

@type data_map() :: %{optional(String.t()) => term()}

t()

@type t() :: %Layr8.Attachment{
  byte_count: non_neg_integer() | nil,
  data: data_map(),
  description: String.t(),
  filename: String.t(),
  format: String.t(),
  id: String.t(),
  lastmod_time: non_neg_integer() | nil,
  media_type: String.t()
}

Functions

marshal(att)

@spec marshal(t()) :: map()

Serializes an Attachment into a DIDComm v2 JSON envelope map.

Optional string fields are omitted when empty; optional numeric fields are omitted when nil. data is always included (defaults to %{}).

parse(map)

@spec parse(map()) :: t()

Parses a DIDComm v2 attachment map into an Attachment struct.

Missing fields default to empty strings / nil / %{}.