New features
Bot message decryption (msmsg) Meta AI and other fbid bot replies are now decrypted automatically and dispatched as a normalEvent::Message. No special handling required — just listen for messages as usual. See the Signal API reference.
Constant-memory streaming uploads
Audio and video uploads can now stream from disk without loading the full file into memory, and produce a per-64 KiB HMAC sidecar that enables progressive playback for recipients. Ideal for large media on memory-constrained hosts. See Upload.
Inline edit decryption
Secret-encrypted edits (message edits, poll edits, event edits, and poll-add-option) are now decrypted automatically on receive. Most apps no longer need to call the manual decryption helpers. See Polls.
Typed event subscriptions
Event handlers can now declare which event kinds they care about via EventHandler::interest() and on_event_for(&[EventKind], …), letting the runtime skip work for events you don’t consume. See Events and Bot.
messageSecret retention policy
A new configurable retention policy (Managed, BotOnly, Full, Disabled) controls how long messageSecret values are kept per message class, with sensible defaults (30d / 90d / 30d). History seeding and a fallback resolver are also available. See Bot.
Updates
Longer retry receipt window The defaultsent_message_ttl_secs has been bumped from 5 minutes to 2 hours so retry receipts from slow or briefly offline recipients still resolve to the original message.
Persisted sender-key chains on disconnect
disconnect() now flushes the Signal cache to your backend before clearing it, so advanced sender-key chains survive reconnects and avoid unnecessary SKDM re-fanouts.
Renamed ConnectFailureReason::MainDeviceGone → AccountLocked
Matches WhatsApp Web’s REASON_LOCKED (HTTP 403) and better reflects the actual condition. Update any match arms accordingly.
TransportEvent::Disconnected now carries a reason
Custom transports now report DisconnectReason (ServerClose, StreamEnded, ReadError, or Unknown) so reconnect logic can branch on cause. This is a breaking change for custom Transport implementations — see Transport and Custom backends.
Batched app-state mutation MACs
AppSyncStore::get_mutation_macs provides a batched lookup that backends can override with a SQL IN query, eliminating an N+1 during app-state sync. See Store.
CompactString for LID lookups
get_current_lid and SendContextResolver::get_lid_for_phone now return Option<CompactString> instead of Option<String> for lower allocation pressure. See Storage.
Spawnable marker trait
A new Spawnable marker (Send + 'static on native, 'static on wasm32) makes generic spawn helpers easier to write across targets. See Custom backends.
WhatsApp Web parity
- Uniform plaintext padding (1..=16 bytes) replaces the previous biased scheme.
- Full device set included on every send for participant-hash calculation, with standard base64 alphabet and persisted group metadata for not-modified group queries.
- Sender-key chains are now serialized per
(group, sender)pair. - DM sends now fail fast when every per-device encrypt fails instead of silently producing an empty stanza.
- Stanza classification fixes:
poll-add-optionis classified aspoll, andalbumastext. unwrap_messagenow peels a wider set ofFutureProofMessagewrappers (includinggroupStatusV2andspoiler).
Bug fixes
decrypt-fail=hide coverage
conditional_reveal_message, secret_encrypted_message, and PollAddOption are now correctly hidden on decrypt failure, and SenderRevoke is excluded from hide alongside AdminRevoke.
Peer edit sender resolution
MessageEdit events from peers now resolve the original sender from the envelope rather than the edit target, fixing mis-attribution on multi-device accounts.
Session-recreate cooldown is bounded
The session-recreate history is now a bounded TTL cache (~256 entries, 1h) with atomic per-peer check-and-stamp, so long-running clients no longer accumulate unbounded state. Per-peer cooldown behavior is unchanged.
SKDM-only decrypt acking
Sender-key distribution-only decrypts are now acked so they drain from the offline queue instead of being redelivered.