Skip to main content

novelai_bridge/
error.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4/// Stable error codes returned by this crate.
5#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
6#[serde(rename_all = "snake_case")]
7pub enum BridgeErrorCode {
8    /// The request failed local validation or the API rejected its shape.
9    InvalidRequest,
10    /// Authentication failed, usually because the API key is missing or invalid.
11    AuthenticationFailed,
12    /// The account does not have enough credit or subscription access.
13    InsufficientCredit,
14    /// The request conflicted with the current server-side state.
15    RequestConflict,
16    /// The request was rate limited.
17    RateLimited,
18    /// A transport-level network error occurred.
19    NetworkError,
20    /// The server returned a 5xx response.
21    ServerError,
22    /// The error did not match a more specific category.
23    UnknownError,
24}
25
26impl BridgeErrorCode {
27    /// Returns the serialized string form used by [`BridgeError::code`].
28    pub fn as_str(&self) -> &'static str {
29        match self {
30            Self::InvalidRequest => "invalid_request",
31            Self::AuthenticationFailed => "authentication_failed",
32            Self::InsufficientCredit => "insufficient_credit",
33            Self::RequestConflict => "request_conflict",
34            Self::RateLimited => "rate_limited",
35            Self::NetworkError => "network_error",
36            Self::ServerError => "server_error",
37            Self::UnknownError => "unknown_error",
38        }
39    }
40}
41
42/// Unified error type returned by this crate.
43#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
44pub struct BridgeError {
45    /// Machine-readable error code.
46    pub code: String,
47    /// Human-readable error message.
48    pub message: String,
49    /// Parsed retry delay in milliseconds when available.
50    pub retry_after_ms: Option<u64>,
51    /// Optional structured details attached by the caller or mapper.
52    pub details: Option<Value>,
53}
54
55impl BridgeError {
56    /// Creates a new error with the given code and message.
57    pub fn new(code: BridgeErrorCode, message: impl Into<String>) -> Self {
58        Self {
59            code: code.as_str().to_owned(),
60            message: message.into(),
61            retry_after_ms: None,
62            details: None,
63        }
64    }
65
66    /// Attaches a parsed retry delay in milliseconds.
67    pub fn with_retry_after_ms(mut self, retry_after_ms: Option<u64>) -> Self {
68        self.retry_after_ms = retry_after_ms;
69        self
70    }
71
72    /// Attaches structured JSON details.
73    pub fn with_details(mut self, details: Value) -> Self {
74        self.details = Some(details);
75        self
76    }
77
78    /// Creates an `invalid_request` error.
79    pub fn invalid_request(message: impl Into<String>) -> Self {
80        Self::new(BridgeErrorCode::InvalidRequest, message)
81    }
82
83    /// Creates an `authentication_failed` error.
84    pub fn authentication_failed(message: impl Into<String>) -> Self {
85        Self::new(BridgeErrorCode::AuthenticationFailed, message)
86    }
87
88    /// Creates an `insufficient_credit` error.
89    pub fn insufficient_credit(message: impl Into<String>) -> Self {
90        Self::new(BridgeErrorCode::InsufficientCredit, message)
91    }
92
93    /// Creates a `request_conflict` error.
94    pub fn request_conflict(message: impl Into<String>) -> Self {
95        Self::new(BridgeErrorCode::RequestConflict, message)
96    }
97
98    /// Creates a `rate_limited` error with an optional retry delay.
99    pub fn rate_limited(message: impl Into<String>, retry_after_ms: Option<u64>) -> Self {
100        Self::new(BridgeErrorCode::RateLimited, message).with_retry_after_ms(retry_after_ms)
101    }
102
103    /// Creates a `network_error` error.
104    pub fn network_error(message: impl Into<String>) -> Self {
105        Self::new(BridgeErrorCode::NetworkError, message)
106    }
107
108    /// Creates a `server_error` error.
109    pub fn server_error(message: impl Into<String>) -> Self {
110        Self::new(BridgeErrorCode::ServerError, message)
111    }
112
113    /// Creates an `unknown_error` error.
114    pub fn unknown_error(message: impl Into<String>) -> Self {
115        Self::new(BridgeErrorCode::UnknownError, message)
116    }
117}
118
119impl core::fmt::Display for BridgeError {
120    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121        write!(f, "{}: {}", self.code, self.message)
122    }
123}
124
125impl std::error::Error for BridgeError {}