use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CloudflareError {
#[error("HTTP request failed: {0}")]
Http(String),
#[error("API error: {0}")]
Api(String),
#[error("wrangler not installed. Install with: npm install -g wrangler")]
WranglerNotInstalled,
#[error("wrangler command failed: {0}")]
WranglerFailed(String),
#[error("not logged in to Cloudflare. Run: wrangler login")]
NotLoggedIn,
#[error("failed to parse response: {0}")]
Parse(String),
#[error("config directory not found")]
ConfigDirNotFound,
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error(
"API token missing required permissions for {0}. \
Create a token at https://dash.cloudflare.com/profile/api-tokens \
with the appropriate scopes and set it as CLOUDFLARE_API_TOKEN."
)]
InsufficientPermissions(String),
}
#[derive(Debug, Deserialize)]
pub struct CfApiResponse<T> {
pub success: bool,
#[serde(default)]
pub errors: Vec<CfApiError>,
pub result: Option<T>,
}
impl<T> CfApiResponse<T> {
pub fn into_result(self) -> Result<T, CloudflareError> {
if self.success {
self.result
.ok_or_else(|| CloudflareError::Api("missing result payload".into()))
} else {
let joined = self
.errors
.iter()
.map(|e| e.message.clone())
.collect::<Vec<_>>()
.join(", ");
Err(CloudflareError::Api(joined))
}
}
}
#[derive(Debug, Deserialize)]
pub struct CfApiError {
pub code: i32,
pub message: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TokenSource {
ApiToken,
WranglerOAuth,
}