mockforge_plugin_core/
lib.rs

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