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, RotateSyncTokenResponse,
11    SetCustomDomainRequest, SetExternalDbAccessRequest, SetSecretsRequest, StatusResponse,
12    TenantSecrets, TenantStatus,
13};
14use crate::error::CloudResult;
15
16#[derive(Serialize)]
17struct DeployRequest {
18    image: String,
19}
20
21impl CloudApiClient {
22    pub async fn get_tenant_status(&self, tenant_id: &TenantId) -> CloudResult<TenantStatus> {
23        let response: ApiResponse<TenantStatus> =
24            self.get(&ApiPaths::tenant_status(tenant_id)).await?;
25        Ok(response.data)
26    }
27
28    pub async fn get_registry_token(&self, tenant_id: &TenantId) -> CloudResult<RegistryToken> {
29        let response: ApiResponse<RegistryToken> = self
30            .get(&ApiPaths::tenant_registry_token(tenant_id))
31            .await?;
32        Ok(response.data)
33    }
34
35    pub async fn deploy(&self, tenant_id: &TenantId, image: &str) -> CloudResult<DeployResponse> {
36        let request = DeployRequest {
37            image: image.to_string(),
38        };
39        let response: ApiResponse<DeployResponse> = self
40            .post(&ApiPaths::tenant_deploy(tenant_id), &request)
41            .await?;
42        Ok(response.data)
43    }
44
45    pub async fn fetch_secrets(&self, secrets_url: &str) -> CloudResult<TenantSecrets> {
46        let path = secrets_url
47            .strip_prefix(&self.api_url)
48            .unwrap_or(secrets_url);
49        self.get(path).await
50    }
51
52    pub async fn delete_tenant(&self, tenant_id: &TenantId) -> CloudResult<()> {
53        self.delete(&ApiPaths::tenant(tenant_id)).await
54    }
55
56    pub async fn restart_tenant(&self, tenant_id: &TenantId) -> CloudResult<StatusResponse> {
57        self.post_empty(&ApiPaths::tenant_restart(tenant_id)).await
58    }
59
60    pub async fn retry_provision(&self, tenant_id: &TenantId) -> CloudResult<StatusResponse> {
61        self.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.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.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            .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.post_empty(&ApiPaths::tenant_rotate_credentials(tenant_id))
99            .await
100    }
101
102    pub async fn rotate_sync_token(
103        &self,
104        tenant_id: &TenantId,
105    ) -> CloudResult<RotateSyncTokenResponse> {
106        let response: ApiResponse<RotateSyncTokenResponse> = self
107            .post_empty(&ApiPaths::tenant_rotate_sync_token(tenant_id))
108            .await?;
109        Ok(response.data)
110    }
111
112    pub async fn list_secrets(&self, tenant_id: &TenantId) -> CloudResult<ListSecretsResponse> {
113        self.get(&ApiPaths::tenant_secrets(tenant_id)).await
114    }
115
116    pub async fn set_custom_domain(
117        &self,
118        tenant_id: &TenantId,
119        domain: &str,
120    ) -> CloudResult<CustomDomainResponse> {
121        let request = SetCustomDomainRequest {
122            domain: domain.to_string(),
123        };
124        let response: ApiResponse<CustomDomainResponse> = self
125            .post(&ApiPaths::tenant_custom_domain(tenant_id), &request)
126            .await?;
127        Ok(response.data)
128    }
129
130    pub async fn get_custom_domain(
131        &self,
132        tenant_id: &TenantId,
133    ) -> CloudResult<CustomDomainResponse> {
134        let response: ApiResponse<CustomDomainResponse> =
135            self.get(&ApiPaths::tenant_custom_domain(tenant_id)).await?;
136        Ok(response.data)
137    }
138
139    pub async fn delete_custom_domain(&self, tenant_id: &TenantId) -> CloudResult<()> {
140        self.delete(&ApiPaths::tenant_custom_domain(tenant_id))
141            .await
142    }
143
144    pub async fn cancel_subscription(&self, tenant_id: &TenantId) -> CloudResult<()> {
145        self.post_empty(&ApiPaths::tenant_subscription_cancel(tenant_id))
146            .await
147    }
148}