sprites 0.1.0

Official Rust SDK for Sprites - stateful sandbox environments from Fly.io
Documentation
# sprites-rs

[![Crates.io](https://img.shields.io/crates/v/sprites.svg)](https://crates.io/crates/sprites)
[![Documentation](https://docs.rs/sprites/badge.svg)](https://docs.rs/sprites)
[![License](https://img.shields.io/crates/l/sprites.svg)](LICENSE)

Official Unofficial Rust SDK for [Sprites](https://sprites.dev) - stateful sandbox environments from [Fly.io](https://fly.io).

Sprites are lightweight, persistent VMs powered by Firecracker. They hibernate when idle (no compute cost) and wake instantly when needed. Create checkpoints in ~300ms and restore to any previous state.

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
sprites = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
```

## Quick Start

```rust
use sprites::SpritesClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a client with your API token
    let client = SpritesClient::new(std::env::var("SPRITES_TOKEN")?);

    // Create a sprite
    let sprite = client.create("my-sprite").await?;

    // Run commands
    let output = sprite.command("uname").arg("-a").output().await?;
    println!("{}", output.stdout_str());

    // Create a checkpoint
    let checkpoint = sprite.checkpoint("Initial state").await?;
    println!("Created checkpoint: {}", checkpoint.id);

    // Clean up
    sprite.destroy().await?;

    Ok(())
}
```

## Features

### Command Execution

The `Command` API mirrors `std::process::Command`:

```rust
let output = sprite
    .command("npm")
    .arg("install")
    .current_dir("/app")
    .env("NODE_ENV", "production")
    .output()
    .await?;

if output.success() {
    println!("stdout: {}", output.stdout_str());
} else {
    eprintln!("stderr: {}", output.stderr_str());
}
```

For long-running processes, use `spawn()` for streaming I/O:

```rust
let mut child = sprite.command("npm").arg("run").arg("dev").spawn().await?;

// Wait for completion
let status = child.wait().await?;
println!("Process exited with: {:?}", status);
```

### Checkpoints

Create snapshots for instant rollback (~300ms):

```rust
// Checkpoint before risky operations
let checkpoint = sprite.checkpoint("Before migration").await?;

// Run migrations...
sprite.command("npm").arg("run").arg("migrate").output().await?;

// If something goes wrong, restore instantly
sprite.restore(&checkpoint.id).await?;

// List all checkpoints
let checkpoints = sprite.list_checkpoints().await?;
for cp in checkpoints {
    println!("{}: {:?}", cp.id, cp.comment);
}
```

### Network Policies

Control egress with DNS-based filtering:

```rust
use sprites::{NetworkPolicy, NetworkPolicyRule, PolicyAction};

let policy = NetworkPolicy {
    rules: vec![
        NetworkPolicyRule {
            domain: "api.anthropic.com".into(),
            action: PolicyAction::Allow,
        },
        NetworkPolicyRule {
            domain: "*.npmjs.org".into(),
            action: PolicyAction::Allow,
        },
        NetworkPolicyRule {
            domain: "*".into(),
            action: PolicyAction::Deny,
        },
    ],
    include: vec![], // Optional policy bundles
};

sprite.set_policy(policy).await?;
```

### Filesystem Access

Read and write files without executing commands:

```rust
let fs = sprite.filesystem();

// Read a file
let content = fs.read_file("/app/config.json").await?;

// Write a file
fs.write_file("/app/data.txt", b"Hello, Sprites!").await?;

// List directory
let entries = fs.read_dir("/app").await?;
for entry in entries {
    println!("{}: {} bytes", entry.name, entry.size);
}
```

### Port Forwarding

Proxy local ports to your sprite:

```rust
// Forward local:8080 -> sprite:3000
let proxy = sprite.proxy_port(8080, 3000).await?;
println!("Proxy listening on {}", proxy.local_addr());

// Access your sprite's server at localhost:8080
// ...

proxy.close().await?;
```

## Authentication

Get your API token from [sprites.dev](https://sprites.dev) or exchange Fly.io credentials:

```rust
// Using Fly.io macaroon
let token = SpritesClient::create_token(
    std::env::var("FLY_API_TOKEN")?,
    "your-org-slug",
    None,
).await?;

let client = SpritesClient::new(token);
```

## Configuration

Use the builder for advanced configuration:

```rust
use std::time::Duration;

let client = SpritesClient::builder(token)
    .base_url("https://api.sprites.dev")
    .timeout(Duration::from_secs(30))
    .build();
```

## Examples

See the [examples](examples/) directory:

```bash
# Basic usage
cargo run --example basic

# Debug exec streaming
cargo run --example exec_debug
```

## Related

- [sprites-go]https://github.com/superfly/sprites-go - Official Go SDK
- [Sprites CLI]https://sprites.dev/docs/cli - Command-line interface
- [Sprites Documentation]https://sprites.dev/docs - Full documentation

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.

## License

Apache-2.0 - see [LICENSE](LICENSE) for details.