> ## Documentation Index
> Fetch the complete documentation index at: https://whatsapp-rust.jlucaso.com/llms.txt
> Use this file to discover all available pages before exploring further.

# June 14, 2026 — Drop moka: PortableCache is now the sole in-process cache backend

> Removes the moka dependency (-2.55 MiB stripped, -21% .text). PortableCache gains monotonic TTL/TTI, eager init-lock reclamation, and a reliable async clear(). TypedCache::from_moka is renamed to from_local.

PR [#860](https://github.com/oxidezap/whatsapp-rust/pull/860) removes the `moka` dependency and makes `PortableCache` the only in-process cache backend on every target, including wasm32.

## Why moka was removed

`moka` was the single largest contributor to the release binary — **1.8 MiB of `.text` (15.8%)** — almost entirely from per-cache-type monomorphization. Its `do_run_pending_tasks` alone was emitted **84 times (710 KiB)** across the \~15 distinct `Cache` types the client instantiates; each new typed cache dragged in moka's full generic machinery (\~100 KiB+).

`PortableCache` was already shipping on wasm32 targets and mirrors the full moka `Cache` API (capacity + TTL/TTI eviction, single-flight `get_with`/`get_with_by_ref`). Making it the sole backend required no call-site changes.

## Binary size impact

Real release profile (fat LTO, `codegen-units=1`, `panic=abort`, strip):

| Metric              | before (moka) | after (PortableCache) |                      Δ |
| ------------------- | ------------: | --------------------: | ---------------------: |
| Stripped size       |     13.35 MiB |             10.81 MiB | **−2.55 MiB (−19.1%)** |
| `.text`             |     11.31 MiB |              8.89 MiB | **−2.42 MiB (−21.4%)** |
| LLVM IR lines       |     1,275,789 |               664,220 |             **−47.9%** |
| `Cargo.lock` crates |           357 |                   354 |                     −3 |

The net delta exceeds moka's own 1.8 MiB line because dropping moka also removes its transitive deps (crossbeam-channel/epoch, quanta, part of uuid) and unlocks further LTO savings. CodSpeed reports no performance change across 172 benchmarks.

## PortableCache hardening

Making PortableCache the sole native backend surfaced a few behavioural gaps that were addressed in this PR:

* **Monotonic TTL/TTI** — expiry now uses `wacore::time::Instant` instead of the wall clock, so a system-clock jump can't expire entries early. This matches moka's timer semantics and prevents `session_recreate_history`'s throttle backstop from being bypassed.
* **Eager single-flight init-lock reclamation** — `get_with`/`get_with_by_ref` now drop a key's init lock once no other caller holds it, instead of waiting for `run_pending_tasks`. Fixes unbounded `init_locks` growth in high-cardinality caches (session locks, chat lanes, message-id dedup) that never call `run_pending_tasks`.
* **Reliable async `clear()`** — new `PortableCache::clear()` awaits the write lock. `cleanup_connection_state` and `TypedCache::clear` now use it instead of the best-effort sync `invalidate_all()`, which could skip the clear under contention and leave a stale `ChatLane` after reconnect.
* **`snapshot_entries()`** — new async method that awaits the read lock for a reliable snapshot; used by `SenderKeyDeviceCache::invalidate_entries_for_device` where a missed entry would silently drop an SKDM fanout.

## Breaking changes

### `moka-cache` feature removed

The `moka-cache` Cargo feature no longer exists. Remove it from your `Cargo.toml`:

```toml theme={null}
# Before
whatsapp-rust = { version = "0.6", default-features = false, features = [
    "sqlite-storage", "tokio-transport", "tokio-runtime",
    "ureq-client", "tokio-native", "signal",
    "moka-cache",   # ← remove this line
] }

# After
whatsapp-rust = { version = "0.6", default-features = false, features = [
    "sqlite-storage", "tokio-transport", "tokio-runtime",
    "ureq-client", "tokio-native", "signal",
] }
```

### `TypedCache::from_moka` renamed to `from_local`

If you construct a `TypedCache` directly in your own code, update the constructor name:

```rust theme={null}
// Before
let cache = TypedCache::from_moka(my_cache);

// After
let cache = TypedCache::from_local(my_cache);
```

### `portable_cache` module is now always public

`whatsapp_rust::portable_cache` is no longer `cfg`-gated. Any conditional compilation on `#[cfg(any(not(feature = "moka-cache"), target_arch = "wasm32"))]` around imports of that module should be removed.

## Trade-offs

`PortableCache` differs from moka in two ways relevant to very high-throughput deployments:

* **Eviction policy**: FIFO instead of TinyLFU (lower hit rate under heavily skewed access patterns)
* **Concurrency**: one `RwLock` per cache vs moka's sharded, lock-free reads (more contention under heavy concurrent access)

For typical bot/single-account workloads this is unlikely to matter; the integration benchmarks (CodSpeed) confirmed no performance change across all 172 benchmarks.
