-
Notifications
You must be signed in to change notification settings - Fork 0
docs: update for bot API overhaul (whatsapp-rust#852) #322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
aa29e85
docs: update for bot API overhaul (whatsapp-rust#852)
claude 2bd04f2
fix: address review comments on bot-api-overhaul docs
claude 3a6adeb
fix: address cubic review findings
claude d206aad
docs(changelog): address review nitpicks in bot-api-overhaul entry
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| --- | ||
| title: "June 11, 2026 — Bot API overhaul (breaking)" | ||
| description: "Lifecycle simplification, typed event registrars, single-dependency consumption, and messaging sugar ahead of 1.0." | ||
| --- | ||
|
|
||
| PR [#852](https://github.com/oxidezap/whatsapp-rust/pull/852) is a focused breaking-change pass over the public bot API while such changes are still cheap. You will need to migrate your code, but the migration is mechanical. See the [breaking changes](#breaking-changes) section below. | ||
|
|
||
| ## New features | ||
|
|
||
| ### One dependency is enough | ||
|
|
||
| `whatsapp-rust` now re-exports `wacore`, `wacore_binary`, and `waproto` wholesale. A consumer needs exactly one `Cargo.toml` line: | ||
|
|
||
| ```toml | ||
| [dependencies] | ||
| whatsapp-rust = "0.6" | ||
| tokio = { version = "1", features = ["macros", "rt-multi-thread"] } | ||
| ``` | ||
|
|
||
| All sub-crate paths (`whatsapp_rust::wacore::...`, `whatsapp_rust::waproto::whatsapp`, etc.) are reachable through the main crate, including when pinning a git revision. | ||
|
|
||
| `UreqHttpClient` moved from the misplaced `whatsapp_rust::transport` to `whatsapp_rust::http`. A new `whatsapp_rust::prelude` covers the common bot path in one import line (including `wa` as the protobuf alias): | ||
|
|
||
| ```rust | ||
| use whatsapp_rust::prelude::*; | ||
| ``` | ||
|
|
||
| ### Simplified lifecycle | ||
|
|
||
| `Bot::run(self)` now runs the bot on the current task with a **single** `await`. `Bot::spawn(self)` starts it in the background and returns a `BotHandle`: | ||
|
|
||
| ```rust | ||
| // Foreground — blocks until logout or disconnect | ||
| bot.run().await; | ||
|
|
||
| // Background — returns immediately | ||
| let handle = bot.spawn(); | ||
| let client = handle.client(); // full Client API | ||
| handle.shutdown().await; // graceful: flushes state, then stops | ||
| handle.abort(); // escape hatch, skips flush | ||
| ``` | ||
|
|
||
| Awaiting a `BotHandle` resolves to `()` (was `Result<(), Canceled>`). Dropping the handle still aborts the task — the e2e harness relies on this. | ||
|
|
||
| ### Builder defaults | ||
|
|
||
| With the default cargo features, transport, HTTP client, and runtime are pre-filled (Tokio WebSocket, ureq, Tokio), so only the backend has to be provided: | ||
|
|
||
| ```rust | ||
| let bot = Bot::builder() | ||
| .with_backend(SqliteStore::new("whatsapp.db").await?) | ||
| .build() | ||
| .await?; | ||
| ``` | ||
|
|
||
| `with_*` setters are now available in every typestate, so they also work as overrides. The typestate markers got names (`MissingBackend`, `MissingTransport`, `MissingHttpClient`, `MissingRuntime`) — a missing-field compile error now names which field is missing. | ||
|
|
||
| `with_backend` accepts `impl Backend + 'static` (no caller-side `Arc::new`). `with_backend_arc` accepts an already-shared `Arc<dyn Backend>`. | ||
|
|
||
| ### Typed event registrars | ||
|
|
||
| Dedicated builder methods cover the common event path — no `match &*event` needed: | ||
|
|
||
| ```rust | ||
| Bot::builder() | ||
| .on_message(|ctx| async move { | ||
| // ctx: MessageContext — has reply, reply_quoting, react, send_message | ||
| }) | ||
| .on_qr_code(|code, timeout| async move { /* ... */ }) | ||
| .on_pair_code(|code, timeout| async move { /* ... */ }) | ||
| .on_connected(|client| async move { /* ... */ }) | ||
| .on_logged_out(|info| async move { /* ... */ }) | ||
| ``` | ||
|
|
||
| `on_event` / `on_event_for` are unchanged as catch-alls. `with_event_handler` registers a struct-based `EventHandler` directly on the bus for stateful handlers (eliminates the clone-dance that closure captures force on consumers). | ||
|
|
||
| All handlers **accumulate** — registering a second handler now runs both instead of silently replacing the first. | ||
|
|
||
| The bus still skips materializing events nobody wants: the adapter registers the union of all handler interests and filters per handler at dispatch. | ||
|
|
||
| ### Messaging sugar | ||
|
|
||
| New helpers for the common send paths: | ||
|
|
||
| ```rust | ||
| // On MessageContext (inside on_message) | ||
| ctx.reply("pong").await?; | ||
| ctx.reply_quoting("pong").await?; | ||
|
|
||
| // On Client | ||
| client.send_text(&jid, "hello").await?; | ||
|
|
||
| // Static constructors on wa::Message (via MessageBuilderExt) | ||
| use whatsapp_rust::prelude::*; | ||
| let msg = wa::Message::text("hello"); | ||
| let msg_with_quote = wa::Message::text_with_context("hello", ctx.build_quote_context()); | ||
| ``` | ||
|
|
||
| The raw `ctx.send_message(wa::Message { ... })` path is unchanged for advanced cases. | ||
|
|
||
| ### `BotBuilderError` typed | ||
|
|
||
| `BotBuilderError::Other(anyhow)` is gone. The only variant is now `Store(StoreError)` — the one error `build()` can actually produce. | ||
|
|
||
| ## Breaking changes | ||
|
|
||
| | Old | New | | ||
| |---|---| | ||
| | `bot.run().await?.await?` | `bot.run().await` (foreground) or `let handle = bot.spawn()` (background) | | ||
| | `.with_backend(Arc::new(store))` | `.with_backend(store)` — `Arc` wrapping is internal | | ||
| | `.with_backend(arc)` for a shared Arc | `.with_backend_arc(arc)` | | ||
| | `use whatsapp_rust::transport::UreqHttpClient` | `use whatsapp_rust::http::UreqHttpClient` | | ||
| | `bot::Missing` typestate marker | `bot::MissingBackend` / `MissingTransport` / `MissingHttpClient` / `MissingRuntime` | | ||
| | `BotBuilderError::Other(anyhow)` | removed; only `BotBuilderError::Store(StoreError)` | | ||
| | Registering two handlers — second replaces first | Both run; handlers accumulate | | ||
|
|
||
| ### Migration guide | ||
|
|
||
| **Lifecycle:** | ||
| ```rust | ||
| // Before | ||
| let mut bot = builder.build().await?; | ||
| let handle = bot.run().await?; | ||
| handle.await?; | ||
|
|
||
| // After (foreground) | ||
| let bot = builder.build().await?; | ||
| bot.run().await; | ||
|
|
||
| // After (background / ctrl-c handling) | ||
| let bot = builder.build().await?; | ||
| let handle = bot.spawn(); | ||
| tokio::signal::ctrl_c().await?; | ||
| handle.shutdown().await; | ||
| ``` | ||
|
|
||
| **Backend:** | ||
| ```rust | ||
| // Before | ||
| let backend = Arc::new(SqliteStore::new("whatsapp.db").await?); | ||
| Bot::builder().with_backend(backend) | ||
|
|
||
| // After | ||
| Bot::builder().with_backend(SqliteStore::new("whatsapp.db").await?) | ||
|
|
||
| // After (already-shared Arc) | ||
| Bot::builder().with_backend_arc(existing_arc) | ||
| ``` | ||
|
|
||
| **`UreqHttpClient` import:** | ||
| ```rust | ||
| // Before | ||
| use whatsapp_rust::transport::UreqHttpClient; | ||
|
|
||
| // After | ||
| use whatsapp_rust::http::UreqHttpClient; | ||
| ``` | ||
|
|
||
| **Builder dependencies — drop sibling crates from `Cargo.toml`:** | ||
| ```toml | ||
| # Before (all required) | ||
| whatsapp-rust = "0.6" | ||
| whatsapp-rust-sqlite-storage = "0.6" | ||
| whatsapp-rust-tokio-transport = "0.6" | ||
| whatsapp-rust-ureq-http-client = "0.6" | ||
| wacore = "0.6" | ||
| waproto = "0.6" | ||
|
|
||
| # After (one line is enough) | ||
| whatsapp-rust = "0.6" | ||
| tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] } | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.