Skip to main content

systemprompt_cloud/api_client/
tenant_api.rs

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