Amarula.Contacts (amarula v0.1.0)

View Source

Contact discovery via USync. The consumer-facing half of Baileys' onWhatsApp / fetchStatus.

Both functions build a single USync iq (see Amarula.Protocol.USync), send it through the connection's generic IQ primitive (Amarula.Connection.query_iq/3), and turn the reply into friendly maps carrying Amarula.Address values — never raw jid strings, matching Amarula.Msg/Amarula.Group.

These are re-exported from the Amarula facade (Amarula.on_whatsapp/2, Amarula.fetch_status/2, Amarula.resolve_lid/2).

Summary

Types

One resolve_lid/2 result: the contact's LID and PN addresses.

One on_whatsapp/2 result: the resolved address and whether it's on WhatsApp.

One fetch_status/2 result: the address, its status/bio text, and when it was set.

Functions

Fetch the status/bio text of the given users.

Check which of the given phone numbers are on WhatsApp.

Resolve each phone number to its privacy LID (<n>@lid) and persist the LID↔PN mapping, so Amarula.canonical_jid/2 (and the Signal addressing the send pipeline uses) resolve that contact afterwards.

Types

conn()

@type conn() :: GenServer.server()

lid_pair()

@type lid_pair() :: %{lid: Amarula.Address.t(), pn: Amarula.Address.t()}

One resolve_lid/2 result: the contact's LID and PN addresses.

presence()

@type presence() :: %{address: Amarula.Address.t() | nil, exists: boolean()}

One on_whatsapp/2 result: the resolved address and whether it's on WhatsApp.

status()

@type status() :: %{
  address: Amarula.Address.t() | nil,
  status: String.t() | nil,
  set_at: DateTime.t() | nil
}

One fetch_status/2 result: the address, its status/bio text, and when it was set.

Functions

fetch_status(conn, jids)

@spec fetch_status(
  conn(),
  [String.t() | Amarula.Address.t()] | String.t() | Amarula.Address.t()
) ::
  {:ok, [status()]} | {:error, term()}

Fetch the status/bio text of the given users.

jids are wire jid strings or Amarula.Address values. Returns one result per user with the status text (nil when not visible to you, "" when explicitly empty) and the time it was set.

on_whatsapp(conn, phones)

@spec on_whatsapp(conn(), [String.t()] | String.t()) ::
  {:ok, [presence()]} | {:error, term()}

Check which of the given phone numbers are on WhatsApp.

phones are bare numbers or +-prefixed (e.g. "15551234567"); each is sent as a USync contact lookup. Returns one result per number with the resolved Amarula.Address and an exists flag.

Amarula.Contacts.on_whatsapp(conn, ["15551234567"])
#=> {:ok, [%{address: %Amarula.Address{...}, exists: true}]}

resolve_lid(conn, phones)

@spec resolve_lid(conn(), [String.t()] | String.t()) ::
  {:ok, [lid_pair()]} | {:error, term()}

Resolve each phone number to its privacy LID (<n>@lid) and persist the LID↔PN mapping, so Amarula.canonical_jid/2 (and the Signal addressing the send pipeline uses) resolve that contact afterwards.

on_whatsapp/2 returns only the PN, so it can't establish a mapping; this runs a :lid+:contact USync (the only query that returns the pairing) and feeds the result into the same mapping store Amarula auto-populates from group metadata and the send pipeline. Returns one entry per number that resolved to a LID; numbers not on WhatsApp (no LID in the reply) are omitted.

Amarula.Contacts.resolve_lid(conn, ["15551234567"])
#=> {:ok, [%{lid: %Amarula.Address{kind: :lid, ...},
#           pn: %Amarula.Address{kind: :pn, ...}}]}