Skip to main content

systemprompt_cloud/api_client/
tenant_api.rs

1//! Tenant-scoped endpoints for [`super::CloudApiClient`].
2
3use serde::Serialize;
4use systemprompt_identifiers::TenantId;
5use systemprompt_models::modules::ApiPaths;
6
7use super::CloudApiClient;
8use super::types::{
9    ApiResponse, CustomDomainResponse, DeployResponse, ExternalDbAccessResponse,
10    ListSecretsResponse, RegistryToken, RotateCredentialsResponse, SetCustomDomainRequest,
11    SetExternalDbAccessRequest, SetSecretsRequest, StatusResponse, TenantSecrets, TenantStatus,
12};
13use crate::error::CloudResult;
14
15#[derive(Serialize)]
16struct DeployRequest {
17    image: String,
18}
19
20impl CloudApiClient {
21    pub async fn get_tenant_status(&self, tenant_id: &TenantId) -> CloudResult<TenantStatus> {
22        let response: ApiResponse<TenantStatus> =
23            self.tenant_get(&ApiPaths::tenant_status(tenant_id)).await?;
24        Ok(response.data)
25    }
26
27    pub async fn get_registry_token(&self, tenant_id: &TenantId) -> CloudResult<RegistryToken> {
28        let response: ApiResponse<RegistryToken> = self
29            .tenant_get(&ApiPaths::tenant_registry_token(tenant_id))
30            .await?;
31        Ok(response.data)
32    }
33
34    pub async fn deploy(&self, tenant_id: &TenantId, image: &str) -> CloudResult<DeployResponse> {
35        let request = DeployRequest {
36            image: image.to_owned(),
37        };
38        let response: ApiResponse<DeployResponse> = self
39            .tenant_post(&ApiPaths::tenant_deploy(tenant_id), &request)
40            .await?;
41        Ok(response.data)
42    }
43
44    pub async fn fetch_secrets(&self, secrets_url: &str) -> CloudResult<TenantSecrets> {
45        let path = secrets_url
46            .strip_prefix(&self.api_url)
47            .unwrap_or(secrets_url);
48        self.tenant_get(path).await
49    }
50
51    pub async fn delete_tenant(&self, tenant_id: &TenantId) -> CloudResult<()> {
52        self.tenant_delete(&ApiPaths::tenant(tenant_id)).await
53    }
54
55    pub async fn restart_tenant(&self, tenant_id: &TenantId) -> CloudResult<StatusResponse> {
56        self.tenant_post_empty(&ApiPaths::tenant_restart(tenant_id))
57            .await
58    }
59
60    pub async fn retry_provision(&self, tenant_id: &TenantId) -> CloudResult<StatusResponse> {
61        self.tenant_post_empty(&ApiPaths::tenant_retry_provision(tenant_id))
62            .await
63    }
64
65    pub async fn set_secrets(
66        &self,
67        tenant_id: &TenantId,
68        secrets: std::collections::HashMap<String, String>,
69    ) -> CloudResult<Vec<String>> {
70        let keys: Vec<String> = secrets.keys().cloned().collect();
71        let request = SetSecretsRequest { secrets };
72        self.tenant_put_no_content(&ApiPaths::tenant_secrets(tenant_id), &request)
73            .await?;
74        Ok(keys)
75    }
76
77    pub async fn unset_secret(&self, tenant_id: &TenantId, key: &str) -> CloudResult<()> {
78        let path = format!("{}/{}", ApiPaths::tenant_secrets(tenant_id), key);
79        self.tenant_delete(&path).await
80    }
81
82    pub async fn set_external_db_access(
83        &self,
84        tenant_id: &TenantId,
85        enabled: bool,
86    ) -> CloudResult<ExternalDbAccessResponse> {
87        let request = SetExternalDbAccessRequest { enabled };
88        let response: ApiResponse<ExternalDbAccessResponse> = self
89            .tenant_put(&ApiPaths::tenant_external_db_access(tenant_id), &request)
90            .await?;
91        Ok(response.data)
92    }
93
94    pub async fn rotate_credentials(
95        &self,
96        tenant_id: &TenantId,
97    ) -> CloudResult<RotateCredentialsResponse> {
98        self.tenant_post_empty(&ApiPaths::tenant_rotate_credentials(tenant_id))
99            .await
100    }
101
102    pub async fn list_secrets(&self, tenant_id: &TenantId) -> CloudResult<ListSecretsResponse> {
103        self.tenant_get(&ApiPaths::tenant_secrets(tenant_id)).await
104    }
105
106    pub async fn set_custom_domain(
107        &self,
108        tenant_id: &TenantId,
109        domain: &str,
110    ) -> CloudResult<CustomDomainResponse> {
111        let request = SetCustomDomainRequest {
112            domain: domain.to_owned(),
113        };
114        let response: ApiResponse<CustomDomainResponse> = self
115            .tenant_post(&ApiPaths::tenant_custom_domain(tenant_id), &request)
116            .await?;
117        Ok(response.data)
118    }
119
120    pub async fn get_custom_domain(
121        &self,
122        tenant_id: &TenantId,
123    ) -> CloudResult<CustomDomainResponse> {
124        let response: ApiResponse<CustomDomainResponse> = self
125            .tenant_get(&ApiPaths::tenant_custom_domain(tenant_id))
126            .await?;
127        Ok(response.data)
128    }
129
130    pub async fn delete_custom_domain(&self, tenant_id: &TenantId) -> CloudResult<()> {
131        self.tenant_delete(&ApiPaths::tenant_custom_domain(tenant_id))
132            .await
133    }
134
135    pub async fn cancel_subscription(&self, tenant_id: &TenantId) -> CloudResult<()> {
136        self.tenant_post_empty(&ApiPaths::tenant_subscription_cancel(tenant_id))
137            .await
138    }
139}