Skip to main content

synth_ai/
lib.rs

1//! Canonical Rust SDK for Synth.
2//!
3//! This crate mirrors the canonical Python SDK namespace model with a single
4//! front-door `SynthClient`.
5
6use std::env;
7use std::sync::Arc;
8
9pub mod containers_api;
10pub mod graphs_api;
11pub mod inference_api;
12pub mod models;
13pub mod openapi_paths;
14pub mod optimization_api;
15pub mod pools_api;
16mod transport;
17pub mod tunnels_api;
18pub mod verifiers_api;
19
20pub use types::SynthError as Error;
21pub use types::{Result, SynthError};
22
23pub use containers_api::ContainersClient;
24pub use graphs_api::GraphsClient;
25pub use inference_api::InferenceClient;
26pub use optimization_api::OptimizationClient;
27pub use pools_api::PoolsClient;
28pub use tunnels_api::TunnelsClient;
29pub use verifiers_api::VerifiersClient;
30
31mod types;
32
33/// SDK version.
34pub const VERSION: &str = env!("CARGO_PKG_VERSION");
35
36/// Default Synth API base URL.
37pub const DEFAULT_BASE_URL: &str = synth_ai_core::urls::DEFAULT_BACKEND_URL;
38
39/// Environment variable for API key.
40pub const API_KEY_ENV: &str = "SYNTH_API_KEY";
41
42/// Canonical front-door client.
43#[derive(Clone)]
44pub struct SynthClient {
45    transport: Arc<transport::Transport>,
46}
47
48impl SynthClient {
49    /// Create a new client with explicit credentials.
50    pub fn new(api_key: impl Into<String>, base_url: Option<&str>) -> Result<Self> {
51        let base_url = base_url.unwrap_or(DEFAULT_BASE_URL).to_string();
52        let transport = transport::Transport::new(api_key.into(), base_url)?;
53        Ok(Self {
54            transport: Arc::new(transport),
55        })
56    }
57
58    /// Create a client from environment variables.
59    pub fn from_env() -> Result<Self> {
60        let api_key = env::var(API_KEY_ENV).map_err(|_| SynthError::MissingApiKey)?;
61        let base_url = env::var("SYNTH_BASE_URL")
62            .ok()
63            .or_else(|| env::var("SYNTH_BACKEND_URL").ok());
64        Self::new(api_key, base_url.as_deref())
65    }
66
67    pub fn base_url(&self) -> &str {
68        self.transport.base_url()
69    }
70
71    pub fn optimization(&self) -> OptimizationClient {
72        OptimizationClient::new(self.transport.clone())
73    }
74
75    pub fn inference(&self) -> InferenceClient {
76        InferenceClient::new(self.transport.clone())
77    }
78
79    pub fn graphs(&self) -> GraphsClient {
80        GraphsClient::new(self.transport.clone())
81    }
82
83    pub fn verifiers(&self) -> VerifiersClient {
84        VerifiersClient::new(self.transport.clone())
85    }
86
87    pub fn pools(&self) -> PoolsClient {
88        PoolsClient::new(self.transport.clone())
89    }
90
91    pub fn containers(&self) -> ContainersClient {
92        ContainersClient::new(self.transport.clone())
93    }
94
95    pub fn tunnels(&self) -> TunnelsClient {
96        TunnelsClient::new(self.transport.clone())
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn default_base_url_is_set() {
106        assert!(!DEFAULT_BASE_URL.is_empty());
107    }
108
109    #[test]
110    fn from_env_without_key_fails() {
111        env::remove_var(API_KEY_ENV);
112        let result = SynthClient::from_env();
113        assert!(result.is_err());
114    }
115}