# Browsr Client

Rust client for browser automation via the Browsr API.

## Installation

```toml
[dependencies]
browsr-client = { path = "../browsr-client" }
```

## Configuration

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `BROWSR_BASE_URL` | Base URL of the Browsr server | `https://api.browsr.dev` |
| `BROWSR_API_KEY` | API key for authentication | None (optional for local) |
| `BROWSR_API_URL` | Legacy alias for `BROWSR_BASE_URL` | None |
| `BROWSR_HOST` / `BROWSR_PORT` | Alternative local server specification | None |

### Initialization

```rust
use browsr_client::{BrowsrClient, BrowsrClientConfig};

// From environment variables (recommended for production)
let client = BrowsrClient::from_env();

// Local development (no auth needed)
let client = BrowsrClient::new("http://localhost:8082");

// With API key authentication
let client = BrowsrClient::new("https://api.browsr.dev")
    .with_api_key("your-api-key");

// Explicit configuration
let config = BrowsrClientConfig::new("https://api.browsr.dev")
    .with_api_key("your-api-key")
    .with_timeout(60)
    .with_headless(true);
let client = BrowsrClient::from_client_config(config);
```

## API Reference

### Session Management

```rust
// List sessions
let sessions = client.list_sessions().await?;

// Create a session
let session_id = client.create_session().await?;

// Destroy a session
client.destroy_session(&session_id).await?;
```

### Navigation

```rust
// Navigate to a URL
let response = client.navigate("https://example.com", None).await?;
```

### Element Interaction

```rust
// Click an element
client.click("#button", None).await?;

// Type text into an input
client.type_text("#input", "Hello World", None).await?;

// Wait for an element
client.wait_for_element(".loading", Some(5000), None).await?;
```

### Content Extraction

```rust
// Get page title
let response = client.get_title(None).await?;

// Get element text
let response = client.get_text("h1", None).await?;

// Get HTML content
let response = client.get_content(Some("article".to_string()), None).await?;
```

### Structured Extraction (AI-powered)

```rust
// Extract structured data using natural language
let response = client.extract_structured(
    "Extract all product names and prices from the page",
    None,  // Optional JSON schema
    None,  // Optional max_chars
    None,  // Optional session_id
).await?;
```

### Screenshots

```rust
// Take a screenshot
let response = client.screenshot(false, None).await?;  // viewport only

// Full page screenshot
let response = client.screenshot(true, None).await?;
```

### JavaScript Execution

```rust
// Evaluate JavaScript
let response = client.evaluate("document.title", None).await?;
```

### Observation

Get a complete snapshot of the browser state:

```rust
use browsr_client::ObserveOptions;

let options = ObserveOptions {
    use_image: Some(true),
    full_page: Some(false),
    wait_ms: Some(500),
    include_content: Some(true),
};

let observation = client.observe(None, None, options).await?;
println!("URL: {}", observation.dom_snapshot.url);
println!("Title: {}", observation.dom_snapshot.title);
```

### Web Scraping

```rust
use browsr_client::BrowsrClient;
use browsr_types::ScrapeApiRequest;

// Simple URL scraping
let result = client.scrape_url("https://example.com").await?;

// With full options
let request = ScrapeApiRequest::new("https://example.com");
let result = client.scrape_v1(request).await?;
```

### Web Search

```rust
// Simple search
let results = client.search_query("rust programming").await?;

// With options
use browsr_types::SearchOptions;

let options = SearchOptions {
    query: "rust programming".to_string(),
    limit: Some(10),
};
let results = client.search(options).await?;
```

### Low-Level Command Execution

```rust
use browsr_types::Commands;

// Execute multiple commands
let commands = vec![
    Commands::NavigateTo { url: "https://example.com".to_string() },
    Commands::WaitForElement {
        selector: "h1".to_string(),
        timeout_ms: Some(5000),
        visible_only: None,
    },
    Commands::Screenshot { full_page: None, path: None },
];

let response = client.execute_commands(commands, None, None, None).await?;
```

## Utilities

```rust
// Check if client has API key configured
if client.has_auth() {
    println!("Authenticated");
}

// Check if using local server
if client.is_local() {
    println!("Local development mode");
}

// Get base URL
let url = client.base_url();
```

## Error Handling

```rust
use browsr_client::ClientError;

match client.navigate("https://example.com", None).await {
    Ok(response) => println!("Success"),
    Err(ClientError::Http(e)) => eprintln!("Network error: {}", e),
    Err(ClientError::InvalidResponse(msg)) => eprintln!("Invalid response: {}", msg),
    Err(ClientError::Serialization(e)) => eprintln!("JSON error: {}", e),
    Err(ClientError::Stdout(msg)) => eprintln!("Stdout transport error: {}", msg),
    Err(ClientError::Io(e)) => eprintln!("IO error: {}", e),
}
```

## Complete Example

```rust
use browsr_client::{BrowsrClient, ObserveOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client from environment
    let client = BrowsrClient::from_env();

    // Navigate to a page
    client.navigate("https://news.ycombinator.com", None).await?;

    // Wait for content to load
    client.wait_for_element(".itemlist", Some(5000), None).await?;

    // Extract structured data
    let response = client.extract_structured(
        "Extract the top 5 story titles and their URLs",
        None,
        None,
        None,
    ).await?;

    println!("Extracted: {:?}", response);

    // Take a screenshot
    let screenshot = client.screenshot(false, None).await?;
    println!("Screenshot taken");

    Ok(())
}
```


