1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum CoreError {
8 #[error("IO error: {0}")]
9 Io(#[from] std::io::Error),
10
11 #[error("YAML parsing error: {0}")]
12 Yaml(#[from] serde_yaml::Error),
13
14 #[error("JSON parsing error: {0}")]
15 Json(#[from] serde_json::Error),
16
17 #[error("Validation error: {message}")]
18 Validation { message: String },
19
20 #[error("Configuration error: {message}")]
21 Configuration { message: String },
22
23 #[error("Service not found: {service_type}")]
24 ServiceNotFound { service_type: String },
25
26 #[error("Invalid service scope: {scope}")]
27 InvalidServiceScope { scope: String },
28
29 #[error("Lock error on resource: {resource}")]
30 LockError { resource: String },
31
32 #[error("Lifecycle error in component '{component}' during '{operation}': {source}")]
33 LifecycleError {
34 component: String,
35 operation: String,
36 source: Box<dyn std::error::Error + Send + Sync>,
37 },
38
39 #[error("System error: {message}")]
40 SystemError {
41 message: String,
42 source: Option<Box<dyn std::error::Error + Send + Sync>>,
43 },
44
45 #[error("Module error: {message}")]
46 Module { message: String },
47
48 #[error("Provider error: {message}")]
49 Provider { message: String },
50
51 #[error("Codegen error: {message}")]
52 Codegen { message: String },
53
54 #[error("Template error: {message}")]
55 Template { message: String },
56
57 #[error("Database error: {message}")]
58 Database { message: String },
59
60 #[error("API error: {code} - {message}")]
61 Api {
62 code: String,
63 message: String,
64 hint: Option<String>,
65 },
66}
67
68impl CoreError {
69 pub fn validation(message: impl Into<String>) -> Self {
71 Self::Validation {
72 message: message.into(),
73 }
74 }
75
76 pub fn configuration(message: impl Into<String>) -> Self {
78 Self::Configuration {
79 message: message.into(),
80 }
81 }
82
83 pub fn service_not_found(service_type: impl Into<String>) -> Self {
85 Self::ServiceNotFound {
86 service_type: service_type.into(),
87 }
88 }
89
90 pub fn system_error(message: impl Into<String>) -> Self {
92 Self::SystemError {
93 message: message.into(),
94 source: None,
95 }
96 }
97
98 pub fn system_error_with_source(
100 message: impl Into<String>,
101 source: Box<dyn std::error::Error + Send + Sync>,
102 ) -> Self {
103 Self::SystemError {
104 message: message.into(),
105 source: Some(source),
106 }
107 }
108
109 pub fn api_error(code: impl Into<String>, message: impl Into<String>) -> Self {
111 Self::Api {
112 code: code.into(),
113 message: message.into(),
114 hint: None,
115 }
116 }
117
118 pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
120 if let Self::Api { hint: ref mut h, .. } = self {
121 *h = Some(hint.into());
122 }
123 self
124 }
125
126 pub fn is_validation(&self) -> bool {
128 matches!(self, Self::Validation { .. })
129 }
130
131 pub fn is_configuration(&self) -> bool {
133 matches!(self, Self::Configuration { .. })
134 }
135
136 pub fn is_service(&self) -> bool {
138 matches!(self, Self::ServiceNotFound { .. })
139 }
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct ErrorDefinition {
145 pub code: String,
146 pub http: u16,
147 pub message: String,
148 pub hint: String,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct ApiErrorResponse {
154 pub error: ApiError,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct ApiError {
160 pub code: String,
161 pub message: String,
162 pub hint: Option<String>,
163}
164
165impl ApiError {
166 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
168 Self {
169 code: code.into(),
170 message: message.into(),
171 hint: None,
172 }
173 }
174
175 pub fn with_hint(mut self, hint: impl Into<String>) -> Self {
177 self.hint = Some(hint.into());
178 self
179 }
180}
181
182impl From<CoreError> for ApiError {
183 fn from(error: CoreError) -> Self {
184 match error {
185 CoreError::Api { code, message, hint } => Self { code, message, hint },
186 CoreError::Validation { message } => Self::new("VALIDATION_ERROR", message),
187 CoreError::Configuration { message } => Self::new("CONFIG_ERROR", message),
188 CoreError::ServiceNotFound { service_type } => {
189 Self::new("SERVICE_NOT_FOUND", format!("Service not found: {}", service_type))
190 }
191 _ => Self::new("INTERNAL_ERROR", error.to_string()),
192 }
193 }
194}
195
196impl From<ApiError> for ApiErrorResponse {
197 fn from(error: ApiError) -> Self {
198 Self { error }
199 }
200}
201
202pub type ErrorCatalog = HashMap<String, ErrorDefinition>;
204
205pub type ElifError = CoreError;