use thiserror::Error;
#[derive(Error, Debug)]
pub enum OpError {
#[error("1Password CLI (op) not found. Please install it from https://1password.com/downloads/command-line/")]
NotFound,
#[error("Not signed in to 1Password. Please sign in using the 1Password app or run `op signin`")]
NotSignedIn,
#[error("Vault not found: {0}")]
VaultNotFound(String),
#[error("Item not found: {0}")]
ItemNotFound(String),
#[error("Account not found: {0}")]
AccountNotFound(String),
#[error("User not found: {0}")]
UserNotFound(String),
#[error("Group not found: {0}")]
GroupNotFound(String),
#[error("Document not found: {0}")]
DocumentNotFound(String),
#[error("Connect server not found: {0}")]
ConnectServerNotFound(String),
#[error("Invalid secret reference: {0}. Expected format: op://vault/item/field")]
InvalidSecretReference(String),
#[error("Permission denied: {0}")]
PermissionDenied(String),
#[error("Rate limit exceeded. Please wait before making more requests.")]
RateLimitExceeded,
#[error("Feature not available: {0}")]
FeatureNotAvailable(String),
#[error("1Password CLI error: {0}")]
CliError(String),
#[error("Failed to parse op CLI output: {0}")]
ParseError(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
}
impl OpError {
pub fn from_stderr(stderr: &str) -> Self {
let stderr_lower = stderr.to_lowercase();
if stderr_lower.contains("not signed in")
|| stderr_lower.contains("sign in")
|| stderr_lower.contains("authorization")
|| stderr_lower.contains("session expired")
{
return OpError::NotSignedIn;
}
if stderr_lower.contains("isn't a vault")
|| (stderr_lower.contains("vault") && stderr_lower.contains("not found"))
{
return OpError::VaultNotFound(stderr.to_string());
}
if stderr_lower.contains("isn't an item")
|| (stderr_lower.contains("item") && stderr_lower.contains("not found"))
|| stderr_lower.contains("no item found")
{
return OpError::ItemNotFound(stderr.to_string());
}
if stderr_lower.contains("isn't a user")
|| (stderr_lower.contains("user") && stderr_lower.contains("not found"))
{
return OpError::UserNotFound(stderr.to_string());
}
if stderr_lower.contains("isn't a group")
|| (stderr_lower.contains("group") && stderr_lower.contains("not found"))
{
return OpError::GroupNotFound(stderr.to_string());
}
if stderr_lower.contains("isn't a document")
|| (stderr_lower.contains("document") && stderr_lower.contains("not found"))
{
return OpError::DocumentNotFound(stderr.to_string());
}
if stderr_lower.contains("connect server")
&& (stderr_lower.contains("not found") || stderr_lower.contains("isn't"))
{
return OpError::ConnectServerNotFound(stderr.to_string());
}
if stderr_lower.contains("permission denied")
|| stderr_lower.contains("access denied")
|| stderr_lower.contains("not authorized")
{
return OpError::PermissionDenied(stderr.to_string());
}
if stderr_lower.contains("rate limit") || stderr_lower.contains("too many requests") {
return OpError::RateLimitExceeded;
}
if stderr_lower.contains("not available")
|| stderr_lower.contains("upgrade")
|| stderr_lower.contains("requires")
{
return OpError::FeatureNotAvailable(stderr.to_string());
}
OpError::CliError(stderr.to_string())
}
}