arxivis 1.0.0

Official Rust SDK for the Arxivis document store
Documentation
# arxivis-rs

Official Rust SDK for the [Arxivis](https://github.com/v019-Labs/arxivis) document store.

## Requirements

- Rust 2021 edition (MSRV: 1.75)
- Tokio async runtime

## Installation

Add to your `Cargo.toml`:

```toml
[dependencies]
arxivis = { path = "./sdk/rust" }
tokio = { version = "1", features = ["full"] }
```

## Quick start

```rust
use arxivis::{ArxivisClient, UploadOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = ArxivisClient::new("http://localhost:8080", "axv_xxxx_yyyy")?;

    // Upload
    let data = std::fs::read("invoice.pdf")?;
    let record = client
        .upload(
            data,
            "invoice.pdf",
            UploadOptions::new()
                .path("/invoices/2024/")
                .tags(vec!["cliente".into(), "enero".into()])
                .compress(true),
        )
        .await?;
    println!("stored: {}", record.id);

    // List
    let page = client.list("/invoices/2024/", Default::default()).await?;
    for f in &page.files {
        println!("{} — {} bytes", f.original_name, f.size);
    }

    // Search
    let hits = client.search("factura", Default::default()).await?;
    println!("{} results", hits.total);

    // Download
    let bytes = client.download(&record.id).await?;
    std::fs::write("copy.pdf", &bytes)?;

    // Delete
    client.delete_file(&record.id).await?;

    Ok(())
}
```

## API reference

### `ArxivisClient`

```rust
// Create
let client = ArxivisClient::new(base_url, api_key)?;

// Custom timeout
use std::time::Duration;
let client = ArxivisClient::new(base_url, api_key)?
    .with_timeout(Duration::from_secs(120))?;
```

| Method | Return | Description |
|---|---|---|
| `get_stats()` | `Stats` | Aggregate storage statistics |
| `upload(data, filename, opts)` | `FileRecord` | Upload raw bytes |
| `list(path, opts)` | `ListResult` | Paginated file listing |
| `get(id)` | `FileRecord` | Fetch file metadata |
| `download(id)` | `Bytes` | Download raw bytes |
| `delete_file(id)` | `()` | Soft-delete a file |
| `download_zip(ids)` | `Bytes` | Export files as ZIP |
| `create_folder(path)` | `String` | Create virtual folder |
| `search(query, opts)` | `ListResult` | Full-text search (FTS5) |
| `semantic_search(query, opts)` | `SearchResult` | Vector similarity search |
| `hybrid_search(query, opts)` | `SearchResult` | FTS5 + semantic fusion |
| `create_key(name)` | `CreateKeyResult` | Create API key |
| `list_keys()` | `Vec<ApiKey>` | List API keys |
| `revoke_key(id)` | `()` | Revoke an API key |
| `download_url(id)` | `String` | Direct download URL |
| `preview_url(id)` | `String` | Inline preview URL |
| `path_url(file_path)` | `String` | Virtual-path URL |

### `UploadOptions` builder

```rust
use arxivis::UploadOptions;

let opts = UploadOptions::new()
    .path("/invoices/2024/")
    .tags(vec!["cliente".into()])
    .compress(true)
    .encrypt(false);
```

### `ListOptions` / `SearchOptions`

```rust
use arxivis::{ListOptions, SearchOptions};

let list_opts = ListOptions::new().limit(20).offset(40);
let search_opts = SearchOptions::new().limit(10);
```

### `ArxivisError`

```rust
use arxivis::ArxivisError;

match client.get("unknown-id").await {
    Err(ArxivisError::Api { status, message }) if status == 404 => {
        println!("not found");
    }
    Err(e) if e.is_unauthorized() => println!("check your API key"),
    Err(e) if e.is_rate_limited() => println!("slow down"),
    Err(e) => eprintln!("error: {e}"),
    Ok(record) => println!("{}", record.id),
}
```

## License

MIT