More than a year in
The repo went up on 1 July 2025. Today: 1,462 commits, 17 contributors, around 700 stars, and a client that pairs by QR or phone number, encrypts one-to-one and group messages, syncs history, moves media, and places and answers real WhatsApp calls with audio and video.
wacore was built with no runtime of its own, so the same protocol code runs anywhere. Three projects took it up on that:
- whatsapp-rust-bridge compiles the core to wasm for JavaScript. It lives under WhiskeySockets, and
baileys@latest(the 7.0 line, in release candidate) depends on it directly. Baileys is the reference WhatsApp Web library for JavaScript, at roughly a million installs a week. - baileyrs: a WhatsApp Web library for JavaScript, powered by Rust, with a Baileys-compatible API.
- whatsapp-rust-esp32: a full end-to-end-encrypted WhatsApp client on an ESP32-S3. No Tokio, hundreds of kilobytes of RAM, and it pairs and exchanges encrypted messages. Every "this has to stay runtime-agnostic" review comment was paying for that one.
None of it was planned in July 2025. Thank you to everyone who filed an issue with a stanza dump attached, argued with a diff, or shipped something on top of this and told us what broke. A reverse-engineered protocol is not something one person figures out.
This release
488 pull requests since 0.6.0, over roughly three months. The big items are VoIP (1:1 voice, 1:1 video, group calls and call links, with the media plane and not only the signaling), the switch of protobuf codegen from prost to buffa, a pre-1.0 pass over the public API (typed errors, sealed event payloads, #[non_exhaustive]), a plugin host, an optional SQLite chat store, opt-in tracing and metrics, and a per-message round trip that allocates about a third less than 0.6.0's.
A lot of APIs changed, and the Breaking changes section below is the one to read before upgrading. The two invasive ones are buffa's generated proto surface and the anyhow to typed-error migration, and both touch nearly every call site in a downstream crate. They are taken now because breaking changes are still cheap before 1.0.
Highlights
VoIP
- 1:1 voice calls (#918). Incoming and outgoing, against the official WhatsApp app, with the full media path: mic capture, encode, encrypt, relay, decrypt, decode, playout. Includes a pure-Rust MLow codec (WhatsApp's proprietary voice codec, ported from the reverse-engineered reference and pinned by a byte-exact golden roundtrip test), E2E-SRTP with the WARP integrity tag and the SFrame layer, and a sans-IO
CallEnginethat owns no socket, clock or thread. No codec FFI, so it still builds for wasm and embedded targets. - 1:1 video calls (#1024). Start with video, upgrade from audio, downgrade back, and accept the same transitions from an official client. Codec-neutral: consumers pass complete H.264 Annex-B access units through
VideoSource/VideoSink. Authenticated PLI/FIR is treated as a decoder resynchronization boundary, which is what made real webcam video render on the Android peer. - Group calls and call links (#1130). Group-bound calls, ad-hoc promotion of an active direct call, reusable call links, 128-user waiting rooms with admission and administrator controls, roster-driven subscriptions, atomic epoch rotation and key fan-out, participant-attributed audio, video, RTCP and data, plus reactions, hand raising and screen sharing.
- Encoded audio and native Opus (#1050). Applications can supply raw MLow or Opus packets without linking a codec. Full-duplex native Opus negotiation (PT120/16 kHz as the production profile, PT111/48 kHz as an explicit variant). MLow stays the compatibility default.
- tctoken on outgoing call offers (#970), zero-copy RTP/STUN parsing (#957), and a tail of live-tested relay and signaling fixes (#1102, #1104, #1107, #1128).
let handle = client.voip()
.call(peer)
.audio(mic_source, speaker_sink)
.video(h264_source, h264_sink) // optional
.start()
.await?;
handle.wait_ended().await;The media plane sits behind optional features (voip, voip-runtime, voip-mlow, voip-libopus, voip-encoded), and a default build pulls none of it. Call signaling is not gated: the IncomingCall and MissedCall events, and reject and terminate, are there in a default build.
Extensibility
- Plugin architecture (#1061). A build-time native plugin host behind the
pluginsfeature, with a generation-scoped extension lifecycle (client-lifecycle), typed plugin APIs, capabilities, dependency ordering, scoped tasks with completion barriers, and a bounded event router keyed by(plugin_id, topic). whatsapp-rust-chat-store(#1014). An opt-in crate that materializes the client's event stream into queryable SQLite tables, in the same database file as the device store, so a UI or a stateful bot survives a restart without re-syncing. Event-sourced write-behind writer, encodedwa::Messageas the source of truth, keyset pagination, aStoreChangebroadcast for invalidation, and FTS5 search. Not on crates.io yet: the schema and the query surface are still moving, so it is consumed by git path for now.- Optional tracing (#733): around 172 spans under a
wa.{conn,recv,send,iq,appstate,pair,media,receipt,retry,pdo,notif,session,bot}.*taxonomy, OTel-ready, with phone numbers redacted by default. Optional metrics (#734) through themetricsfacade, plus awhatsapp-rust-plugin-metricsplugin (also unpublished, by git path). Both are off by default, with no dependency and no overhead when disabled. - Per-session resource attribution in
stats()(#967). - Typed legacy session interop (#1072) behind
legacy-session-interop, for importing externally produced auth state. - A SQLite connection-init hook that runs before pragmas and migrations (#1074).
Delivery guarantees
- Opt-in inbound durability hook (#920) turns the inbound consumer from at-most-once into at-least-once. The transport ack is deferred until the hook commits, and the decrypted message is buffered durably before the Signal ratchet flushes. With no hook registered the behaviour is unchanged.
- Ordered and bounded event delivery (#981).
EventDelivery::Ordered { capacity }delivers callbacks in arrival order through one bounded mailbox, matching WA Web'spreserveOrder: true. A full mailbox drops the event and counts it inStatsSnapshot::events_droppedinstead of growing without limit. - Batched inbound commit during the offline drain (#961). WA Web commits durability, signal-store writes and aggregate receipts once per snapshot; we were doing all of it per message. A 421-message backlog was spending about 1.2 s in per-message round-trips.
- An opt-in
RetryAdmissionhook (#985) and an observe-onlyServerAckevent (#989).
Messaging surface
- Passkey companion linking (#928): WhatsApp's SHORTCAKE_PASSKEY WebAuthn device-link gate, end to end, with a
PasskeyAuthenticatorseam for the one step that cannot be reproduced in-tree. - Reactions (#720), message forwarding (#738), keep-in-chat (#740), quiz polls (#754), events with RSVP (#758), chat labels (#715), a 1:1 disappearing-message timer (#745),
mark_as_playedfor voice and video notes (#737), group profile pictures (#739),save_contact(#742), theclearChat(#755) anduserStatusMute(#760) app-state actions, and newsletter mute/unmute (#757). - Encrypted channel (CAG) reactions and comments, both directions (#830).
- Meta AI and fbid bot replies via
<enc type="msmsg">(#650). - Secret-encrypted envelopes: poll-edit, poll-add-option and event-edit (#645), and message edits on receive (#665, #667, #762).
- Constant-memory streaming upload with a media sidecar (#684), high-level media builders from
UploadResponse(#764),ContextInfoin media options (#931), and media download without a connected session (#1194). - First-party sticker packs from the CDN (#644), and the verified business name on messages and usync (#741, #1081).
Generated protocol registries
Hand-maintained protocol tables were replaced with registries generated from the whatspec IR, so refreshing them is a file copy instead of an audit.
- mex operations (#728), with typed
VariablesandResponseper op. This also fixed two doc-ids the current WA Web bundle no longer ships, which had been failing silently. - A/B props (#729): 2100 typed flags replacing 11 magic
u32s, at no binary cost for the ones nothing references. - App-state (syncd) schemas (#716). Every action now carries its own
version,scopeand index shape; we had been stampingversion = 1on all of them. - Proto bumped to WhatsApp Web 2.3000.1040878135 (#726), then 2.3000.1042742319 (#1001).
Performance
The allocation work from 0.6.0 continued, with one change in method: CodSpeed now runs deterministic instruction-count and memory instruments on every PR (#828, #898, #950), so a regression is caught before merge and every number below was measured rather than estimated.
Per-message round trip
The ping-pong allocation series (#1015 to #1020) took 32.3% off the bytes allocated per cycle, from a 46,088 B baseline, across six PRs: hot-path allocations, a persistent receipt worker, sync fast paths for the store adapter, exact stanza sizing, per-branch boxed send futures and an inlined marshal hint cache.
A second sweep removed another dozen-plus allocations from the DM round trip (#1114, #1116, #1122, #1131, #1137), coalesced queued noise frames into one transport write (#1119, #1120, #1121) and memoized the DM device fan-out per recipient (#1118).
Signal and crypto
- Counter leasing (#1026, #1048): warm group encryption went from 84.69 ms to 23.98 ms (-71.7%), warm participant fan-out from 49.16 ms to 8.69 ms (-82.3%).
- The sender-key backlog moved behind an
Arc(#881), taking an in-order decrypt on top of a ~2000-key backlog from a 97 µs to a 33 µs median and removing the ~82 KB allocation every decrypt was paying. It is now stored asCopypairs as well (#953), which takes the worst-case out-of-order group decrypt from 163.7 µs to 113.3 µs (-31%). - XEdDSA memoization for sender signing and verification (#838, #839, #1213), pre-keyed zero-salt HKDF extracts (#847, #863, #864), and shift-free eviction of skipped message keys (#946).
Binary protocol and JID
- Token lookup moved to a length-bucketed
tiny_mapon encode (#873), takingmarshal_auto_smallfrom 168.7 ns to 111.8 ns (-34%), and then to a build-time static hash table (#1056) that is 29 KiB smaller, faster on hits, and drops thehashifydependency.marshal_exactgot 3x faster by replaying plan-pass hints instead of reclassifying every string (#1057). - Small attribute lists are stored inline (#819): a message-shaped stanza went from 15 to 11 allocations, an 800-participant group stanza from 4012 to 2412 (-40%). Packed values are unpacked through a byte-pair table (#1214), and the per-node box around
NodeRefcontent is gone (#1216), worth -9.5% instructions on the fan-out bench and -40% on the allocation count. Jiddisplay emits onewrite_str(#848), 176.7 ns to 69.7 ns, followed by a parsing sweep that stops the scan at the@, reads the device and agent fields with a decimal-only reader, and stops re-validating UTF-8 the writer just assembled (#1171 to #1173, #1176, #1183, #1187), with the same pass trimming node child iteration and attribute lookups (#1174, #1175).- Wire strings are validated through
smoothutf8(#932), and inflate writes into an uninitialized buffer, dropping amemsetthat was 6% self time (#933).
App-state and history sync
- ltHash index-MAC dedup:
bench_collect_unique_index_macs[1000]went from 5,678 µs to 550.8 µs (#868), then another -19% at 1000 and -72% at 10 with inline index-MAC keys (#955). The N+1 previous-MAC lookups became a single query (#687, #821), and the O(n²) in-patch overwrite scan became an O(1) map (#701). - History sync got streaming decompression (#672), a pooled inflate reader (#683), storage of the compressed payload with a streaming reader (#853) and a decode-gating scan (#836). Together: allocation churn from 20.20 MB to 14.43 MB (-28.6%), CodSpeed stream-drain memory from 243.8 KB to 115.2 KB, and -16.2% peak heap on a 20k-row secret batch (#1058, #1054).
Send path and caching
- The per-group device fan-out is memoized behind a topology generation (#824), the group phash is memoized on the same entry (#840), warm sends stay warm under the own-device SKDM steady state (#1021), and cold sender-key distribution is single-flight (#937).
- One message encode is shared between the reporting token and the DM or group plaintext (#904, #905), and DM content is encoded once and spliced into the recipient and DSM plaintexts (#787, #788).
- Device-registry lookups borrow their keys and build them inline (#681, #682), taking per-member device resolution on an 800-member group send from 50,915 to 12,538 allocations (-75%).
- moka is gone.
PortableCacheis the only in-process cache backend (#860).
Storage
- Per-session memory and thread use was cut and made configurable (#926), and the per-checkout
SELECT 1liveness probe (36.6% of the bare checkout cost) was removed (#874). - WAL readers are no longer blocked by search (#1151): an FTS5 prefix query over 60k rows went from 13.3 ms to 0.8 ms.
Binary size
Binary size is now a CI gate with a per-PR budget and a historical series (#859).
waproto::codecwas pinned to a single instantiation (#842), taking.textfrom 13.03 to 11.85 MiB (-9.1%). Cold entry-point futures were boxed (#843) and the protoPartialEqanchor dropped, taking 148eqimpls to 0 (#846).wa::Messageshrank from 3784 to 952 bytes (-75%) by boxing its inline content variants (#866).- A full audit landed -1.47 MiB stripped (-13.3%) and -14.8%
.text(#1055) through-Zshare-generics, lld with ICF, SQLite at-Ozwith a subsystem trim, and the rest of the codec sweep. Every rejected lever is documented with its drawback.
WhatsApp Web compliance and reliability
- App-state convergence (#1158). A
snapshotMacmismatch on a patch means the collection's ltHash has diverged, not that the server is tampering. We treated it as fatal and re-requested the same unusable patch forever (the report was 114 identical failures over one evening, surviving restarts). WA Web degrades the collection instead. The same PR stops losing patches rejected with 409. Related: aggregate MAC validation for genesis patches (#988), snapshot-rollback and duplicate-index guards (#752, #753), index-mode ltHash for SET plus REMOVE on the same index (#829), and key recovery across companion devices (#1052). - Signal durability (#1027, #1041 to #1044): sender-key advances gated before the wire, retry advances persisted before the wire, durability gates retained through deletes, sender-key mutations serialized, and cancelled session checkouts recovered. A deterministic chaos suite covers it (#1049).
- A blind WA Web parity sweep (#965) raised the offline-drain snapshot from 200 to 400, lowered the Signal forward-jump cap from 25000 to 2000, made the reconnect backoff reset only after a stable connection of 30 s or more (with explicit penalties surviving the reset), and made
<xml-not-well-formed>force-close the socket. - Top-level
<status>stanzas are handled and acked (#1101). An unacked one was recycling the stream. - Pair-code lifetime (#1163). A phone-number link no longer dies with the QR rotation. The stage-1 and stage-2 crypto was re-audited and cleared first. The
companion_finishanswer is now read instead of assumed (#1198), andlink_code_pairing_noncewas corrected (#976, #979). - JID correctness (#1178, #1182, #1184). The AD-JID domain byte was being kept as an
agent, so encode followed by decode was not idempotent. Agent identity, the AD form and device dedup now agree, and interop JIDs encode with the token that carries their integrator. - LID and PN: DM wire addressing is gated on the account's 1:1 migration state (#943), the write policy is source-aware and matches
createLidPnMappings(#1011), and mappings are learned fromphoneNumberToLidMappings(#1010) and from embedder-supplied sources (#1013). - Retry and SKDM: recoverable group and 1:1 decrypt failures retry instead of NACK (#986, #987), the per-group resend rate is bounded to avoid
AccountLocked(#871), SKDM redistribution is gated on the primary device (#872), own devices are never memoized in the sender-key map (#999), per-device sessions are locked across the SKDM fan-out (#990), and the inbound sender-key chain is serialized (#992). - Hardening: node-decode recursion depth is bounded against hostile frames (#994), nothing is sent after a transport failure so the nonce cannot be reused (#1117), the keepalive watchdog is anchored to first send (#995), noise frame-counter exhaustion is an error rather than a wrap (#782), the WARP MI tag is authenticated before recv ROC state is folded (#998),
download_to_writerleaves only verified media (#1197), and self-only protocol messages are honored only from our own account (#646). - Connection lifecycle: the failure stanza is no longer dropped on logout, ban or outdated (#1165), the reconnect backoff races the terminal shutdown (#1179), the
Originheader is sent on the WebSocket upgrade (#1166), and SIGTERM shuts the client down cleanly (#960).
Breaking changes
Protobuf codegen: prost to buffa
#557 migrates codegen to buffa and puts its zero-copy views on the real decode paths. This changes the shape of every generated type:
| Pattern | Before (prost) | After (buffa) |
|---|---|---|
| Sub-message fields | Option<T>, Option<Box<T>> where recursive |
MessageField<T> (.as_option() / .is_set()) |
| Enum fields | Option<i32> |
Option<EnumType> (typed) |
| Enum variants | CamelCase |
SCREAMING_SNAKE_CASE, with CamelCase aliases still generated |
| Type names | AdvSignedDeviceIdentity |
ADVSignedDeviceIdentity |
| Decode (owned) | Type::decode(bytes) |
Type::decode_from_slice(bytes) |
| Decode (borrowed) | not available | TypeView::decode_view(bytes) |
| Encode | msg.encode(&mut buf)? |
msg.encode_to_vec() |
whatsapp.rs is no longer tracked: build.rs generates it into OUT_DIR from the committed descriptor, so consumers never need protoc. Proto field names are snake_case, which is wire-compatible. Encoding a waproto type from outside waproto should go through the pinned waproto::codec helpers (#1091); a clippy.toml guard enforces that in-repo.
Errors
anyhowno longer appears in any public signature (#893). There is one typed error per feature domain (SendError,GroupError,ContactError,BlockingError,ChatStateError,PresenceError,CommunityError,NewsletterError,ProfileError,PollError,SignalError,TcTokenError,MediaReuploadError,AppStateError), all built on a sharedClientErrorbase with#[from]chaining. Every listed method'sErrvariant changed, though?into ananyhowcontext still works.ConnectErrorandConnectStage(#1090):connect(),wait_for_socket()andwait_for_connected()returnResult<(), ConnectError>,ClientError::AlreadyConnectedis gone, andlogout()is now infallible.- All 46 occurrences of
#[error(transparent)]became#[error("{0}")](#1100). TheDisplayoutput is byte-for-byte identical, but the wrapped typed error stays reachable throughsource(), so a 403 or a 409 can be classified without matching on strings.ErrorChainExtwrites that walk once. A refused HTTP status is recoverable by type (#1195). - The read loop exits with a typed reason (#956). Routine server recycles are not errors, and
Disconnectedcarries the reason.
Public API freeze ahead of 1.0
- Event payloads are sealed (#1000, #1002 to #1004): 25 field-bearing payloads plus the notification and sync families are
#[non_exhaustive]with abonbuilder, three inlineEventvariants became sealed newtypes, and four unit markers became empty sealed structs.EventInterestmoved fromu64tou128. Payloads are now built withType::builder().build(). #[non_exhaustive]was added to public error enums, public value enums and lib-constructed response structs (#735, #736, #794), and dead privacy enums were dropped.- The bot API was overhauled (#852).
bot.run().await?.await?becomesbot.run().awaitin the foreground orbot.spawn()in the background, returning aBotHandlewithclient(), a gracefulshutdown()andabort().with_backend(arc)becomeswith_backend_arc,whatsapp_rust::transport::UreqHttpClientmoved towhatsapp_rust::http,bot::Missingwas replaced by named typestate markers, andBotBuilderError::Otheris gone. Registering two handlers now runs both, where the second used to silently replace the first. There are typed registrars (on_message,on_qr_code,on_pair_code,on_connected,on_logged_out) and aprelude. - One dependency line is enough (#852, #954):
wacore,wacore_binaryandwaprotoare re-exported wholesale. impl Into<Jid>across the public surface (#834), alloc-aware message-id parameter types (#775), aDownloadParamsstruct instead of six positional arguments (#768),get_participatingreturning aHashMap(#767), and taggedWireEnumvariants serialized as structs (#1096).
Persistence and state
sqlite-storagepersists blobs as protobuf instead of bincode (#911), through buffa once #557 landed on top of it.- messageSecret retention is bounded by policy and by an event-time horizon (#668).
- The Signal cache flushes on disconnect, which stops SKDM re-fanout (#670).
- App-state
Mutationno longer stores duplicate index and value MACs (#689), and previous-MAC lookups are batched (#687). FDownloadis a&BlobDownloadFntrait object instead of a generic parameter (#1055), which affectswacoreconsumers calling the app-state sync entry points directly.wa::Messageboxes its inline content variants (#866), so pattern matches that bound those fields by value need a deref.- Message edits are decrypted on receive (#665), and the inbound commit pipeline batches during the offline drain (#961), which changes when handlers observe drained messages.
Cargo features
- Removed:
moka-cache, which was in the default set, so a build pinningdefault-features = falseand listing it by name has to drop it (moka is gone entirely,PortableCacheis the only backend), anddebug-diagnostics. - Added:
voip,voip-runtime,voip-mlow,voip-libopus,voip-encoded,plugins,client-lifecycle,tracing,tracing-pii,metrics,legacy-session-interop,danger-skip-cert-chain-verify. - New workspace members:
storages/chat-store,plugins/metrics,examples/voip-cli. - MSRV is declared for the first time, at 1.94, and enforced in CI (#1093). 0.6.0 declared none.
prostis no longer in the dependency graph at all, which shows up in your lockfile and your license audit as well as at the call sites.
Tooling and CI
- CodSpeed benchmarks run on every PR, with deterministic RNG and hashers, a fixed 2-worker runtime and sharding (#828, #835, #898, #902, #950), plus benchmarks built from the stanza shapes production actually sends (#1186).
- Binary size has a per-PR budget gate and a historical series (#859).
- Supply chain, docs, MSRV and feature-matrix gates were added (#1093): workspace lints (
dbg_macroandtododenied),cargo-deny, a rustdoc gate and a per-feature build check. - Miri covers the unsafe decode path (#1162), the decoder has roundtrip property tests and an unmarshal fuzz target (#895), and fixed sleeps in tests were replaced with bounded polling (#1094).
- The test suites run through cargo-nextest (#1209), and the Docker image is multi-arch, runs unprivileged and is published to GHCR (#927).
Contributors
Thanks to everyone who shipped code into this release:
- @jlucaso1: VoIP (voice, video, group calls, the MLow codec), the buffa migration, the error and event API freeze, the plugin host, chat-store, tracing and metrics, and most of the performance, WA Web parity and durability work.
- @Salientekill: admin-revoke fan-out fix, prekey re-upload after re-pair,
groupStatusV2unwrapping, participant phone-number backfill,edit_message_with_stanza_id. - @blaueeiner: PDO placeholder-resend skips for view-once, PN-LID mappings from history sync, public
add_lid_pn_mapping, pushname matching, app-state collection reservation. - @Bot-Dev-RPA: removal of the obsolete device-registry cleanup task, VoIP relay port racing, sibling-device call handling.
- @zdanysfa:
<ack>recipient preservation and softened unknownstream:error, incoming peer message-edit decryption. - @arsa0x:
ContextInfoin media options. - @JeanCapixaba: the observe-only
ServerAckevent. - @oonid: own-device LID namespace alignment for LID-addressed DMs.
- @alexandme: Rust 1.93 build fix for the pushname arm.
- @dependabot: kept dependencies current across the release window.
- @codspeed-hq: the CodSpeed harness this release's performance numbers are measured on (#828).
New contributors
- @alexandme made their first contribution in #632
- @zdanysfa made their first contribution in #633
- @oonid made their first contribution in #636
- @arsa0x made their first contribution in #931
- @blaueeiner made their first contribution in #934
- @JeanCapixaba made their first contribution in #989
- @Bot-Dev-RPA made their first contribution in #1070
Full changelog: v0.6.0...v0.7.0, 488 PRs across VoIP, the protobuf migration, the pre-1.0 API work, performance, WA Web parity and reliability.
All PRs in this release (auto-generated, full attribution)
- feat!: migrate from prost to buffa for protobuf codegen by @jlucaso1 in #557
- fix(send): admin revoke not applied on recipient devices by @Salientekill in #621
- audit: WA Web protocol compliance fixes by @jlucaso1 in #623
- audit (round 2): more WA Web protocol compliance fixes by @jlucaso1 in #624
- fix(groups): correct change_number stanza shape by @jlucaso1 in #625
- feat(groups): capture display_name on participant info by @jlucaso1 in #626
- fix: align inbound parsing with WA Web for receipts and messages by @jlucaso1 in #627
- fix(send): emit correct / stanza for native-flow buttons by @jlucaso1 in #628
- fix(offline): drive WA Web pull-batch loop for offline backlog by @jlucaso1 in #629
- fix: zombie connection after stream-error 500 (ClientPayload + receipt compliance) by @jlucaso1 in #630
- fix(message): nack unrecoverable decrypt errors instead of silent drop by @jlucaso1 in #631
- fix(wacore): drop if-let guard so the pushname arm builds on Rust 1.93 by @alexandme in #632
- fix(client): preserve recipient in , soften unknown stream:error by @zdanysfa in #633
- fix: self-DM stops working, WA Web compliance for fanout and BadMac by @jlucaso1 in #634
- fix: self-DM/sibling decryption deadlock (retry shape + session recovery + peer pkmsg identity) by @jlucaso1 in #635
- fix(send): align own devices to LID namespace for LID-addressed DMs by @oonid in #636
- fix(prekeys): re-upload after re-pair to heal stale server bundle by @Salientekill in #641
- fix(polls): align poll vote encryption/decryption to conversation addressing by @jlucaso1 in #642
- feat(history-sync): server-error receipt to request blob re-upload by @jlucaso1 in #643
- feat(stickers): fetch first-party sticker pack data from the CDN by @jlucaso1 in #644
- feat(secret-encrypted): decrypt poll-edit / poll-add-option / event-edit envelopes by @jlucaso1 in #645
- fix(security): only honor self-only protocol messages from our own account by @jlucaso1 in #646
- fix(offline): drain offline queue by acking duplicate and undecryptable messages by @jlucaso1 in #647
- fix(offline): transport-ack stanzas with only unrecognized enc types by @jlucaso1 in #648
- fix(receipt): preserve sender device in delivery receipt
toby @jlucaso1 in #649 - feat(msmsg): decrypt Meta AI / fbid bot replies (
<enc type="msmsg">) by @jlucaso1 in #650 - fix(runtime): introduce Spawnable trait for WASM compatibility by @jlucaso1 in #651
- fix(send): fail DM send when every per-device encrypt fails by @jlucaso1 in #652
- fix(messages): pad to uniform 1..=16 bytes matching WA Web by @jlucaso1 in #653
- fix(send): classify poll-add-option as poll and album as text by @jlucaso1 in #654
- fix(send): hide decrypt-fail for conditional-reveal and poll-add-option by @jlucaso1 in #655
- fix(send): don't hide decrypt-fail on SenderRevoke by @jlucaso1 in #656
- fix(send): serialize the group sender-key chain per (group, sender) by @jlucaso1 in #657
- perf(retry): replace session-recreate Mutex with a TTL cache, atomic per-peer check+stamp by @jlucaso1 in #658
- fix(offline): clear self-fanout with sender receipt, not a bare ack by @jlucaso1 in #659
- perf(appstate): drop per-operand allocations in LTHash fold and update_hash by @jlucaso1 in #660
- perf(jid): add consuming into_non_ad for owned send-path JIDs by @jlucaso1 in #661
- perf(send): build encrypt-task Signal address from a borrow, not a Jid clone by @jlucaso1 in #662
- feat(transport): surface the disconnect reason in logs by @jlucaso1 in #663
- fix(message): ack SKDM-only session decrypts by @jlucaso1 in #664
- fix(message)!: decrypt secret encrypted edits on receive by @jlucaso1 in #665
- fix(send): set peer PDO push priority attrs by @jlucaso1 in #666
- fix(message): decrypt incoming peer message edits by @zdanysfa in #667
- feat(msg-secret)!: bound messageSecret retention by policy and event-time horizon by @jlucaso1 in #668
- perf(history-sync): free LazyHistorySync raw bytes after a successful decode by @jlucaso1 in #669
- fix(connection)!: flush Signal cache on disconnect to stop SKDM re-fanout by @jlucaso1 in #670
- ci(wasm): guard whatsapp-rust wasm32 build and fix two #668 regressions by @jlucaso1 in #671
- perf: implement streaming decompression for history sync processing by @jlucaso1 in #672
- perf(message): cut per-message allocation churn on the hot path by @jlucaso1 in #673
- perf(send): Arc immutable device fields + recent-message bytes by @jlucaso1 in #674
- perf(send): box the phash-mismatch cold path out of the spawned future by @jlucaso1 in #675
- perf(events): typed event subscription to skip boxing unwanted events by @jlucaso1 in #676
- perf(lid-pn): skip PN->LID session migration for peers with no PN state by @jlucaso1 in #677
- fix(send): correct group phash and mark full SKDM target set (WA Web parity) by @jlucaso1 in #678
- feat: WA Web phash parity — usync device_hash (#3), group-metadata phash (#7), bcl hash validation (#6) by @jlucaso1 in #679
- perf(usync): batch LID-PN re-learn from device response off the cold group-send path by @jlucaso1 in #680
- perf(device-registry): borrow lookup keys in get_devices_from_registry (hot group-send path) by @jlucaso1 in #681
- perf(device-registry): build lookup keys with CompactString (inline, no heap) by @jlucaso1 in #682
- perf(zlib): pool streaming InflateReader state across history-sync blobs by @jlucaso1 in #683
- feat(upload): constant-memory streaming upload + media streaming sidecar by @jlucaso1 in #684
- feat(upload): add encrypted_len() and UploadSource for Bytes by @jlucaso1 in #685
- perf(history-sync): single-byte fast-path for read_varint by @jlucaso1 in #686
- perf(appstate)!: batch previous-MAC lookups (N+1 to 1 query) by @jlucaso1 in #687
- perf(appstate): parse sync response once (+ dedup external-blob download) by @jlucaso1 in #688
- perf(appstate)!: drop duplicate index/value MAC storage from Mutation by @jlucaso1 in #689
- perf!: cut clones/allocs in LID resolution, single-device send, history-sync by @jlucaso1 in #690
- perf: cut copies in PBKDF2, noise large-frame send, history-sync secret records by @jlucaso1 in #691
- fix(send): unwrap groupStatusV2 + align unwrap_message with WA Web (not text) by @Salientekill in #692
- fix(send): classify payment-family stanzas as text + add stanza-type override by @jlucaso1 in #693
- fix(client): use portable_atomic::AtomicU64 in offline_resume by @jlucaso1 in #694
- feat(prekeys): make pre-key upload batch size configurable via the builder by @jlucaso1 in #695
- fix(send): hoist messageContextInfo to outer in DeviceSentMessage (WA Web parity) by @jlucaso1 in #696
- perf(send): cut throwaway allocations in DM phash and LID conversion by @jlucaso1 in #697
- fix(message): emit quote remoteJid only for cross-chat quotes by @jlucaso1 in #698
- chore(deps): bump yoke from 0.8.2 to 0.8.3 by @dependabot[bot] in #699
- chore(deps): bump log from 0.4.30 to 0.4.31 by @dependabot[bot] in #700
- perf(appstate): replace O(n²) in-patch overwrite scan with an O(1) map by @jlucaso1 in #701
- fix(retry): send raw 32-byte prekey/signed-prekey values in retry receipts by @jlucaso1 in #702
- perf(device-registry): cache Arc to avoid deep clone on warm hits by @jlucaso1 in #703
- fix(time): stop wall-clock default from panicking on wasm32 by @jlucaso1 in #704
- fix(retry): match WA Web's bot gate so bot DM retry receipts aren't dropped by @jlucaso1 in #705
- fix(prekeys): force the upload on prekey-low instead of re-querying the server count by @jlucaso1 in #706
- fix(blocking): resolve LID/PN before is_blocked compares, fixing PN-query false negatives by @jlucaso1 in #707
- fix(receipt): downgrade delivery ack to "sent" on lid feature-incapable error by @jlucaso1 in #708
- fix(retry): allocate retry-receipt prekey from the monotonic counter, not random by @jlucaso1 in #709
- perf(groups): cache Arc to avoid deep-cloning group metadata on warm sends by @jlucaso1 in #710
- fix(send): emit mediatype for interactive/list/order/product/native-flow sends by @jlucaso1 in #711
- perf(decrypt): trim per-SKDM allocations in the group fan-in path by @jlucaso1 in #712
- perf(signal): cache Arc to avoid deep-cloning the message-key backlog by @jlucaso1 in #713
- perf(store): batch session/identity/sender-key flush into one transaction per category by @jlucaso1 in #714
- feat(labels): add chat label create/delete/associate API with inbound sync by @jlucaso1 in #715
- refactor(appstate): drive syncd actions from a generated schema registry + public generic action API by @jlucaso1 in #716
- feat(signal): react to locally-detected peer identity changes by @jlucaso1 in #717
- perf(identity): gate identity-change reset behind had-prior-identity, like WA Web by @jlucaso1 in #718
- perf(events): snapshot handlers behind an Arc to drop the per-event Vec clone by @jlucaso1 in #719
- feat(reaction): add Client::send_reaction and MessageContext::react for DM/group by @jlucaso1 in #720
- perf(signal-cache): amortize eviction and stop scanning on reads by @jlucaso1 in #721
- fix(prekey): remove the consumed one-time prekey atomically with the session flush by @jlucaso1 in #722
- fix(edit): send message edits as a top-level protocolMessage, matching WA Web by @jlucaso1 in #723
- fix: @call JID decode, receipt participant_pn, profile-pic empty→remove, has_device churn by @jlucaso1 in #724
- feat(newsletter): plaintext channel edit/revoke + reject newsletter on the E2E send path by @jlucaso1 in #725
- chore(proto): sync to WhatsApp Web 2.3000.1040878135 by @jlucaso1 in #726
- feat(mex): typed mex operations from the whatspec IR, drop hand-maintained mex_ids by @jlucaso1 in #728
- feat(abprops): vendor typed A/B-props registry, drop hand-maintained config_codes by @jlucaso1 in #729
- fix(send): address LID-mapped DM by LID end to end so the server stops 400-rejecting it by @jlucaso1 in #731
- refactor: split message/client/send monoliths into per-theme modules by @jlucaso1 in #732
- feat(observability): optional tracing instrumentation (off by default, OTel-ready) by @jlucaso1 in #733
- feat(metrics): optional metrics layer (off by default, Prometheus/OTLP-ready) by @jlucaso1 in #734
- feat(api): mark public error enums #[non_exhaustive] for 1.0 forward-compat by @jlucaso1 in #735
- feat(api): #[non_exhaustive] on public value enums + drop dead privacy enums by @jlucaso1 in #736
- feat(receipt): add mark_as_played for voice/video notes by @jlucaso1 in #737
- feat(send): add forward_message + MessageExt::prepare_for_forward by @jlucaso1 in #738
- feat(groups): high-level set/remove group profile picture by @jlucaso1 in #739
- feat(send): add keep_message (keep-in-chat for everyone) by @jlucaso1 in #740
- feat(usync): surface verified business name (verified_name) by @jlucaso1 in #741
- feat(chat-actions): add save_contact (outgoing contact-name sync) by @jlucaso1 in #742
- feat(send): emit for view-once sends by @jlucaso1 in #743
- feat(receipt): read-receipt status parity (read-self, context, peer_participant_pn) by @jlucaso1 in #744
- feat(client): set_chat_disappearing_timer for 1:1 disappearing messages by @jlucaso1 in #745
- fix(binary): coerce "1"/"0" wire booleans in attr parsers by @jlucaso1 in #746
- feat(iq): keep server error_type + backoff on IQ error responses by @jlucaso1 in #747
- fix(appstate): require snapshot MAC when validating (no silent skip) by @jlucaso1 in #748
- fix(polls): match WA Web poll wire shape (pollContentType=TEXT, no vote metadata) by @jlucaso1 in #749
- perf(appstate): return Arc from key-lookup callback (no per-mutation 160B clone) by @jlucaso1 in #750
- fix(appstate): repair main build broken by #748/#750 merge by @jlucaso1 in #751
- feat(appstate): reject duplicate index within a patch (anti-tampering parity) by @jlucaso1 in #752
- feat(appstate): guard snapshot apply against version rollback by @jlucaso1 in #753
- feat(polls): support quiz polls on send (create_quiz) by @jlucaso1 in #754
- feat(chat): support clearChat app-state action (incoming + outgoing) by @jlucaso1 in #755
- fix(wasm): make cache backend target-aware so moka-cache defaults don't break wasm32 by @jlucaso1 in #756
- feat(newsletter): mute/unmute channel notifications by @jlucaso1 in #757
- feat(events): create and respond (RSVP) API by @jlucaso1 in #758
- fix(appstate): don't swallow external-blob download failures by @jlucaso1 in #759
- feat(chat): support userStatusMute app-state action (incoming + outgoing) by @jlucaso1 in #760
- fix(groups): keep persisted group metadata in sync on membership change by @jlucaso1 in #761
- feat(edit): support message-secret encrypted edits (secret_encrypted_message) by @jlucaso1 in #762
- perf(portable-cache): O(log n) remove_key instead of O(n) insertion scan by @jlucaso1 in #763
- feat(media): high-level media message builders from UploadResponse by @jlucaso1 in #764
- perf(cache): raise device_registry_cache default capacity 1000 -> 5000 by @jlucaso1 in #765
- fix(appstate): clear stale mutation MACs on snapshot re-sync by @jlucaso1 in #766
- refactor(groups): get_participating returns HashMap<Jid, GroupMetadata> by @jlucaso1 in #767
- refactor(download): take DownloadParams struct instead of 6 positional args by @jlucaso1 in #768
- fix(appstate): validate index MAC even when the decrypted index field is absent by @jlucaso1 in #769
- refactor(download): remove dead, full-buffering download_to_file by @jlucaso1 in #770
- refactor(polls): group enc_payload + enc_iv into PollVoteCiphertext by @jlucaso1 in #771
- feat(prekeys): validate companion device-identity (ADV) on fetched bundles by @jlucaso1 in #772
- fix(appstate): re-sync unsynced collection that gets patches without a snapshot by @jlucaso1 in #773
- perf(upload): slice ciphertext zero-copy instead of copying per attempt by @jlucaso1 in #774
- refactor(api): consistent, alloc-aware message-id param types by @jlucaso1 in #775
- feat(usync): surface device list from get_user_info by @jlucaso1 in #776
- fix(receipt): chunk read/played receipts into 256 ids per stanza by @jlucaso1 in #777
- refactor(groups): set_description prev takes Option<&str> by @jlucaso1 in #778
- perf(retry): peek the cached message on resend instead of take + re-add by @jlucaso1 in #779
- feat(receipt): expose the 'offline' attr on the Receipt event by @jlucaso1 in #780
- feat(send): emit member_label meta attrs (appdata + tag_reason) by @jlucaso1 in #781
- fix(noise): error on frame counter exhaustion instead of wrapping by @jlucaso1 in #782
- fix(iq): pong server pings with an absent type, not only type=get by @jlucaso1 in #783
- refactor(framing): drop dead, would-desync oversize check in decode_frame by @jlucaso1 in #784
- fix(conn): log benign server recycles quietly without hiding real errors by @jlucaso1 in #785
- perf(appstate): move snapshot mutations into the accumulator instead of extend by @jlucaso1 in #786
- perf(send): encode DM content once, splice into recipient + DSM plaintexts [PoC] by @jlucaso1 in #787
- perf(send): splice reporting context onto plaintexts, drop per-send Message clone by @jlucaso1 in #788
- fix(adv): fall back to stored account identity for ADV account_signature_key by @jlucaso1 in #790
- chore(session): remove dead SessionManager (zero production callers) by @jlucaso1 in #791
- perf(receive): make custom enc handlers an immutable set-once snapshot by @jlucaso1 in #792
- fix(wasm): relax EncHandler Send+Sync via MaybeSendSync, gate async_trait by @jlucaso1 in #793
- api: mark lib-constructed response/result structs #[non_exhaustive] for 1.0 by @jlucaso1 in #794
- fix(wasm): relax networking traits Send+Sync via MaybeSendSync by @jlucaso1 in #795
- refactor(handlers): split notification.rs god-file by domain by @jlucaso1 in #796
- fix(device-list): always keep the primary device after a raw_id mismatch patch by @jlucaso1 in #797
- fix(retry): recover from unknown-device retries that carry a key bundle by @jlucaso1 in #798
- fix(usync): refetch an empty device record instead of trusting it by @jlucaso1 in #799
- chore(send): log benign prekey-fetch skips at debug instead of warn by @jlucaso1 in #800
- fix(device-list): never drop the primary on a device-remove patch by @jlucaso1 in #801
- fix(retry): resync the device list on a retry from an unknown device by @jlucaso1 in #802
- perf(receive): adopt inbound payloads zero-copy in FrameDecoder by @jlucaso1 in #803
- perf(receive): resolve the noise socket once per read loop, drop ack re-encode copy by @jlucaso1 in #804
- perf(send): establish sessions before taking the sender-key chain lock by @jlucaso1 in #807
- perf(store): cache the device snapshot as Arc<Device> by @jlucaso1 in #808
- perf(signal-cache): share cached sessions via Arc, peek without deep clone by @jlucaso1 in #809
- perf(group): derive the PN-to-LID reverse index, stop persisting it by @jlucaso1 in #810
- perf(lid-pn): share identifier strings between cache keys and entries by @jlucaso1 in #811
- chore(deps): bump metrics-exporter-prometheus from 0.16.2 to 0.18.3 by @dependabot[bot] in #812
- chore(deps): bump chrono from 0.4.44 to 0.4.45 by @dependabot[bot] in #813
- chore(deps): bump http from 1.4.1 to 1.4.2 by @dependabot[bot] in #814
- chore(deps): bump prost from 0.14.3 to 0.14.4 by @dependabot[bot] in #815
- chore(deps): bump diesel from 2.3.9 to 2.3.10 by @dependabot[bot] in #816
- fix(protocol): tighten error handling gaps by @jlucaso1 in #817
- perf(appstate): move snapshot and patches into the blocking handoff instead of deep-cloning by @jlucaso1 in #818
- perf(binary): store small attribute lists inline, dropping the per-node heap allocation by @jlucaso1 in #819
- perf(receipt): aggregate offline delivery receipts per chat like WA Web by @jlucaso1 in #820
- perf(appstate): batch the previous-MAC prefetch in build_patch like the inbound path by @jlucaso1 in #821
- perf(send): hash the participant list from one arena instead of a String per device by @jlucaso1 in #822
- perf(send): probe the LID-PN map in one direction on warm device lookups by @jlucaso1 in #823
- perf(send): memoize the per-group device list behind a topology generation by @jlucaso1 in #824
- fix(contacts): use fn items for LID mapping extractors so boxed futures compile by @jlucaso1 in #826
- perf(client): borrow the ack id instead of allocating a String per stanza by @jlucaso1 in #827
- Add CodSpeed performance measurement setup by @codspeed-hq[bot] in #828
- fix(appstate): match WA Web index-mode ltHash for SET+REMOVE on the same index by @jlucaso1 in #829
- feat(messages): encrypted CAG reactions and channel comments, both directions by @jlucaso1 in #830
- perf(messages): write-behind buffer for messageSecret persistence by @jlucaso1 in #831
- fix(storage): serialize msg_secret reads through the db semaphore by @jlucaso1 in #832
- feat(prekeys): track the first un-uploaded prekey and reuse the window like WA Web by @jlucaso1 in #833
- feat(api): adopt the impl Into convention across the public surface by @jlucaso1 in #834
- ci(codspeed): run simulation and memory instruments in a single job by @jlucaso1 in #835
- perf(history-sync): gate prost decode behind a secret-presence scan, share chat ids, schema-pinned wire tags by @jlucaso1 in #836
- bench: measure the operation, not the harness by @jlucaso1 in #837
- perf(libsignal): memoize the sender signing key with a pre-warmed XEdDSA cache by @jlucaso1 in #838
- perf(libsignal): cache the verify-side Edwards derivations per sender key by @jlucaso1 in #839
- perf(send): memoize the group phash on the device-list memo entry by @jlucaso1 in #840
- fix(pdo): request a placeholder resend at most once per message by @jlucaso1 in #841
- perf(waproto): pin the Message codec to one instantiation via non-generic helpers by @jlucaso1 in #842
- perf(api): box the cold entry-point futures so consumers stop re-codegening the graphs by @jlucaso1 in #843
- perf(retry): fuse the retry count and reason into one cache entry by @jlucaso1 in #844
- perf(docker): enable -Zshare-generics in the image build by @jlucaso1 in #845
- perf(wacore): drop the proto PartialEq anchor from the skdm-only check by @jlucaso1 in #846
- perf(appstate): pre-key the ltHash HKDF extract once by @jlucaso1 in #847
- perf(binary): emit the Jid display as one write_str by @jlucaso1 in #848
- bench: borrow inputs in the benches that only read them by @jlucaso1 in #849
- perf(noise): pre-key the transport AES-GCM once per connection by @jlucaso1 in #850
- deps: upgrade curve25519-dalek and x25519-dalek to the 5.0/3.0 release candidates by @jlucaso1 in #851
- feat!: overhaul the public bot API ahead of 1.0 by @jlucaso1 in #852
- perf(history-sync)!: store the compressed payload and expose a streaming reader by @jlucaso1 in #853
- chore(reporting-token): draw the message secret from the thread RNG by @jlucaso1 in #855
- bench: cover the receive path — plaintext decode and appstate index-MAC dedup by @jlucaso1 in #856
- bench: cover four inbound/group hot paths for CodSpeed baselines by @jlucaso1 in #858
- ci: track binary size with a per-PR budget gate and historical series by @jlucaso1 in #859
- perf: drop moka, use PortableCache as the sole in-process cache backend by @jlucaso1 in #860
- perf(send): de-monomorphize Signal encrypt fan-out to dyn dispatch by @jlucaso1 in #861
- perf(iq): de-monomorphize send_and_wait_iq via boxed send future by @jlucaso1 in #862
- perf(signal): pre-key the zero-salt HKDF extract for message-key derivation by @jlucaso1 in #863
- perf(reporting-token): pre-key the zero-salt HKDF extract for token-key derivation by @jlucaso1 in #864
- refactor(appstate): scan instead of HashSet for index-mac dedup in the patch path by @jlucaso1 in #865
- perf(proto)!: shrink wa::Message ~75% by boxing inline content variants by @jlucaso1 in #866
- perf(appstate): index-sort dedup for large patches, O(n²) scan stays for small by @jlucaso1 in #868
- perf: drop a ~67 KiB duplicate prost decode tree + hoist a per-message traversal by @jlucaso1 in #869
- fix(retry): bound outbound resend rate per group to prevent AccountLocked by @jlucaso1 in #871
- fix(send): gate SKDM redistribution on the primary device (WA Web parity) by @jlucaso1 in #872
- perf(binary): length-bucketed token lookup (tiny_map) on the encode hot path by @jlucaso1 in #873
- perf(sqlite): skip the per-checkout SELECT 1 liveness probe by @jlucaso1 in #874
- feat(example): add 🦀send chat command by @jlucaso1 in #875
- perf(conn): reuse the shutdown listener across the read loop by @jlucaso1 in #876
- perf(signal): skip the rollback clone for in-order decrypts by @jlucaso1 in #877
- test(bench): add an in-order DM decrypt benchmark by @jlucaso1 in #878
- perf(signal): reuse the encrypt buffer instead of take + realloc by @jlucaso1 in #879
- perf(signal): share the sender-key message backlog behind an Arc by @jlucaso1 in #881
- feat(retry): WA Web log-level parity and retry-flow observability counters by @jlucaso1 in #887
- perf(signal): flush the signal cache without holding the device read-lock by @jlucaso1 in #888
- fix(retry): dedup registration-id parsing and reject oversized payloads by @jlucaso1 in #889
- chore(deps): update Cargo.lock to latest compatible versions by @jlucaso1 in #890
- chore: bump nightly toolchain to nightly-2026-06-16 by @jlucaso1 in #891
- refactor: move the demo binary to examples/ and make env_logger a dev-dependency by @jlucaso1 in #892
- refactor(error)!: replace anyhow in public APIs with per-domain typed errors by @jlucaso1 in #893
- ci: add an all-features build job and fix the --nocapture flag by @jlucaso1 in #894
- test(binary): add decoder roundtrip property tests and unmarshal fuzz target by @jlucaso1 in #895
- refactor(send): extract tc-token lifecycle and pin/revoke actions into submodules by @jlucaso1 in #896
- perf(send): resolve group SKDM warm gate with one inner-map lookup per device by @jlucaso1 in #897
- bench(integration): port integration benchmarks to CodSpeed (simulation + memory) by @jlucaso1 in #898
- chore(deps): prune the aes-gcm dev-dep and tidy dependency declarations by @jlucaso1 in #899
- perf(prekeys): avoid full record decode on the pre-key upload path by @jlucaso1 in #900
- perf(prekeys): stream prekey generation to cut the connect-time peak by @jlucaso1 in #901
- bench(integration): cut CodSpeed variance with a fixed 2-worker runtime + deterministic allocator by @jlucaso1 in #902
- perf(send): skip the unused DeviceSentMessage plaintext on companion-less DMs by @jlucaso1 in #903
- perf(send): share one message encode between the reporting token and DM plaintext by @jlucaso1 in #904
- perf(send): share one message encode between the group reporting token and skmsg plaintext by @jlucaso1 in #905
- ci(codspeed): drop the memory instrument from the integration benches by @jlucaso1 in #906
- feat(groups): backfill participant phone_number from LID-PN mapping by @Salientekill in #909
- chore(deps): cargo update by @jlucaso1 in #910
- refactor(sqlite-storage)!: replace bincode with prost for persisted blobs by @jlucaso1 in #911
- perf(size): size-optimize off-hot-path crates via per-package opt-level by @jlucaso1 in #912
- fix(atomics): use portable_atomic for 64-bit atomics + lint against std by @jlucaso1 in #913
- VoIP 1:1 calling by @jlucaso1 in #918
- feat: opt-in inbound durability hook (at-least-once delivery) by @jlucaso1 in #920
- chore(deps): update workspace dependencies to latest by @jlucaso1 in #921
- fix(build): isolate voip example so the demo build drops cpal/alsa-sys by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/922
- fix(status): omit addressing_mode on status@broadcast send by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/925
- perf(sqlite-storage): cut per-session memory & threads, with configurable tuning by @jlucaso1 in #926
- ci(docker): portable multi-arch image, unprivileged runtime, GHCR publish by @jlucaso1 in #927
- feat(passkey): SHORTCAKE_PASSKEY companion linking by @jlucaso1 in #928
- chore(deps): bump aes-gcm from 0.11.0-rc.4 to 0.11.0 by @dependabot[bot] in https://github.com/oxidezap/whatsapp-rust/pull/929
- feat(media): support ContextInfo in media options by @arsa0x in #931
- perf(binary): validate wire strings with smoothutf8 by @jlucaso1 in #932
- perf(binary): inflate into uninitialized buffer, drop the zero-init memset by @jlucaso1 in #933
- fix(receive): skip PDO placeholder-resend for view-once, ack instead by @blaueeiner in #934
- fix(receive): skip PDO placeholder-resend for bot and hosted unavailable too by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/935
- perf(send): trim group-send warm-path CPU and cold fan-out allocations by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/936
- perf(send): single-flight cold group sender-key distribution by @jlucaso1 in #937
- perf(send): keep send_message's future pointer-sized by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/938
- fix(send): gate DM LID wire addressing on the account's 1:1 migration state by @jlucaso1 in #943
- perf(history-sync): size the secret-record accumulator by sampled density by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/945
- perf(libsignal): evict skipped message keys without shifting the buffer by @jlucaso1 in #946
- perf(history-sync): keep heap-error types off the scanner happy path by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/947
- perf(send): keep public send futures pointer-scale by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/948
- perf(binary): keep BinaryError construction off the decoder happy path by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/949
- bench: deterministic rng and hashers; pin and shard the CodSpeed CI by @jlucaso1 in #950
- tracing: tag wa.iq / wa.send.message / wa.conn.run spans with account identity by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/951
- perf: keep droppy error/default construction off per-message happy paths by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/952
- perf(libsignal): store the sender-key backlog as Copy (iteration, seed) pairs by @jlucaso1 in #953
- api: re-export the crates whose types appear in the public API by @jlucaso1 in #954
- perf: inline index-MAC keys, reusable conversation decode, single-encode send by @jlucaso1 in #955
- fix!: typed read-loop exit — routine server recycles are not errors; Disconnected carries the reason by @jlucaso1 in #956
- perf(voip): zerocopy the RTP/STUN fixed-layout parse; borrow STUN attr values by @jlucaso1 in #957
- perf(connect): move own-device sync off the pre-active path; drop keepalive loop span by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/958
- perf(tracing): drop client-lifetime wa.conn.run span by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/959
- fix: shut down on SIGTERM, not just SIGINT (docker stop timeout) by @jlucaso1 in #960
- feat(recv)!: batch the inbound commit pipeline during the offline drain by @jlucaso1 in #961
- Per-session metrics: wire I/O counters, memory report in bytes, runtime-agnostic task instrumentation by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/962
- Meter Bot::run's main future through the task instrument by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/963
- fix(stats): make Client::memory_report() Send by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/964
- feat: WA Web parity fixes (offline drain, crypto caps, reconnect, groups) by @jlucaso1 in #965
- fix(tctoken): persist issuance timestamp on IQ success and gate cstoken independently by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/966
- feat(stats): attribute per-session resources beyond the Client by @jlucaso1 in #967
- feat: rotate signed pre-key on a cadence (WA Web RotateKeyJob) by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/968
- feat(tctoken): attach tctoken in usync status/about and spam-report IQs by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/969
- feat(tctoken): attach and issue tctoken on outgoing VoIP call offers by @jlucaso1 in #970
- feat: gate DM read/played receipts on readreceipts privacy by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/971
- fix(waproto): stop the build script recompiling on every run by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/973
- fix(appstate): bound pairing key-share wait by the 180s critical deadline by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/974
- perf: parallelize remaining serial/blocking hot paths (startup, media, send/recv) by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/975
- fix(pair-code): correct link_code_pairing_nonce byte and close WA Web stage-2 gaps by @jlucaso1 in #976
- fix(iq): cancellation-safe IQ response waiters (unblocks try_join!) + named fan-out consts by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/978
- fix(pair-code): canonicalize companion_platform_display OS to a server-safe set by @jlucaso1 in #979
- fix(tc-token): atomic newer-wins store; drop tc_token_lock and close the cross-source race by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/980
- feat(events): opt-in ordered + bounded inbound event delivery by @jlucaso1 in #981
- perf(recv): hold the per-sender session lock only around Signal decrypt by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/983
- feat(retry): opt-in RetryAdmission hook (compliant supersede of #982) by @jlucaso1 in #985
- fix(recv): retry (not NACK) recoverable group skmsg decrypt failures by @jlucaso1 in #986
- fix(recv): retry (not NACK) InvalidSignedPreKeyId on the 1:1 decrypt path by @jlucaso1 in #987
- fix(appstate): validate aggregate snapshot/patch MACs for genesis patches by @jlucaso1 in #988
- feat(events): observe-only ServerAck event for server stanzas by @JeanCapixaba in #989
- fix(send): lock per-device sessions across the group SKDM fan-out by @jlucaso1 in #990
- fix(cache): don't capacity-evict a session lock a task still holds by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/991
- fix(recv): serialize the group inbound sender-key chain with a lock by @jlucaso1 in #992
- fix(binary): bound node-decode recursion depth to reject hostile frames by @jlucaso1 in #994
- fix(keepalive): anchor dead-socket watchdog to first send, not last by @jlucaso1 in #995
- fix(send): isolate a group device's session-setup failure from the cohort by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/996
- fix(passkey): don't skip the verification-code UX on a fresh link by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/997
- fix(voip): authenticate WARP MI tag before folding recv ROC state by @jlucaso1 in #998
- fix(send): never memoize own devices in the sender-key map (WA Web parity) by @jlucaso1 in #999
- refactor(events): model ServerAck.class as Option, document payload stability by @jlucaso1 in #1000
- chore(proto): bump WhatsApp protocol surface to 2.3000.1042742319 by @jlucaso1 in #1001
- refactor(events): seal ServerAck with non_exhaustive + bon builder by @jlucaso1 in #1002
- refactor(events): seal notification, sync event payloads (non_exhaustive + bon builder) by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1003
- refactor(events): complete the event-payload API freeze by @jlucaso1 in #1004
- chore(deps): update dependencies to latest versions by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1009
- feat(history-sync): learn PN-LID mappings from phoneNumberToLidMappings by @blaueeiner in #1010
- feat(lid-pn): source-aware write policy matching WA Web createLidPnMappings by @jlucaso1 in #1011
- feat(lid-pn): make add_lid_pn_mapping pub for embedder-learned sources by @blaueeiner in #1013
- feat(chat-store): SQLite-backed chat/message history store by @jlucaso1 in #1014
- perf(message): reduce hot-path allocations by @jlucaso1 in #1015
- perf(receipt): persistent worker for live delivery receipts by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1016
- perf(signal): sync fast paths for hot store adapter methods by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1017
- perf(node): cut ack re-encode, exact stanza sizing, warm session pre-filter by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1018
- perf(send): dispatch send_message_impl to per-branch boxed futures by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1019
- perf(binary): inline the exact-marshal string hint cache by @jlucaso1 in #1020
- perf(group): keep warm sends warm under the own-device SKDM steady state by @jlucaso1 in #1021
- perf(signal): coalesce receive flushes and persist outbound state pre-wire by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1022
- VoIP 1:1 video calls by @jlucaso1 in #1024
- perf(client): trim per-message allocations on the send/receive hot path by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1025
- perf(signal): lease outbound counters in batches instead of flushing every send by @jlucaso1 in #1026
- fix(signal): gate the group sender-key advance before the wire by @jlucaso1 in #1027
- ci: cache target dir and drop incremental to stop full recompiles by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1033
- chore(deps): update workspace dependencies to latest compatible versions by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1034
- fix(signal): persist retry advances before wire by @jlucaso1 in #1041
- fix(signal): retain durability gates through deletes by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1042
- fix(signal): serialize sender-key mutations by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1043
- fix(signal): recover cancelled session checkouts by @jlucaso1 in #1044
- fix(message): preserve active chat lanes by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1045
- ci: reclaim runner disk before tests by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1047
- perf(signal): reuse leases across ciphertext APIs by @jlucaso1 in #1048
- test(signal): add deterministic durability chaos coverage by @jlucaso1 in #1049
- feat(voip): add encoded audio pipeline and native Opus negotiation by @jlucaso1 in #1050
- fix(voip): prevent stale audio-to-video upgrades by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1051
- fix(appstate): recover missing keys across companion devices by @jlucaso1 in #1052
- feat(proto): upgrade buffa to 0.9 and open SyncdOperation by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1053
- perf(core): reduce allocation churn across sync and crypto paths by @jlucaso1 in #1054
- perf(size): -1.47 MiB (-13.3%) stripped binary — build-config levers + control-plane demonomorphization by @jlucaso1 in #1055
- perf(size): token lookup via static hash table — −29 KiB, faster than hashify on hits and marshal, dep dropped by @jlucaso1 in #1056
- perf: marshal_exact 3× faster — replay plan-pass hints instead of reclassifying every string by @jlucaso1 in #1057
- perf(core): reduce history sync and decrypt allocation churn by @jlucaso1 in #1058
- perf(send): reduce DM allocation and serialization churn by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1059
- feat(core): expand protocol metadata and shared primitives by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1060
- feat(plugins): add extensible client architecture by @jlucaso1 in #1061
- feat(core): expose signal record components and dirty events by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1062
- feat(core): add typed USync query engine by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1063
- feat(core): expose typed stanza responses and retries by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1069
- fix(client): remove obsolete device-registry cleanup task by @Bot-Dev-RPA in #1070
- feat(send): add targeted retransmission controls by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1071
- feat(signal): add typed legacy session interop by @jlucaso1 in #1072
- feat(sqlite-storage): add connection-init hook before pragmas and migrations by @jlucaso1 in #1074
- chore(deps): update all workspace dependencies to latest by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1075
- fix(contacts): short-circuit user-directed IQs for the system JID by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1080
- feat(messages): surface business verified name from the message envelope by @jlucaso1 in #1081
- feat(chat-store): classify business template/buttons/list/interactive messages by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1082
- fix(chat-store): resolve PN/LID aliases so receipts reach their rows by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1083
- feat(messaging): add edit_message_with_stanza_id to override the outer stanza id by @Salientekill in https://github.com/oxidezap/whatsapp-rust/pull/1084
- chore(deps): update workspace dependencies to latest by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1085
- perf(cache): non-generic single-flight registry + boxed-on-miss init futures by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1086
- chore: remove dead public API surface from wacore and libsignal by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1087
- fix(concurrency): cancellation-safe app-state sync dedup and message-secret backpressure by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1088
- refactor(api): rustdoc for entry types, must_use, root re-exports, and constructor consistency by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1089
- refactor(errors): typed ConnectError and friends for the public API by @jlucaso1 in #1090
- feat(waproto): pinned HistorySync encode wrappers in codec by @jlucaso1 in #1091
- feat(wacore): stable ReceiptType variant-name accessor backing Serialize by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1092
- ci: workspace lints, cargo-deny, rustdoc gate, MSRV, and feature-matrix checks by @jlucaso1 in #1093
- test: replace fixed sleeps with bounded polling and add negative coverage for server-controlled parsers by @jlucaso1 in #1094
- refactor(derive): serialize tagged WireEnum variants as structs by @jlucaso1 in #1096
- fix(groups): send the previous description id when updating a group description by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1097
- fix(chat-store): key receipts and contacts by the peer's bare identity by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1099
- refactor(errors): make the public error surface recoverable without string matching by @jlucaso1 in #1100
- fix(recv): handle and acknowledge top-level status stanzas by @jlucaso1 in #1101
- fix(voip): dial the relay endpoint on the web client port by @jlucaso1 in #1102
- perf(stats): stop dating every wire frame for a field nothing reads by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1103
- fix(voip): race the relay's advertised and web-client ports for media by @Bot-Dev-RPA in #1104
- perf(send): stamp one message from one clock read by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1106
- fix(voip): a busy device must not end an outgoing call for its siblings by @Bot-Dev-RPA in #1107
- docs(agents): correct stale agent docs and add a WA Web verification path by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1109
- ci: skip the mock-server jobs on fork PRs instead of failing their template by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1110
- chore(voip/mlow): make the decoder cross-check vectors regenerable by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1112
- perf: cut two per-message allocations on the pingpong hot path by @jlucaso1 in #1114
- perf: remove four per-message tasks and buffers from the send/receive round trip by @jlucaso1 in #1116
- fix(socket): stop sending after a transport failure instead of reusing the nonce by @jlucaso1 in #1117
- perf(send): memoize the DM device fan-out per recipient by @jlucaso1 in #1118
- perf(socket): coalesce queued noise frames into one transport write by @jlucaso1 in #1119
- perf(client): send queued acks and receipts as one burst by @jlucaso1 in #1120
- perf(socket): seal each noise frame where it lands in the batch buffer by @jlucaso1 in #1121
- perf: cut a dozen per-message allocations from the DM round trip by @jlucaso1 in #1122
- perf: answer three store calls without boxing a ready future by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1124
- chat-store: record locally-originated amendments by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1126
- fix(chat-store): reconcile outgoing timestamps from server acks by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1127
- fix(voip): send callee answer signaling by @jlucaso1 in #1128
- ci: centralize and pin bartender image by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1129
- feat(voip): add group calls and call links by @jlucaso1 in #1130
- perf: five cuts to the per-message allocation count by @jlucaso1 in #1131
- perf(noise): keep the frame decoder's buffer instead of giving it away by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1136
- perf: four more cuts to the per-message allocation count by @jlucaso1 in #1137
- Two follow-ups: the burst's other half, and a DM 406 that went nowhere by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1139
- fix: six chat-store and send-path issues by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1144
- fix(signal): stop a DH ratchet stranding the counter lease by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1149
- perf(storage): let WAL readers run, and stop search from monopolizing them by @jlucaso1 in #1151
- fix(signal): store pre-key public keys in one encoding by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1152
- fix(prekeys): act on the device a rejected fetch names by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1153
- fix(chat-store): keep receipt times for 1:1 chats, per state by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1155
- fix(appstate): let a diverged collection converge, and stop losing 409'd patches by @jlucaso1 in #1158
- ci(miri): check the unsafe decode path under the interpreter by @jlucaso1 in #1162
- fix(pair-code): keep a phone-number link alive past the QR rotation by @jlucaso1 in #1163
- fix(device-props): stop asking every pairing for a full history sync by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1164
- fix(conn): stop dropping the failure stanza on logout, ban and outdated by @jlucaso1 in #1165
- fix(transport): send the Origin header on the WebSocket upgrade by @jlucaso1 in #1166
- perf(jid): stop the scan at the
@and resolve the server once by @jlucaso1 in #1171 - perf(jid): parse the device and agent fields with a decimal-only reader by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1172
- perf(jid): stop re-validating UTF-8 the writer just assembled by @jlucaso1 in #1173
- perf(node): iterate children by tag without going through Flatten by @jlucaso1 in #1174
- perf(attrs): read required attributes with a single lookup by @jlucaso1 in #1175
- perf(jid): compare structured JID attributes without rendering them by @jlucaso1 in #1176
- fix(jid): stop keeping the AD-JID domain byte as an agent by @jlucaso1 in #1178
- fix(lifecycle): race the reconnect backoff against the terminal shutdown by @jlucaso1 in #1179
- fix(jid): make agent identity, the AD form, and device dedup agree by @jlucaso1 in #1182
- perf(jid): skip the agent normalisation when the raw agents already match by @jlucaso1 in #1183
- fix(jid): encode interop JIDs with the token that carries their integrator by @jlucaso1 in #1184
- bench(send): measure the shapes production actually sends by @jlucaso1 in #1186
- perf(libsignal): stop revalidating UTF-8 the address buffer just wrote by @jlucaso1 in #1187
- fix(media): let a CDN's non-2xx status reach the download classifier by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1188
- perf(messages): draw the pad length from the thread RNG by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1189
- feat(pair-code): report a refused pair-code request to the consumer by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1191
- perf(secret-enc): draw the addon IV from the thread RNG by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1192
- feat(download): allow media download without a connected session by @jlucaso1 in #1194
- feat(errors): make a refused HTTP status recoverable by type by @jlucaso1 in #1195
- fix(download): guarantee download_to_writer leaves only verified media by @jlucaso1 in #1197
- fix(pair-code): read the companion_finish answer instead of assuming it by @jlucaso1 in #1198
- chore(deps): update workspace dependencies to latest by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1199
- refactor(deps): drop redundant crates and unused dependency features by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1200
- build(deps): drop three dependency features nothing activates by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1201
- fix(iq): report detail the IQ parser drops, once per process by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1202
- fix(history-sync): match our own pushname entry by JID user by @blaueeiner in https://github.com/oxidezap/whatsapp-rust/pull/1203
- fix(appstate): reserve the collection for an AppStateSync task by @blaueeiner in https://github.com/oxidezap/whatsapp-rust/pull/1205
- docs(appstate): correct the batched-sync iteration cap comment by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1206
- fix(appstate): report what a batched sync actually achieved by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1207
- fix(appstate): unbreak the bootstrap gate and read the right lifecycle signals by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1208
- ci(test): run the suites through cargo-nextest by @jlucaso1 in #1209
- fix(libsignal): keep skipped message-key seeds projectable by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1210
- feat(libsignal): let a consumer opt out of counter leasing by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1211
- bench(libsignal): measure what the sender-key XEdDSA memo is worth by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1212
- feat(libsignal): let a caller prewarm the sender-key derivation memo by @jlucaso1 in #1213
- perf(binary): unpack packed values through a byte-pair table by @jlucaso1 in #1214
- perf(binary): validate packed output with the wire path's validator by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1215
- perf(binary): drop the per-node box around NodeRef content by @jlucaso1 in #1216
- feat(libsignal): let a consumer provide the X25519 agreement by @jlucaso1 in https://github.com/oxidezap/whatsapp-rust/pull/1218