1use std::time::Duration;
4
5#[derive(Debug, thiserror::Error)]
7pub enum RegistryError {
8 #[error("pack not found: {name}@{version}")]
10 NotFound { name: String, version: String },
11
12 #[error("unauthorized: {message}")]
14 Unauthorized { message: String },
15
16 #[error("rate limited: retry after {retry_after:?}")]
18 RateLimited { retry_after: Option<Duration> },
19
20 #[error("pack revoked: {name}@{version} - {reason}")]
22 Revoked {
23 name: String,
24 version: String,
25 reason: String,
26 safe_version: Option<String>,
28 },
29
30 #[error("digest mismatch for {name}@{version}: expected {expected}, got {actual}")]
32 DigestMismatch {
33 name: String,
34 version: String,
35 expected: String,
36 actual: String,
37 },
38
39 #[error("signature verification failed: {reason}")]
41 SignatureInvalid { reason: String },
42
43 #[error("key not trusted: {key_id}")]
45 KeyNotTrusted { key_id: String },
46
47 #[error("pack is unsigned: {name}@{version}")]
49 Unsigned { name: String, version: String },
50
51 #[error("invalid pack reference: {reference} - {reason}")]
53 InvalidReference { reference: String, reason: String },
54
55 #[error("network error: {message}")]
57 Network { message: String },
58
59 #[error("cache error: {message}")]
61 Cache { message: String },
62
63 #[error("invalid response: {message}")]
65 InvalidResponse { message: String },
66
67 #[error("configuration error: {message}")]
69 Config { message: String },
70
71 #[error("lockfile error: {message}")]
73 Lockfile { message: String },
74}
75
76impl RegistryError {
77 pub fn exit_code(&self) -> i32 {
79 match self {
80 Self::NotFound { .. } => 1,
82 Self::Config { .. } => 1,
83 Self::InvalidReference { .. } => 1,
84
85 Self::Unauthorized { .. } => 2,
87
88 Self::Revoked { .. } => 3,
90 Self::DigestMismatch { .. } => 4,
91 Self::SignatureInvalid { .. } => 4,
92 Self::KeyNotTrusted { .. } => 4,
93 Self::Unsigned { .. } => 4,
94
95 Self::RateLimited { .. } => 5,
97 Self::Network { .. } => 5,
98
99 Self::Cache { .. } => 6,
101 Self::InvalidResponse { .. } => 6,
102 Self::Lockfile { .. } => 7,
103 }
104 }
105
106 pub fn is_retryable(&self) -> bool {
108 matches!(self, Self::RateLimited { .. } | Self::Network { .. })
109 }
110}
111
112impl From<reqwest::Error> for RegistryError {
113 fn from(err: reqwest::Error) -> Self {
114 Self::Network {
115 message: err.to_string(),
116 }
117 }
118}
119
120pub type RegistryResult<T> = Result<T, RegistryError>;