use thiserror::Error;
pub type Result<T> = std::result::Result<T, DeviceFlowError>;
#[derive(Error, Debug)]
pub enum DeviceFlowError {
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error),
#[error("URL parsing error: {0}")]
Url(#[from] url::ParseError),
#[error("OAuth error: {error} - {error_description}")]
OAuth {
error: String,
error_description: String,
},
#[error("Authorization denied")]
AuthorizationDenied,
#[error("Device code expired")]
ExpiredToken,
#[error("Polling too frequently, slow down")]
SlowDown,
#[error("Authorization pending")]
AuthorizationPending,
#[error("Invalid device code")]
InvalidCode,
#[error("Invalid client configuration: {0}")]
InvalidClient(String),
#[error("Token expired and refresh failed")]
TokenExpired,
#[error("Unsupported provider: {0}")]
UnsupportedProvider(String),
#[error("Maximum polling attempts ({0}) exceeded")]
MaxAttemptsExceeded(u32),
#[error("Invalid scope: {0}")]
InvalidScope(String),
#[cfg(feature = "qr-codes")]
#[error("QR code generation error: {0}")]
QrCode(#[from] qrcode::types::QrError),
#[error("Unexpected error: {0}")]
Other(String),
}
impl DeviceFlowError {
pub fn oauth_error(error: impl Into<String>, description: impl Into<String>) -> Self {
Self::OAuth {
error: error.into(),
error_description: description.into(),
}
}
pub fn invalid_client(message: impl Into<String>) -> Self {
Self::InvalidClient(message.into())
}
pub fn other(message: impl Into<String>) -> Self {
Self::Other(message.into())
}
pub fn is_retryable(&self) -> bool {
matches!(
self,
Self::Network(_) | Self::AuthorizationPending | Self::SlowDown
)
}
pub fn is_slow_down(&self) -> bool {
matches!(self, Self::SlowDown)
}
pub fn is_pending(&self) -> bool {
matches!(self, Self::AuthorizationPending)
}
}