Skip to main content

wepub_core/
error.rs

1use thiserror::Error;
2
3/// Convenience alias for [`std::result::Result`] specialized to [`WepubError`].
4pub type Result<T> = std::result::Result<T, WepubError>;
5
6/// Error type returned by every fallible call in this crate.
7///
8/// Variants split errors by responsibility: the network layer, the wire
9/// protocol, the credentials, the per-store domain (validation / upload /
10/// publish), and a catch-all [`Internal`](WepubError::Internal) for
11/// "should-never-happen" states.
12#[derive(Debug, Error)]
13pub enum WepubError {
14    /// Underlying transport failure surfaced by `reqwest` (DNS, TCP, TLS,
15    /// connect / read / overall timeout, body read error, etc.).
16    #[error("network error: {0}")]
17    Network(#[from] reqwest::Error),
18
19    /// The remote returned a non-2xx HTTP status. `body` carries the
20    /// (possibly empty) response body verbatim.
21    #[error("API error (status {status}): {body}")]
22    Api {
23        /// HTTP status code from the failed response.
24        status: u16,
25        /// Response body received with the failure status.
26        body: String,
27    },
28
29    /// The OAuth / JWT credential exchange failed at the protocol level
30    /// (e.g. Google's token endpoint returned `invalid_grant`).
31    #[error("authentication failed: {0}")]
32    Auth(String),
33
34    /// Firefox AMO reported the upload as `valid: false`, or validation
35    /// polling exceeded its timeout. `body` is the validation result JSON
36    /// (pretty-printed) or a timeout description.
37    #[error("AMO validation failed for upload {uuid}: {body}")]
38    Validation {
39        /// AMO upload UUID returned by `POST /addons/upload/`.
40        uuid: String,
41        /// Pretty-printed AMO validation result, or a timeout description.
42        body: String,
43    },
44
45    /// Chrome Web Store reported `uploadState = FAILED` or `NOT_FOUND`, or
46    /// upload polling exceeded its timeout.
47    #[error("CWS upload failed for item {item_id}: {body}")]
48    Upload {
49        /// CWS item id whose upload failed.
50        item_id: String,
51        /// Failure description from the official enum docs, or a timeout
52        /// description.
53        body: String,
54    },
55
56    /// The CWS publish endpoint returned 200 OK but the item state is a
57    /// terminal failure (`REJECTED` or `CANCELLED`). The HTTP call itself
58    /// succeeded, hence this is not [`Api`](WepubError::Api).
59    #[error("publish failed for item {item_id}: {body}")]
60    Publish {
61        /// CWS item id reported in the publish response.
62        item_id: String,
63        /// Short description of the terminal state.
64        body: String,
65    },
66
67    /// JSON deserialization of a response body failed. Indicates the wire
68    /// shape diverged from this crate's expectations.
69    #[error("JSON error: {0}")]
70    Json(#[from] serde_json::Error),
71
72    /// Local filesystem I/O failed (e.g. could not read the source zip).
73    #[error("I/O error: {0}")]
74    Io(#[from] std::io::Error),
75
76    /// A URL passed in by the caller (typically through one of the `with_*`
77    /// builders) failed to parse.
78    #[error("invalid URL: {0}")]
79    InvalidUrl(String),
80
81    /// "Should never happen" programmer-error states: URL join failure,
82    /// pre-epoch system clock, JWT encode failure, hard-coded MIME literal
83    /// rejected by `mime_str`. Reaching this variant indicates a bug in
84    /// `wepub-core` itself.
85    #[error("internal error: {0}")]
86    Internal(String),
87}