# `ExWapp.Prekeys`
[🔗](https://github.com/elchemista/ex_wapp/blob/v0.1.5/lib/ex_wapp/prekeys.ex#L1)

Handles prekey generation and upload to WhatsApp servers.

Reference: whatsmeow/prekeys.go

# `advertise_ids`

```elixir
@spec advertise_ids(map(), [term()]) :: map()
```

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.

# `advertised_watermark`

```elixir
@spec advertised_watermark(map()) :: non_neg_integer()
```

Returns the highest one-time prekey id this account has ever advertised.

# `allocate_ids`

```elixir
@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.

# `build_prekey_count_query`

Builds the IQ node to query prekey count on server.

# `build_prekey_upload`

Builds the IQ node to upload prekeys to server.

Reference: whatsmeow/prekeys.go uploadPreKeys()

# `initial_upload?`

Check if this is an initial upload (no prekeys exist).

# `mark_uploaded`

```elixir
@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.

# `needs_upload?`

Check if prekeys need to be uploaded based on server response.

# `needs_upload?`

Configurable version of `needs_upload?/2` using runtime config.

# `next_safe_id`

```elixir
@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.

# `note_advertised_prekey_id`

```elixir
@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.

# `parse_count_response`

Parses the server's response to a prekey count query.

The response contains a `<count>` child node with a `value` attribute.
Reference: Baileys getAvailablePreKeysOnServer()

---

*Consult [api-reference.md](api-reference.md) for complete listing*
