Skip to main content

heyo_sdk/
types.rs

1//! Public types. Field names mirror the cloud HTTP API (snake_case both on
2//! the wire and in Rust), so the SDK stays a thin wrapper rather than a
3//! parallel domain model.
4
5use std::collections::HashMap;
6
7use serde::{Deserialize, Serialize};
8
9/// `US` or `EU`. The wire field is uppercase; we preserve that.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11pub enum SandboxRegion {
12    US,
13    EU,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "lowercase")]
18pub enum SandboxDriver {
19    Libvirt,
20    Firecracker,
21    Kvm,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(rename_all = "lowercase")]
26pub enum SandboxSize {
27    Micro,
28    Mini,
29    Small,
30    Medium,
31    Large,
32}
33
34impl SandboxSize {
35    pub fn as_str(&self) -> &'static str {
36        match self {
37            SandboxSize::Micro => "micro",
38            SandboxSize::Mini => "mini",
39            SandboxSize::Small => "small",
40            SandboxSize::Medium => "medium",
41            SandboxSize::Large => "large",
42        }
43    }
44}
45
46/// Lifecycle states the cloud reports.
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(rename_all = "kebab-case")]
49pub enum SandboxStatus {
50    Provisioning,
51    Running,
52    Stopped,
53    Paused,
54    Failed,
55    #[serde(rename = "cold-stored")]
56    ColdStored,
57    #[serde(other)]
58    Unknown,
59}
60
61/// Options accepted by `Sandbox::create`. All fields except `image`/`region`
62/// may be left unset; the server applies defaults.
63#[derive(Debug, Clone, Default, Serialize)]
64pub struct SandboxCreateOptions {
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub name: Option<String>,
67    #[serde(skip_serializing_if = "Option::is_none", rename = "archive_id")]
68    pub archive_id: Option<String>,
69    /// Defaults to `US` if unset.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub region: Option<SandboxRegion>,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub driver: Option<SandboxDriver>,
74    /// Image identifier (e.g. `ubuntu:24.04`, `bun`, `pi-…`). Defaults to
75    /// `ubuntu:24.04` if unset.
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub image: Option<String>,
78    #[serde(skip_serializing_if = "Option::is_none", rename = "start_command")]
79    pub start_command: Option<String>,
80    #[serde(default, rename = "open_ports", skip_serializing_if = "Vec::is_empty")]
81    pub open_ports: Vec<u16>,
82    #[serde(skip_serializing_if = "Option::is_none", rename = "ttl_seconds")]
83    pub ttl_seconds: Option<u64>,
84    #[serde(skip_serializing_if = "Option::is_none", rename = "disk_size_gb")]
85    pub disk_size_gb: Option<u32>,
86    #[serde(skip_serializing_if = "Option::is_none", rename = "working_directory")]
87    pub working_directory: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none", rename = "env_vars")]
89    pub env_vars: Option<HashMap<String, String>>,
90    #[serde(skip_serializing_if = "Option::is_none", rename = "setup_hooks")]
91    pub setup_hooks: Option<Vec<String>>,
92    #[serde(skip_serializing_if = "Option::is_none", rename = "size_class")]
93    pub size_class: Option<SandboxSize>,
94    /// Maximum time `create()` will wait for the sandbox to leave the
95    /// `provisioning` state. `None` ⇒ default 5 minutes. `Some(Duration::ZERO)`
96    /// ⇒ return immediately while it's still provisioning.
97    #[serde(skip_serializing)]
98    pub wait_for_ready: Option<std::time::Duration>,
99}
100
101#[derive(Debug, Clone, Deserialize)]
102pub struct SandboxInfo {
103    pub id: String,
104    #[serde(default)]
105    pub name: String,
106    pub status: SandboxStatus,
107    #[serde(default)]
108    pub image: String,
109    #[serde(default)]
110    pub region: Option<String>,
111    #[serde(default)]
112    pub start_command: Option<String>,
113    #[serde(default)]
114    pub working_directory: Option<String>,
115    #[serde(default)]
116    pub size_class: Option<String>,
117    #[serde(default)]
118    pub env_vars: Option<HashMap<String, String>>,
119    #[serde(default)]
120    pub setup_hooks: Option<Vec<String>>,
121    #[serde(default)]
122    pub uptime_secs: u64,
123    #[serde(default)]
124    pub ttl_seconds: Option<u64>,
125    #[serde(default)]
126    pub is_deployed: bool,
127    #[serde(default)]
128    pub error_message: Option<String>,
129    pub status_changed_at: String,
130    #[serde(default)]
131    pub urls: Vec<BoundUrl>,
132    /// Free-form JSON tags set by the server (e.g. `{"project_id": "..."}`).
133    /// Mirrors the `metadata` column on `deployed_sandbox`.
134    #[serde(default)]
135    pub metadata: Option<serde_json::Value>,
136}
137
138#[derive(Debug, Clone, Deserialize)]
139pub struct PublicImage {
140    pub id: String,
141    #[serde(default)]
142    pub name: Option<String>,
143    #[serde(default)]
144    pub description: Option<String>,
145    #[serde(default)]
146    pub backend_type: Option<String>,
147    #[serde(default)]
148    pub format: String,
149    #[serde(default)]
150    pub size_bytes: u64,
151    #[serde(default)]
152    pub created_at: String,
153}
154
155#[derive(Debug, Clone, Deserialize, Serialize)]
156pub struct BoundUrl {
157    pub subdomain: String,
158    #[serde(default)]
159    pub hostname: String,
160    #[serde(default)]
161    pub url: String,
162    pub port: u16,
163    #[serde(default, rename = "is_public")]
164    pub is_public: bool,
165}
166
167#[derive(Debug, Clone, Default)]
168pub struct CommandRunOptions {
169    pub cwd: Option<String>,
170    pub env: Option<HashMap<String, String>>,
171    pub timeout: Option<std::time::Duration>,
172}
173
174#[derive(Debug, Clone)]
175pub struct CommandResult {
176    pub stdout: String,
177    pub stderr: String,
178    pub exit_code: i32,
179    /// Combined stdout+stderr as the backend reports it.
180    pub output: String,
181}