Skip to main content

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>;