mockforge_plugin_registry/
lib.rs1pub mod api;
6pub mod config;
7pub mod dependencies;
8pub mod hot_reload;
9pub mod index;
10pub mod manifest;
11pub mod reviews;
12pub mod runtime;
13pub mod security;
14pub mod storage;
15
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use thiserror::Error;
19
20#[derive(Error, Debug)]
22pub enum RegistryError {
23 #[error("Plugin not found: {0}")]
24 PluginNotFound(String),
25
26 #[error("Invalid version: {0}")]
27 InvalidVersion(String),
28
29 #[error("Plugin already exists: {0}")]
30 PluginExists(String),
31
32 #[error("Authentication required")]
33 AuthRequired,
34
35 #[error("Permission denied")]
36 PermissionDenied,
37
38 #[error("Invalid manifest: {0}")]
39 InvalidManifest(String),
40
41 #[error("Storage error: {0}")]
42 Storage(String),
43
44 #[error("Network error: {0}")]
45 Network(String),
46
47 #[error(transparent)]
48 Io(#[from] std::io::Error),
49
50 #[error(transparent)]
51 Serde(#[from] serde_json::Error),
52}
53
54pub type Result<T> = std::result::Result<T, RegistryError>;
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct RegistryEntry {
59 pub name: String,
61
62 pub description: String,
64
65 pub version: String,
67
68 pub versions: Vec<VersionEntry>,
70
71 pub author: AuthorInfo,
73
74 pub tags: Vec<String>,
76
77 pub category: PluginCategory,
79
80 pub downloads: u64,
82
83 pub rating: f64,
85
86 pub reviews_count: u32,
88
89 pub repository: Option<String>,
91
92 pub homepage: Option<String>,
94
95 pub license: String,
97
98 pub created_at: String,
100
101 pub updated_at: String,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct VersionEntry {
108 pub version: String,
110
111 pub download_url: String,
113
114 pub checksum: String,
116
117 pub size: u64,
119
120 pub published_at: String,
122
123 pub yanked: bool,
125
126 pub min_mockforge_version: Option<String>,
128
129 pub dependencies: HashMap<String, String>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct AuthorInfo {
136 pub name: String,
137 pub email: Option<String>,
138 pub url: Option<String>,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(rename_all = "lowercase")]
144pub enum PluginCategory {
145 Auth,
146 Template,
147 Response,
148 DataSource,
149 Middleware,
150 Testing,
151 Observability,
152 Other,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct SearchQuery {
158 pub query: Option<String>,
160
161 pub category: Option<PluginCategory>,
163
164 pub tags: Vec<String>,
166
167 pub sort: SortOrder,
169
170 pub page: usize,
172
173 pub per_page: usize,
175}
176
177impl Default for SearchQuery {
178 fn default() -> Self {
179 Self {
180 query: None,
181 category: None,
182 tags: vec![],
183 sort: SortOrder::Relevance,
184 page: 0,
185 per_page: 20,
186 }
187 }
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192#[serde(rename_all = "lowercase")]
193pub enum SortOrder {
194 Relevance,
195 Downloads,
196 Rating,
197 Recent,
198 Name,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct SearchResults {
204 pub plugins: Vec<RegistryEntry>,
205 pub total: usize,
206 pub page: usize,
207 pub per_page: usize,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct RegistryConfig {
213 pub url: String,
215
216 pub token: Option<String>,
218
219 pub cache_dir: Option<String>,
221
222 pub timeout: u64,
224
225 pub alternative_registries: Vec<String>,
227}
228
229impl Default for RegistryConfig {
230 fn default() -> Self {
231 Self {
232 url: "https://registry.mockforge.dev".to_string(),
233 token: None,
234 cache_dir: None,
235 timeout: 30,
236 alternative_registries: vec![],
237 }
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn test_registry_entry_serialization() {
247 let entry = RegistryEntry {
248 name: "test-plugin".to_string(),
249 description: "Test plugin".to_string(),
250 version: "1.0.0".to_string(),
251 versions: vec![],
252 author: AuthorInfo {
253 name: "Test Author".to_string(),
254 email: Some("test@example.com".to_string()),
255 url: None,
256 },
257 tags: vec!["test".to_string()],
258 category: PluginCategory::Auth,
259 downloads: 100,
260 rating: 4.5,
261 reviews_count: 10,
262 repository: None,
263 homepage: None,
264 license: "MIT".to_string(),
265 created_at: "2025-01-01T00:00:00Z".to_string(),
266 updated_at: "2025-01-01T00:00:00Z".to_string(),
267 };
268
269 let json = serde_json::to_string(&entry).unwrap();
270 let deserialized: RegistryEntry = serde_json::from_str(&json).unwrap();
271 assert_eq!(entry.name, deserialized.name);
272 }
273
274 #[test]
275 fn test_search_query_default() {
276 let query = SearchQuery::default();
277 assert_eq!(query.page, 0);
278 assert_eq!(query.per_page, 20);
279 }
280}