wavekat_platform_client/error.rs
1//! Public error type for the crate.
2//!
3//! Library convention: typed variants so consumers can `match` on the
4//! failure mode (network vs. HTTP status vs. OAuth state mismatch).
5//! End-user binaries can `?` these into their own `anyhow::Result`
6//! without losing information.
7
8use std::time::Duration;
9
10/// All errors surfaced by the crate.
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 /// The platform returned 401. Split out from [`Error::Http`] so
14 /// consumers can render a tailored "sign in again" message instead
15 /// of the raw response body — the right remedy is almost always
16 /// "mint a fresh token", and the body alone (`{"error":"unauthenticated"}`)
17 /// doesn't tell the user that.
18 #[error("HTTP 401 {url}: {body}")]
19 Unauthorized { url: String, body: String },
20
21 /// The platform returned a non-2xx status (other than 401, which has
22 /// its own [`Error::Unauthorized`] variant). `body` is truncated to a
23 /// reasonable size before being attached.
24 #[error("HTTP {status} {url}: {body}")]
25 Http {
26 status: u16,
27 url: String,
28 body: String,
29 },
30
31 /// Underlying transport failure (DNS, TLS, connection reset, …).
32 #[error("network error: {0}")]
33 Network(#[from] reqwest::Error),
34
35 /// The response body wasn't valid JSON for the expected shape.
36 #[error("decoding response from {url}: {source}")]
37 Decode {
38 url: String,
39 #[source]
40 source: serde_json::Error,
41 },
42
43 /// The OAuth callback returned a `state` value that didn't match
44 /// what we generated. Refusing the token is the only safe move.
45 #[error("OAuth state mismatch — got {actual:?}, expected {expected:?}")]
46 StateMismatch {
47 actual: Option<String>,
48 expected: String,
49 },
50
51 /// The user (or the platform) cancelled the OAuth flow in the
52 /// browser. The `String` carries the platform-supplied reason.
53 #[error("OAuth flow cancelled in browser: {0}")]
54 Cancelled(String),
55
56 /// The OAuth handshake didn't complete within the allotted time.
57 #[error("OAuth handshake timed out after {0:?}")]
58 Timeout(Duration),
59
60 /// Caller-side problem — usually a malformed input (e.g. a token
61 /// that contains bytes we can't put in an HTTP header).
62 #[error("bad request: {0}")]
63 BadRequest(String),
64
65 /// Local I/O failure (loopback bind, socket read/write, …).
66 #[error("I/O: {0}")]
67 Io(#[from] std::io::Error),
68}
69
70pub type Result<T> = std::result::Result<T, Error>;