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}