# heyo-sdk
Rust SDK for the Heyo cloud sandbox API. Mirrors the TypeScript SDK
(`sdk-ts/` → `@heyocomputer/sdk`) so the same patterns translate across
languages.
```rust
use heyo_sdk::{Sandbox, SandboxCreateOptions, SandboxSize, HeyoClientOptions, CommandRunOptions};
#[tokio::main]
async fn main() -> Result<(), heyo_sdk::HeyoError> {
let sandbox = Sandbox::create(
SandboxCreateOptions {
image: Some("ubuntu:24.04".into()),
size_class: Some(SandboxSize::Small),
ttl_seconds: Some(600),
..Default::default()
},
HeyoClientOptions::default(), // reads HEYO_API_KEY
)
.await?;
let out = sandbox.commands().run("uname -a", CommandRunOptions::default()).await?;
println!("{}", out.stdout);
sandbox.kill().await?;
Ok(())
}
```
## Surface
- `Sandbox` — VM lifecycle (`create`, `connect`, `list`, `info`,
`wait_for_ready`, `kill`, `stop/start/restart`, `set_ttl`, `resize`,
`checkpoint/restore`, `replace_mount`, `bind_port`, `shell`).
- `Sandbox::commands()` — `.run(cmd, opts)` against `/sandbox/:id/exec`.
- `Sandbox::files()` — `.read` / `.write` against `/sandbox/:id/read-file` /
`/write-file` (base64 over the wire, exposed as `Vec<u8>` / `String`).
- `ShellSession` — persistent interactive shell over the WebSocket protocol,
with `output()` and `events()` streams, auto-reconnect, and graceful
`close()`.
- `Database` — cloud sqlite (`create`, `connect`, `list`, `regions`, `info`,
`exec`, `batch`, `connect_token`, `connection_info`, `list_connections`,
`revoke_connection`, `checkout`, `checkin`, `delete`).
- `archive_dir(path, opts)` — tar+gz a local directory, presign + PUT + finalize.
## Errors
Everything returns `Result<T, HeyoError>`. Notable variants:
- `Authentication` — no API key.
- `InvalidArgument(String)` — 400/422.
- `NotFound(String)` — 404.
- `Api { status, message, body }` — 5xx and friends.
- `Timeout(Duration, String)` — `wait_for_*` budget exceeded.
- `SandboxFailed { sandbox_id, reason }` — provisioning ended in `failed`.
- `CheckinConflict { expected, current }` — optimistic concurrency on
`Database::checkin`.
- `SessionExpired { session_id }`, `Connection(String)`, `ShellExit(i32)` —
shell session failures.
## Configuration
`HeyoClient::new(HeyoClientOptions { .. })` (or any high-level
`Sandbox::create` / `Database::create` etc. that takes a `HeyoClientOptions`)
resolves config in this order:
1. Fields set on `HeyoClientOptions` win.
2. `HEYO_API_KEY` env var supplies `api_key` when unset.
3. `base_url` defaults to `https://server.heyo.computer`.
4. `timeout` defaults to 60s.
## Running integration tests
All tests under `tests/` are marked `#[ignore]` because they need a live
cloud API + an API key. Set up `.env` next to `Cargo.toml`:
```env
HEYO_API_KEY=heyo_api_xxxxxxxxxxxx
# optional — defaults to localhost:4445 ("local")
HEYO_ENV=local
# or HEYO_BASE_URL=http://localhost:4445
```
Then run individual tests:
```bash
cargo test --test smoke -- --ignored --nocapture
cargo test --test shell_protocol -- --ignored --nocapture
HEYO_DB_ID=db-xxxx cargo test --test db_select_one -- --ignored --nocapture
HEYO_DB_ID=db-xxxx cargo test --test db_checkout_checkin -- --ignored --nocapture
```
Tests skip cleanly with an `eprintln!` message when required env is missing,
so plain `cargo test` (no `--ignored`) is a no-op.
## Status / limitations
- `archive_dir` v0 excludes a fixed deny-list (`.git`, `node_modules`,
`target`, …) plus any caller-supplied directory names. `.gitignore`
parsing is a follow-up.
- `Sandbox::list_public_images` matches the TS surface but the underlying
`/public-images` endpoint may not be wired everywhere; expect 404s on
older clouds.
- The shell test exercises open / IO / resize / close. Forced-reconnect
testing exists in the TS SDK by reaching into a private socket field;
Rust integration tests rely on natural disconnects rather than poking
internals.