liteguard 0.7.20260603

Feature guards, observability, and security response in a single import. Evaluated locally, zero network overhead per check
Documentation
# liteguard

[![Rust SDK](https://github.com/liteguard/liteguard/actions/workflows/test-rust-sdk.yml/badge.svg)](https://github.com/liteguard/liteguard/actions/workflows/test-rust-sdk.yml)
[![crates.io](https://img.shields.io/crates/v/liteguard)](https://crates.io/crates/liteguard)
[![docs.rs](https://docs.rs/liteguard/badge.svg)](https://docs.rs/liteguard)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/liteguard/liteguard/blob/main/LICENSE)

- Website: [liteguard.io]https://liteguard.io
- Project Page: [https://github.com/liteguard/liteguard]https://github.com/liteguard/liteguard
- Issues: [https://github.com/liteguard/liteguard/issues/new]https://github.com/liteguard/liteguard/issues/new

> Feature guards, observability, and security response in a single import. Evaluated locally, zero network overhead per check.

Liteguard for Rust. Initialize one process-scoped `Client`, then create explicit immutable request `Scope`s for per-request properties and protected context.

---

## Installation

```toml
[dependencies]
liteguard = "0.7"
```

---

## Quick Start

```rust
use liteguard::{Client, ClientOptions, Options, Properties, ProtectedContext};
use std::collections::HashMap;

#[tokio::main]
async fn main() {
    let client = Client::init("pct-...", ClientOptions {
        environment: Some("env-production".into()),
        ..Default::default()
    })
    .await
    .unwrap();

    let scope = client.create_scope(
        Properties::new()
            .set("user_id", "user-123")
            .set("plan", "pro")
            .set("region", "us-east-1"),
    );

    if scope.is_open("payments.checkout") {
        // guard is open
    }

    let protected_scope = scope
        .bind_protected_context(ProtectedContext {
            properties: HashMap::from([("email".to_string(), "alice@acme.com".to_string())]),
            signature: "sig-123".into(),
            issued_at: None,
            expires_at: None,
        })
        .await
        .unwrap();

    let session = protected_scope.execute_if_open("payments.checkout", || {
        create_checkout_session()
    });

    if session.is_none() {
        // guard was closed
    }

    client.shutdown().await.unwrap();
}
```

---

## Request Scoping

The core Rust API is scope-first:

- `Client` is process-scoped and shared
- `Scope` is immutable and request-scoped
- ordinary properties live on `Scope`
- protected context binds a derived `Scope` and may fetch or reuse a cached protected bundle

Create derived scopes with ordinary properties:

```rust
use liteguard::Properties;

let base = client.create_scope(Properties::new().set("request_id", "req-123"));
let pro_scope = base.with_properties(Properties::new().set("plan", "pro"));
let cleared = pro_scope.clear_properties(&["plan"]);
```

Bind protected context per request:

```rust
use liteguard::ProtectedContext;
use std::collections::HashMap;

let protected = scope
    .bind_protected_context(ProtectedContext {
        properties: HashMap::from([("email".to_string(), "alice@acme.com".to_string())]),
        signature: "sig-123".into(),
        issued_at: None,
        expires_at: None,
    })
    .await?;

let public_again = protected.clear_protected_context().await?;
```

---

## API Reference

### `Client::init(project_client_token, options) -> Result<Client>`

Initializes the SDK, performs the initial public-bundle fetch, then starts background refresh and signal flush tasks.

### `client.create_scope(properties) -> Scope`

Creates a request scope with the provided ordinary properties.

### `scope.evaluate(name) -> GuardDecision`

Returns a `GuardDecision` containing the full evaluation result: `is_open`, `name`, `adopted`, `reason`, `matched_rule_index`, and `properties`.

### `scope.is_open(name) -> bool`

Evaluates a guard for that request scope and emits a `guard_check` signal.

### `scope.is_open_with_options(name, options) -> bool`

Evaluates a guard with per-call property overrides merged on top of the scope's properties.

### `scope.peek_is_open(name) -> bool`

Read-only evaluation without emitting telemetry or consuming a rate-limit slot.

### `scope.execute_if_open(name, f) -> Option<T>`

Evaluates the guard and executes `f` only when it is open. Emits both `guard_check` and `guard_execution` telemetry.

### `scope.try_execute_if_open(name, f) -> Result<Option<T>, E>`

Explicit fallible variant of guarded execution. Returns `Ok(None)` when the guard is closed, `Ok(Some(value))` when the guard is open and `f` succeeds, and `Err(error)` when the guard is open but `f` fails.

### `scope.bind_protected_context(protected_context).await -> Result<Scope>`

Returns a derived request scope using a protected bundle keyed by the protected-context fingerprint.

### `scope.clear_protected_context().await -> Result<Scope>`

Returns a derived request scope back on the public bundle.

### `scope.start_execution() -> Scope`

Creates an execution correlation handle for linking related guard checks and signals.

### `scope.get_properties() -> Properties`

Returns the current property bag for the scope. Useful for serializing and transporting properties across service boundaries.

### `client.flush().await`

Flushes buffered signals immediately.

### `client.shutdown().await`

Stops background tasks and flushes buffered signals.

---

## Guard Evaluation

Rules are evaluated in order, first matching rule wins. If no rule matches, the guard's default applies.

### Operators

| Operator | Description |
|---|---|
| `EQUALS` | Exact match |
| `NOT_EQUALS` | Negated exact match |
| `IN` | Value in a set |
| `NOT_IN` | Value not in a set |
| `REGEX` | Regular expression match |
| `GT` / `GTE` | Greater than / greater or equal |
| `LT` / `LTE` | Less than / less or equal |

---

## Development

Build-time auto-instrumentation via the [Liteguard CLI](https://github.com/liteguard/liteguard/tree/main/cli) injects guard points around third-party call sites during the build step.

```bash
make test-rust
```

---

## License

Apache 2.0 see [LICENSE](https://github.com/liteguard/liteguard/blob/main/LICENSE).