1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Provider-neutral push delivery with an Expo adapter.
//!
//! The crate separates a small [`PushSender`] port from its [`ExpoPushSender`]
//! adapter. Domain code builds [`PushMessage`] values and reads [`PushOutcome`]
//! values; nothing above the port names a provider. Scheduling, quiet hours,
//! and deciding who gets notified stay in the product.
//!
//! # Two-phase delivery
//!
//! Expo answers a send with a *ticket* per notification, then confirms delivery
//! later through a *receipt*. [`ExpoPushSender`] runs both phases per batch, so
//! one call returns [`PushDeliveryStatus::Delivered`] or
//! [`PushDeliveryStatus::Rejected`] wherever Expo has settled, and
//! [`PushDeliveryStatus::Accepted`] where it has not. Never resend on
//! `Accepted`; the notification is in flight.
//!
//! # Pruning dead tokens
//!
//! A device token stops working once the app is uninstalled. Expo reports that
//! as `DeviceNotRegistered`, which becomes
//! [`PushRejection::DeviceNotRegistered`]. Delete those tokens after every
//! send, or the same failures repeat forever:
//!
//! ```rust
//! use baukit_push::{PushOutcome, PushSender};
//!
//! async fn deliver(
//! sender: &impl PushSender,
//! messages: Vec<baukit_push::PushMessage>,
//! ) -> Result<Vec<String>, baukit_push::PushError> {
//! let outcomes = sender.send(messages).await?;
//! Ok(outcomes
//! .iter()
//! .filter(|outcome| PushOutcome::is_token_dead(outcome))
//! .map(|outcome| outcome.token.clone())
//! .collect())
//! }
//! ```
//!
//! # Retries
//!
//! Whole-request failures arrive as [`PushError::Transport`] carrying a
//! [`baukit_http::RetryClass`], so an Expo rate limit with a `Retry-After`
//! header reaches the caller as a concrete delay through
//! [`PushError::retry_after`]. Per-notification refusals are not errors:
//! inspect [`PushRejection::is_retryable`] on each outcome instead.
pub use ;
pub use ExpoPushSender;
pub use FakePushSender;
pub use ;
// Compiles the README's examples so they cannot drift from the API.
;