Layr8.Message (layr8 v0.3.3)

Copy Markdown View Source

A DIDComm v2 message.

Fields

  • id — unique message identifier (UUID v4)
  • type — DIDComm message type URI
  • from — sender DID
  • to — list of recipient DIDs
  • thread_id — correlates messages in a thread (thid)
  • parent_thread_id — links to a parent thread (pthid)
  • body — message payload (arbitrary map)
  • attachments — list of Layr8.Attachment structs (DIDComm v2 attachments), or nil when the header could not be read; see below
  • attachments_unread — why the attachments header was not read, nil when it was
  • trace_context — the DIDComm trace_context header, see below
  • context — inbound-only metadata from the cloud-node

trace_context

A W3C trace context carried in the top-level trace_context plaintext header, as a map with the W3C header names as string keys: %{"traceparent" => "00-…", "tracestate" => "…"} ("tracestate" is optional). That shape is a ready-made text-map carrier for an OpenTelemetry propagator. nil means the message carried none, or carried a value this SDK could not read (see read_trace_context/1). The SDK carries the value and does not validate the traceparent format; the node does.

A handler's {:reply, msg} and the problem report for a failed handler copy the request's trace_context unchanged when the reply does not set its own.

attachments has three states, not two

the message carriedattachmentsattachments_unread
no attachments header[]nil
a header this SDK readthe attachmentsnil
a header it could not readnilwhy

Returning [] for a header nobody could read would report "this message carried no attachments", which is a measurement that was never taken.

The message itself is parsed either way. An authorization denial must not disappear because a hint travelling beside it was malformed — being refused and being ignored are different events, and a caller waiting on Layr8.Client.request/4 sees the difference as a denial versus a timeout.

Wire Format (outbound)

{
  "id": "...",
  "type": "...",
  "from": "...",
  "to": [...],
  "thid": "...",
  "pthid": "...",
  "body": {...},
  "attachments": [...],
  "trace_context": {"traceparent": "...", "tracestate": "..."}
}

Wire Format (inbound, from cloud-node)

{
  "context": {"recipient": "...", "authorized": true, "sender_credentials": [...]},
  "plaintext": {"id": "...", "type": "...", "from": "...", "to": [...], "body": {...}, "thid": "...", "pthid": "..."}
}

Summary

Types

t()

A W3C trace context: "traceparent" and, optionally, "tracestate".

Functions

Generate a new unique message ID (UUID v4).

Serializes a Layr8.Message into a DIDComm JSON envelope map.

Parses an inbound cloud-node message envelope (with context + plaintext) into a Layr8.Message.

Reads a trace_context header value.

Types

t()

@type t() :: %Layr8.Message{
  attachments: [Layr8.Attachment.t()] | nil,
  attachments_unread: String.t() | nil,
  body: map() | nil,
  context: Layr8.Message.Context.t() | nil,
  from: String.t(),
  id: String.t(),
  parent_thread_id: String.t(),
  thread_id: String.t(),
  to: [String.t()],
  trace_context: trace_context() | nil,
  type: String.t()
}

trace_context()

@type trace_context() :: %{required(String.t()) => String.t()}

A W3C trace context: "traceparent" and, optionally, "tracestate".

Functions

generate_id()

@spec generate_id() :: String.t()

Generate a new unique message ID (UUID v4).

marshal(msg)

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

Serializes a Layr8.Message into a DIDComm JSON envelope map.

The result is suitable for encoding with Jason.encode!/1.

Example

msg = %Layr8.Message{id: "abc", type: "...", from: "did:ex:alice", to: ["did:ex:bob"], body: %{text: "hi"}}
Layr8.Message.marshal(msg)
# => %{"id" => "abc", "type" => "...", "from" => "did:ex:alice", "to" => ["did:ex:bob"], "body" => %{text: "hi"}}

parse(data)

@spec parse(map() | String.t()) :: {:ok, t()} | {:error, term()}

Parses an inbound cloud-node message envelope (with context + plaintext) into a Layr8.Message.

Accepts a map (already JSON-decoded) or a JSON string.

Example

envelope = %{
  "context" => %{"recipient" => "did:ex:bob", "authorized" => true, "sender_credentials" => []},
  "plaintext" => %{"id" => "abc", "type" => "...", "from" => "did:ex:alice", "to" => ["did:ex:bob"], "body" => %{}}
}
Layr8.Message.parse(envelope)

read_trace_context(value)

@spec read_trace_context(term()) :: trace_context() | nil

Reads a trace_context header value.

Returns a map with only the string keys "traceparent" and (when it is a string) "tracestate", or nil for anything that is not a map with a string traceparent. Never raises: a malformed header must not cost the reader the message. Other members are dropped and never forwarded. Atom keys (%{traceparent: ...}) are accepted for values a caller builds.