mockforge_plugin_core/
lib.rs

1//! Pillars: [DevX]
2//!
3//! # MockForge Plugin Core
4//!
5//! Core traits, types, and runtime interfaces for the MockForge plugin system.
6//!
7//! This crate provides the foundational abstractions for building MockForge plugins,
8//! including custom authentication handlers, data sources, response generators, and
9//! template token resolvers.
10//!
11//! ## Overview
12//!
13//! MockForge uses a WebAssembly-based plugin system that allows developers to extend
14//! its functionality without modifying the core application. Plugins are sandboxed for
15//! security and can be loaded/unloaded at runtime.
16//!
17//! ## Plugin Types
18//!
19//! The plugin system supports several categories of plugins:
20//!
21//! - **Authentication Plugins**: Custom authentication and authorization logic
22//! - **Data Source Plugins**: Connect to external data sources for realistic test data
23//! - **Response Plugins**: Generate custom responses based on request data
24//! - **Template Plugins**: Custom token resolvers for the template system
25//!
26//! ## Quick Start
27//!
28//! To create a plugin, implement one or more of the plugin traits:
29//!
30//! ```rust,ignore
31//! use mockforge_plugin_core::{TokenResolver, ResolutionContext, PluginError};
32//!
33//! pub struct MyPlugin;
34//!
35//! #[async_trait::async_trait]
36//! impl TokenResolver for MyPlugin {
37//!     async fn can_resolve(&self, token: &str) -> bool {
38//!         token.starts_with("my_")
39//!     }
40//!
41//!     async fn resolve_token(
42//!         &self,
43//!         token: &str,
44//!         context: &ResolutionContext,
45//!     ) -> Result<String, PluginError> {
46//!         // Custom resolution logic
47//!         Ok(format!("resolved: {}", token))
48//!     }
49//!
50//!     async fn get_metadata(&self) -> PluginMetadata {
51//!         PluginMetadata::new("My custom plugin")
52//!             .with_capability("token_resolver")
53//!             .with_prefix("my_")
54//!     }
55//! }
56//! ```
57//!
58//! ## Key Types
59//!
60//! - [`PluginId`]: Unique identifier for plugins
61//! - [`PluginVersion`]: Semantic version information
62//! - [`PluginManifest`]: Plugin metadata and dependencies
63//! - [`PluginError`]: Common error types
64//! - [`ResolutionContext`]: Context for token resolution
65//!
66//! ## Features
67//!
68//! - Type-safe plugin interfaces
69//! - Comprehensive error handling
70//! - Built-in validation and health checks
71//! - Async/await support
72//! - Security sandboxing via WebAssembly
73//!
74//! ## For Plugin Developers
75//!
76//! For a more convenient development experience, consider using the
77//! [`mockforge-plugin-sdk`](https://docs.rs/mockforge-plugin-sdk) crate, which provides
78//! helper macros, testing utilities, and additional conveniences.
79//!
80//! ## Documentation
81//!
82//! - [Plugin Development Guide](https://docs.mockforge.dev/plugins)
83//! - [API Reference](https://docs.rs/mockforge-plugin-core)
84//! - [Example Plugins](https://github.com/SaaSy-Solutions/mockforge/tree/main/examples/plugins)
85
86// Public modules
87pub mod auth;
88pub mod backend_generator;
89pub mod client_generator;
90pub mod datasource;
91pub mod error;
92pub mod manifest;
93pub mod plugins;
94pub mod response;
95pub mod runtime;
96pub mod template;
97pub mod types;
98
99// Re-export the async trait
100pub mod async_trait;
101pub use async_trait::TokenResolver;
102
103// Re-export types
104pub use auth::*;
105pub use backend_generator::{
106    BackendGenerationMetadata, BackendGenerationResult, BackendGeneratorConfig,
107    BackendGeneratorPlugin, BackendGeneratorPluginConfig, Complexity, TodoCategory, TodoItem,
108};
109pub use client_generator::{
110    ClientGenerationResult, ClientGeneratorConfig, ClientGeneratorPlugin,
111    ClientGeneratorPluginConfig, GeneratedFile, GenerationMetadata, OpenApiSpec,
112};
113pub use datasource::{
114    DataConnection, DataQuery, DataResult, DataSourcePlugin, DataSourcePluginConfig,
115};
116pub use plugins::{ReactClientGenerator, VueClientGenerator};
117pub use response::{
118    ResponseData, ResponseModifierConfig, ResponseModifierPlugin, ResponsePlugin,
119    ResponsePluginConfig, ResponseRequest,
120};
121pub use template::*;
122pub use types::*;
123
124// Re-export helper modules with qualified names to avoid ambiguity
125pub use datasource::helpers as datasource_helpers;
126pub use response::helpers as response_helpers;
127
128// Re-export common types for backwards compatibility
129pub use types::{
130    PluginAuthor, PluginHealth, PluginId, PluginInfo, PluginManifest, PluginMetadata, PluginState,
131    PluginVersion,
132};
133
134// Additional utility traits (commented out as we're using the async trait)
135// pub trait SyncTokenResolver {
136//     /// Check if this resolver can handle a given token
137//     fn can_resolve(&self, token: &str) -> bool;
138//
139//     /// Resolve a token to its value synchronously
140//     fn resolve_token(&self, token: &str, context: &ResolutionContext) -> Result<String, PluginError>;
141//
142//     /// Get plugin metadata
143//     fn get_metadata(&self) -> PluginMetadata;
144//
145//     /// Validate plugin configuration
146//     fn validate(&self) -> Result<(), PluginError> {
147//         Ok(())
148//     }
149// }
150
151// Re-export additional types for backwards compatibility
152pub use types::{PluginError, PluginInstance, RequestMetadata, ResolutionContext, Result};
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157
158    #[test]
159    fn test_plugin_id() {
160        let id = PluginId::new("test-plugin");
161        assert_eq!(id.as_str(), "test-plugin");
162    }
163
164    #[test]
165    fn test_plugin_version() {
166        let version = PluginVersion::new(1, 2, 3);
167        assert_eq!(version.to_string(), "1.2.3");
168    }
169
170    #[test]
171    fn test_plugin_info() {
172        let id = PluginId::new("example");
173        let version = PluginVersion::new(1, 0, 0);
174        let author = PluginAuthor {
175            name: "Author".to_string(),
176            email: Some("author@example.com".to_string()),
177        };
178        let info = PluginInfo {
179            id: id.clone(),
180            version: version.clone(),
181            name: "Example Plugin".to_string(),
182            description: "Description".to_string(),
183            author: author.clone(),
184        };
185
186        assert_eq!(info.id.as_str(), "example");
187        assert_eq!(info.name, "Example Plugin");
188        assert_eq!(info.description, "Description");
189        assert_eq!(info.author.name, "Author");
190        assert_eq!(info.author.email, Some("author@example.com".to_string()));
191    }
192
193    #[test]
194    fn test_resolution_context() {
195        let context = ResolutionContext::new();
196        assert!(!context.environment.is_empty());
197        assert!(context.request_context.is_none());
198    }
199
200    #[test]
201    fn test_request_metadata() {
202        let request =
203            RequestMetadata::new("GET", "/api/users").with_header("Accept", "application/json");
204
205        assert_eq!(request.method, "GET");
206        assert_eq!(request.path, "/api/users");
207        assert_eq!(request.headers.get("Accept"), Some(&"application/json".to_string()));
208    }
209}
210
211// Include client generator tests
212#[cfg(test)]
213mod client_generator_tests;