auth_framework/sdks/
mod.rs

1//! SDK Generation Module
2//!
3//! This module provides SDK generators for multiple programming languages,
4//! enabling easy integration of AuthFramework's enhanced RBAC capabilities.
5
6#[cfg(feature = "enhanced-rbac")]
7pub mod javascript;
8
9#[cfg(feature = "enhanced-rbac")]
10pub mod python;
11
12#[cfg(feature = "enhanced-rbac")]
13pub use javascript::{EnhancedSdkConfig as JsConfig, JsSdkGenerator};
14
15#[cfg(feature = "enhanced-rbac")]
16pub use python::{PythonSdkConfig, PythonSdkGenerator};
17
18use serde::{Deserialize, Serialize};
19use std::collections::HashMap;
20
21/// SDK generation configuration
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct SdkGenerationConfig {
24    /// Base API URL
25    pub base_url: String,
26    /// API version
27    pub version: String,
28    /// Languages to generate SDKs for
29    pub languages: Vec<SdkLanguage>,
30    /// Include RBAC functionality
31    pub include_rbac: bool,
32    /// Include conditional permissions
33    pub include_conditional_permissions: bool,
34    /// Include audit logging
35    pub include_audit: bool,
36    /// Custom client names per language
37    pub client_names: HashMap<SdkLanguage, String>,
38}
39
40/// Supported SDK languages
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
42pub enum SdkLanguage {
43    JavaScript,
44    TypeScript,
45    Python,
46    Rust,
47    Go,
48    Java,
49    CSharp,
50}
51
52impl Default for SdkGenerationConfig {
53    fn default() -> Self {
54        let mut client_names = HashMap::new();
55        client_names.insert(SdkLanguage::JavaScript, "AuthFrameworkClient".to_string());
56        client_names.insert(SdkLanguage::TypeScript, "AuthFrameworkClient".to_string());
57        client_names.insert(SdkLanguage::Python, "AuthFrameworkClient".to_string());
58
59        Self {
60            base_url: "https://api.example.com".to_string(),
61            version: "v1".to_string(),
62            languages: vec![SdkLanguage::TypeScript, SdkLanguage::Python],
63            include_rbac: true,
64            include_conditional_permissions: true,
65            include_audit: true,
66            client_names,
67        }
68    }
69}
70
71/// SDK generation result
72#[derive(Debug)]
73pub struct SdkGenerationResult {
74    /// Generated files by language
75    pub files: HashMap<SdkLanguage, HashMap<String, String>>,
76    /// Generation errors
77    pub errors: Vec<SdkGenerationError>,
78}
79
80/// SDK generation error
81#[derive(Debug, thiserror::Error)]
82pub enum SdkGenerationError {
83    #[error("Language {0:?} not supported")]
84    UnsupportedLanguage(SdkLanguage),
85    #[error("Generation failed for {language:?}: {error}")]
86    GenerationFailed {
87        language: SdkLanguage,
88        error: String,
89    },
90    #[error("Configuration error: {0}")]
91    ConfigurationError(String),
92}
93
94/// Multi-language SDK generator
95pub struct SdkGenerator {
96    config: SdkGenerationConfig,
97}
98
99impl SdkGenerator {
100    /// Create new SDK generator
101    pub fn new(config: SdkGenerationConfig) -> Self {
102        Self { config }
103    }
104
105    /// Generate SDKs for all configured languages
106    pub fn generate_all(&self) -> Result<SdkGenerationResult, Box<dyn std::error::Error>> {
107        let mut result = SdkGenerationResult {
108            files: HashMap::new(),
109            errors: Vec::new(),
110        };
111
112        for &language in &self.config.languages {
113            match self.generate_for_language(language) {
114                Ok(files) => {
115                    result.files.insert(language, files);
116                }
117                Err(error) => {
118                    result.errors.push(SdkGenerationError::GenerationFailed {
119                        language,
120                        error: error.to_string(),
121                    });
122                }
123            }
124        }
125
126        Ok(result)
127    }
128
129    /// Generate SDK for specific language
130    pub fn generate_for_language(
131        &self,
132        language: SdkLanguage,
133    ) -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
134        match language {
135            #[cfg(feature = "enhanced-rbac")]
136            SdkLanguage::JavaScript | SdkLanguage::TypeScript => {
137                let js_config = javascript::EnhancedSdkConfig {
138                    base_url: self.config.base_url.clone(),
139                    version: self.config.version.clone(),
140                    typescript: language == SdkLanguage::TypeScript,
141                    include_rbac: self.config.include_rbac,
142                    include_conditional_permissions: self.config.include_conditional_permissions,
143                    include_audit: self.config.include_audit,
144                    client_name: self
145                        .config
146                        .client_names
147                        .get(&language)
148                        .cloned()
149                        .unwrap_or_else(|| "AuthFrameworkClient".to_string()),
150                };
151
152                let generator = javascript::JsSdkGenerator::new(js_config);
153                generator.generate_sdk()
154            }
155
156            #[cfg(feature = "enhanced-rbac")]
157            SdkLanguage::Python => {
158                let python_config = python::PythonSdkConfig {
159                    base_url: self.config.base_url.clone(),
160                    version: self.config.version.clone(),
161                    include_rbac: self.config.include_rbac,
162                    include_conditional_permissions: self.config.include_conditional_permissions,
163                    include_audit: self.config.include_audit,
164                    client_name: self
165                        .config
166                        .client_names
167                        .get(&language)
168                        .cloned()
169                        .unwrap_or_else(|| "AuthFrameworkClient".to_string()),
170                    async_support: true,
171                    type_hints: true,
172                };
173
174                let generator = python::PythonSdkGenerator::new(python_config);
175                generator.generate_sdk()
176            }
177
178            _ => Err(Box::new(SdkGenerationError::UnsupportedLanguage(language))),
179        }
180    }
181
182    /// Get supported languages
183    pub fn supported_languages() -> Vec<SdkLanguage> {
184        vec![
185            #[cfg(feature = "enhanced-rbac")]
186            SdkLanguage::JavaScript,
187            #[cfg(feature = "enhanced-rbac")]
188            SdkLanguage::TypeScript,
189            #[cfg(feature = "enhanced-rbac")]
190            SdkLanguage::Python,
191        ]
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    #[test]
200    fn test_sdk_generation_config() {
201        let config = SdkGenerationConfig::default();
202        assert_eq!(config.version, "v1");
203        assert!(config.include_rbac);
204        assert!(config.include_conditional_permissions);
205        assert!(config.include_audit);
206    }
207
208    #[test]
209    fn test_supported_languages() {
210        let languages = SdkGenerator::supported_languages();
211        assert!(!languages.is_empty());
212    }
213
214    #[cfg(feature = "enhanced-rbac")]
215    #[test]
216    fn test_multi_language_generation() {
217        let config = SdkGenerationConfig {
218            languages: vec![SdkLanguage::TypeScript, SdkLanguage::Python],
219            ..Default::default()
220        };
221
222        let generator = SdkGenerator::new(config);
223        let result = generator.generate_all();
224
225        assert!(result.is_ok());
226        let sdk_result = result.unwrap();
227
228        // Should have generated files for both languages
229        assert!(sdk_result.files.contains_key(&SdkLanguage::TypeScript));
230        assert!(sdk_result.files.contains_key(&SdkLanguage::Python));
231    }
232}
233
234