Handles prekey generation and upload to WhatsApp servers.
Reference: whatsmeow/prekeys.go
Summary
Functions
Raises the advertised-id watermark to cover ids.
Returns the highest one-time prekey id this account has ever advertised.
Reserves count consecutive ids and returns the first one to mint.
Builds the IQ node to query prekey count on server.
Builds the IQ node to upload prekeys to server.
Check if this is an initial upload (no prekeys exist).
Marks a durably reserved prekey batch as acknowledged by the server.
Check if prekeys need to be uploaded based on server response.
Configurable version of needs_upload?/2 using runtime config.
Returns the next one-time prekey id that is safe to mint.
Records that the server is still serving prekey_id for this account.
Parses the server's response to a prekey count query.
Functions
Raises the advertised-id watermark to cover ids.
Called for every id this client puts in front of the server or a peer: an
upload batch, a retry receipt's key bundle, and any id an inbound pkmsg
proves the server is still serving.
@spec advertised_watermark(map()) :: non_neg_integer()
Returns the highest one-time prekey id this account has ever advertised.
@spec allocate_ids(map(), map(), pos_integer()) :: {:ok, pos_integer()} | {:error, term()}
Reserves count consecutive ids and returns the first one to mint.
The local watermark is only as trustworthy as the store holding it: restore the
session file from a snapshot and the ceiling comes back with it, below ids the
server is already handing out. A host that keeps its durable state somewhere
that cannot roll back — a row in the database the session file is archived
into, say — can close that gap by configuring
prekeys: [id_allocator: fn local_floor, count -> {:ok, first_id} end]. The
allocator is expected to be atomic and monotonic; it receives the local floor
so it can never hand back a range this store has already used.
Without one, the local floor stands on its own, which is correct for any deployment whose store never travels backwards.
An allocator that fails aborts the caller. Refusing to mint costs a thinner prekey pool on the server until it recovers; minting anyway costs an id space that two devices disagree about, which nothing repairs.
Builds the IQ node to query prekey count on server.
Builds the IQ node to upload prekeys to server.
Reference: whatsmeow/prekeys.go uploadPreKeys()
Check if this is an initial upload (no prekeys exist).
@spec mark_uploaded(ExWapp.Store.t(), [map()]) :: :ok | {:error, term()}
Marks a durably reserved prekey batch as acknowledged by the server.
Private key material is already present before the IQ is sent; this mutation only changes upload bookkeeping and can therefore be safely retried.
Check if prekeys need to be uploaded based on server response.
Configurable version of needs_upload?/2 using runtime config.
@spec next_safe_id(map(), map()) :: pos_integer()
Returns the next one-time prekey id that is safe to mint.
An id is safe only if it was never handed to the server. WhatsApp keeps
serving an uploaded prekey to peers long after this client forgot it — after a
crash before the durable write, or after the session file is restored from an
older snapshot — and a peer that opens a session with a stale id sends a
pkmsg this client answers with :prekey_not_found. Minting that id again
with fresh key material makes the damage permanent: the peer holds one public
half, the store holds another, and every X3DH between them fails from then on.
So the ceiling is the highest id ever advertised, not the highest id still
held.
@spec note_advertised_prekey_id(ExWapp.Store.t(), term()) :: :ok | {:error, term()}
Records that the server is still serving prekey_id for this account.
The trigger is an inbound pkmsg naming a one-time prekey the local store
cannot produce. Nothing can recover that message — the private half is gone —
but the id must never be reissued, so the watermark absorbs it here.
Parses the server's response to a prekey count query.
The response contains a <count> child node with a value attribute.
Reference: Baileys getAvailablePreKeysOnServer()