1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CloudApiResponse<T> {
9 pub data: T,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct CloudApiError {
14 pub error: CloudApiErrorDetail,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct CloudApiErrorDetail {
19 pub code: String,
20 pub message: String,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct CloudUserInfo {
25 pub id: String,
26 pub email: String,
27 #[serde(default)]
28 pub name: Option<String>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct CloudCustomerInfo {
33 pub id: String,
34 #[serde(default)]
35 pub status: Option<String>,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "snake_case")]
40pub enum SubscriptionStatus {
41 Active,
42 Trialing,
43 PastDue,
44 Paused,
45 Canceled,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct CloudPlanInfo {
50 #[serde(default)]
51 pub id: Option<String>,
52 pub name: String,
53 pub memory_mb: i32,
54 pub volume_gb: i32,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
58pub struct CloudPlan {
59 pub id: String,
60 pub name: String,
61 pub paddle_price_id: String,
62 #[serde(default)]
63 pub memory_mb_default: i32,
64 #[serde(default)]
65 pub volume_gb: i32,
66 #[serde(default)]
67 pub max_tenants: Option<i32>,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
71#[serde(rename_all = "snake_case")]
72pub enum CloudTenantStatus {
73 Pending,
74 Active,
75 Suspended,
76 Deleted,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct CloudTenantInfo {
81 pub id: String,
82 pub name: String,
83 #[serde(default)]
84 pub subscription_id: Option<String>,
85 #[serde(default)]
86 pub subscription_status: Option<SubscriptionStatus>,
87 #[serde(default)]
88 pub app_id: Option<String>,
89 #[serde(default)]
90 pub hostname: Option<String>,
91 #[serde(default)]
92 pub region: Option<String>,
93 #[serde(default)]
94 pub status: Option<CloudTenantStatus>,
95 #[serde(default)]
96 pub plan: Option<CloudPlanInfo>,
97 #[serde(default)]
98 pub external_db_access: bool,
99 pub database_url: String,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
103pub struct CloudTenant {
104 pub id: String,
105 pub name: String,
106 pub fly_app_name: Option<String>,
107 pub fly_hostname: Option<String>,
108 #[serde(default)]
109 pub hostname: Option<String>,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113pub struct CloudTenantStatusResponse {
114 pub status: String,
115 #[serde(default)]
116 pub message: Option<String>,
117 #[serde(default)]
118 pub app_url: Option<String>,
119 #[serde(default)]
120 pub secrets_url: Option<String>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct CloudTenantSecrets {
125 pub jwt_secret: String,
126 pub database_url: String,
127 pub app_url: String,
128 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub sync_token: Option<String>,
130 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub anthropic_api_key: Option<String>,
132 #[serde(default, skip_serializing_if = "Option::is_none")]
133 pub openai_api_key: Option<String>,
134 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub gemini_api_key: Option<String>,
136}
137
138#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
139pub struct SetExternalDbAccessRequest {
140 pub enabled: bool,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct ExternalDbAccessResponse {
145 pub tenant_id: String,
146 pub external_db_access: bool,
147 pub database_url: String,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct RotateCredentialsResponse {
152 pub status: String,
153 pub message: String,
154 pub internal_database_url: String,
155 pub external_database_url: String,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct RotateSyncTokenResponse {
160 pub status: String,
161 pub sync_token: String,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct UserMeResponse {
166 pub user: CloudUserInfo,
167 #[serde(default)]
168 pub customer: Option<CloudCustomerInfo>,
169 #[serde(default)]
170 pub tenants: Vec<CloudTenantInfo>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct CloudListResponse<T> {
175 pub data: Vec<T>,
176}
177
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct RegistryToken {
180 pub registry: String,
181 pub username: String,
182 pub token: String,
183 pub repository: String,
184 pub tag: String,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct DeployResponse {
189 pub status: String,
190 pub app_url: Option<String>,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
194pub struct CloudStatusResponse {
195 pub status: String,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct SetSecretsRequest {
200 pub secrets: HashMap<String, String>,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct CheckoutRequest {
205 pub price_id: String,
206 pub region: String,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub redirect_uri: Option<String>,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct CheckoutResponse {
213 pub checkout_url: String,
214 pub transaction_id: String,
215 pub checkout_session_id: String,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
219#[serde(rename_all = "snake_case")]
220pub enum ProvisioningEventType {
221 SubscriptionCreated,
222 TenantCreated,
223 DatabaseCreated,
224 SecretsStored,
225 VmProvisioningStarted,
226 VmProvisioningProgress,
227 VmProvisioned,
228 SecretsConfigured,
229 InfrastructureReady,
230 TenantReady,
231 ProvisioningFailed,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct ProvisioningEvent {
236 pub tenant_id: String,
237 pub event_type: ProvisioningEventType,
238 pub status: String,
239 #[serde(default)]
240 pub message: Option<String>,
241 #[serde(default)]
242 pub app_url: Option<String>,
243 #[serde(default)]
244 pub fly_app_name: Option<String>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize)]
248pub struct CheckoutEvent {
249 pub checkout_session_id: String,
250 pub tenant_id: String,
251 pub tenant_name: String,
252 pub event_type: ProvisioningEventType,
253 pub status: String,
254 #[serde(default)]
255 pub message: Option<String>,
256 #[serde(default)]
257 pub app_url: Option<String>,
258 #[serde(default)]
259 pub fly_app_name: Option<String>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
263pub struct CloudLogEntry {
264 pub timestamp: String,
265 pub message: String,
266 #[serde(default)]
267 pub level: Option<String>,
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct CloudLogsResponse {
272 pub logs: Vec<CloudLogEntry>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
276pub struct ListSecretsResponse {
277 pub keys: Vec<String>,
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
281pub struct SetCustomDomainRequest {
282 pub domain: String,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
286pub struct DnsInstructions {
287 pub record_type: String,
288 pub host: String,
289 pub value: String,
290 pub ttl: u32,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
294pub struct CustomDomainResponse {
295 pub domain: String,
296 pub status: String,
297 pub verified: bool,
298 pub dns_target: String,
299 pub dns_instructions: DnsInstructions,
300 #[serde(default, skip_serializing_if = "Option::is_none")]
301 pub created_at: Option<String>,
302 #[serde(default, skip_serializing_if = "Option::is_none")]
303 pub verified_at: Option<String>,
304}
305
306pub type ApiResponse<T> = CloudApiResponse<T>;
307pub type ApiError = CloudApiError;
308pub type ApiErrorDetail = CloudApiErrorDetail;
309pub type UserInfo = CloudUserInfo;
310pub type CustomerInfo = CloudCustomerInfo;
311pub type PlanInfo = CloudPlanInfo;
312pub type Plan = CloudPlan;
313pub type TenantInfo = CloudTenantInfo;
314pub type Tenant = CloudTenant;
315pub type TenantStatus = CloudTenantStatusResponse;
316pub type TenantSecrets = CloudTenantSecrets;
317pub type ListResponse<T> = CloudListResponse<T>;
318pub type StatusResponse = CloudStatusResponse;
319pub type LogEntry = CloudLogEntry;
320pub type LogsResponse = CloudLogsResponse;