Amarula.Address (amarula v0.4.2)

View Source

A WhatsApp address — the consumer-facing way to name who/what a message is for or from. A friendly value you can build, inspect, and pass to sends, instead of juggling raw "user@server" jid strings.

Four kinds, distinguished by :kind:

  • :pn — a phone-number identity (<number>@s.whatsapp.net).
  • :lid — a privacy "Linked ID" (<id>@lid). WhatsApp's wire-preferred identity; the same person has both a PN and a LID.
  • :group — a group chat (<id>@g.us). A container of participants, not a person; its members are fetched separately (group metadata), not stored here.
  • :none — the empty address (empty/0): "no identity". A stand-in for "we don't have one yet" (e.g. Amarula.own_address/1 before login) — returned instead of nil, so you never have to nil-check. It names nothing: every is_*? is false, it is never same_account? with anything, and it has no jid string (to_jid!/1 raises; to_jid/1 returns {:error, :no_jid}).

:device is the device number (nil = account-level / primary). An address with device: nil names the whole account; with a device it names one client.

Parsed-only

An Address is a pure value — only what's deterministic from the string. It does NOT carry resolved data (a PN's LID, a group's participants, device lists): those need connection state, are lazy, and can change, so they stay internal. Don't expect Address.pn(...) to "know" its LID.

Strings in, strings out

parse/1 turns a jid string into an Address; to_jid/1 turns an Address back into its jid string (both via Amarula.Protocol.Binary.JID). The public API and events speak Address; under the hood the protocol speaks jid strings. The public API also accepts a raw string and parses it for you, so Amarula.send_text(conn, "5511...@s.whatsapp.net", ...) and Amarula.send_text(conn, Address.pn("5511..."), ...) both work.

Summary

Functions

The empty address — "no identity". Returned instead of nil (see the :none kind).

Whether this is the empty address (empty/0, kind :none).

A group address from a bare id or full @g.us jid string.

A LID address from a bare id or full jid string.

The account-level address (device stripped).

Parse a jid string into an Address (via JID.decode/1). An already-parsed Address passes through unchanged, and nil passes through as nil — so it's safe to call on an optional String.t() | nil field without wrapping. Also returns nil for an unparseable or unknown-server string; use parse!/1 when a bad jid should raise instead.

Like parse/1 but raises ArgumentError on an unparseable jid (never nil).

A PN address from a bare number or full jid string.

Whether two addresses name the same account (same user+kind, ignoring device). The empty address (:none) names nothing, so it is never the same account as anything — including another empty.

Get the jid string for an Address (or pass a jid string straight through).

Like to_jid/1 but returns the bare string, raising on the empty address.

Types

kind()

@type kind() :: :pn | :lid | :group | :none

t()

@type t() :: %Amarula.Address{
  device: non_neg_integer() | nil,
  kind: kind(),
  user: String.t()
}

Functions

empty()

@spec empty() :: t()

The empty address — "no identity". Returned instead of nil (see the :none kind).

empty?(arg1)

@spec empty?(t()) :: boolean()

Whether this is the empty address (empty/0, kind :none).

group(id)

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

A group address from a bare id or full @g.us jid string.

group?(arg1)

@spec group?(t()) :: boolean()

lid(user)

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

A LID address from a bare id or full jid string.

lid?(arg1)

@spec lid?(t()) :: boolean()

normalize(a)

@spec normalize(t()) :: t()

The account-level address (device stripped).

parse(address)

@spec parse(String.t() | t() | nil) :: t() | nil

Parse a jid string into an Address (via JID.decode/1). An already-parsed Address passes through unchanged, and nil passes through as nil — so it's safe to call on an optional String.t() | nil field without wrapping. Also returns nil for an unparseable or unknown-server string; use parse!/1 when a bad jid should raise instead.

parse!(jid)

@spec parse!(String.t() | t()) :: t()

Like parse/1 but raises ArgumentError on an unparseable jid (never nil).

pn(user)

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

A PN address from a bare number or full jid string.

pn?(arg1)

@spec pn?(t()) :: boolean()

same_account?(arg1, arg2)

@spec same_account?(t(), t()) :: boolean()

Whether two addresses name the same account (same user+kind, ignoring device). The empty address (:none) names nothing, so it is never the same account as anything — including another empty.

to_jid(jid)

@spec to_jid(String.t() | t()) :: {:ok, String.t()} | {:error, :no_jid}

Get the jid string for an Address (or pass a jid string straight through).

This is the function to use when you have a msg.channel/from/to (an Address) and need the "user@server" string WhatsApp uses — e.g. to build a MessageKey. A plain string passes through unchanged, so you can hand it either form.

Returns {:ok, jid}, or {:error, :no_jid} for the empty address (:none), which has no jid. Use to_jid!/1 for the bare string.

iex> Amarula.Address.to_jid(Amarula.Address.pn("5511999999999"))
{:ok, "5511999999999@s.whatsapp.net"}

to_jid!(jid)

@spec to_jid!(String.t() | t()) :: String.t()

Like to_jid/1 but returns the bare string, raising on the empty address.