liteguard 0.4.20260317

Feature guards, observability, and security response in a single import. Evaluated locally, zero network overhead per check
Documentation
// Code generated by tools/src/proto-codegen.ts DO NOT EDIT.
// Source of truth: proto/liteguard.proto  Run: make proto

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// A typed property value for rule evaluation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PropertyValue {
    Bool(bool),
    Number(f64),
    Text(String),
}

impl From<bool> for PropertyValue {
    fn from(v: bool) -> Self {
        PropertyValue::Bool(v)
    }
}
impl From<f64> for PropertyValue {
    fn from(v: f64) -> Self {
        PropertyValue::Number(v)
    }
}
impl From<i64> for PropertyValue {
    fn from(v: i64) -> Self {
        PropertyValue::Number(v as f64)
    }
}
impl From<&str> for PropertyValue {
    fn from(v: &str) -> Self {
        PropertyValue::Text(v.to_owned())
    }
}
impl From<String> for PropertyValue {
    fn from(v: String) -> Self {
        PropertyValue::Text(v)
    }
}

/// A map of named properties passed to guard evaluation.
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Properties(pub HashMap<String, PropertyValue>);

impl Properties {
    pub fn new() -> Self {
        Properties::default()
    }
    pub fn set(mut self, key: impl Into<String>, value: impl Into<PropertyValue>) -> Self {
        self.0.insert(key.into(), value.into());
        self
    }
    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<PropertyValue>) {
        self.0.insert(key.into(), value.into());
    }
    pub fn get(&self, key: &str) -> Option<&PropertyValue> {
        self.0.get(key)
    }
    pub fn remove(&mut self, key: &str) {
        self.0.remove(key);
    }
    pub fn clear(&mut self) {
        self.0.clear();
    }
}

/// Comparison operator used in a Rule.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Operator {
    Equals,
    NotEquals,
    In,
    NotIn,
    Regex,
    Gt,
    Gte,
    Lt,
    Lte,
}

/// A single rule condition within a Guard.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Rule {
    pub property_name: String,
    pub operator: Operator,
    pub values: Vec<PropertyValue>,
    pub result: bool,
    pub enabled: bool,
}

/// A named feature guard with an ordered rule set.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Guard {
    pub name: String,
    pub rules: Vec<Rule>,
    pub default_value: bool,
    pub adopted: bool,
    pub rate_limit_per_minute: i32,
    pub rate_limit_properties: Vec<String>,
    pub disable_measurement: Option<bool>,
}

/// SDK initialization options.
#[derive(Debug, Clone)]
pub struct ClientOptions {
    pub environment: Option<String>,
    pub fallback: bool,
    pub refresh_rate_seconds: u64,
    pub flush_rate_seconds: u64,
    pub flush_size: usize,
    pub backend_url: String,
    pub quiet: bool,
    pub http_timeout_seconds: u64,
    pub flush_buffer_multiplier: usize,
    pub disable_measurement: bool,
}

impl Default for ClientOptions {
    fn default() -> Self {
        ClientOptions {
            environment: None,
            fallback: false,
            refresh_rate_seconds: 30,
            flush_rate_seconds: 10,
            flush_size: 500,
            backend_url: "https://api.liteguard.io".into(),
            quiet: true,
            http_timeout_seconds: 4,
            flush_buffer_multiplier: 4,
            disable_measurement: false,
        }
    }
}

impl ClientOptions {
    pub(crate) fn with_defaults(mut self) -> Self {
        if self.refresh_rate_seconds == 0 {
            self.refresh_rate_seconds = 30;
        }
        if self.flush_rate_seconds == 0 {
            self.flush_rate_seconds = 10;
        }
        if self.flush_size == 0 {
            self.flush_size = 500;
        }
        if self.backend_url.is_empty() {
            self.backend_url = "https://api.liteguard.io".into();
        }
        if self.http_timeout_seconds == 0 {
            self.http_timeout_seconds = 4;
        }
        if self.flush_buffer_multiplier == 0 {
            self.flush_buffer_multiplier = 4;
        }
        self
    }
}

/// Per-call options for a single guard check.
#[derive(Debug, Clone, Default)]
pub struct Options {
    pub disable_measurement: bool,
    pub properties: Properties,
    pub fallback: Option<bool>,
}

/// ProtectedContext.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProtectedContext {
    pub properties: HashMap<String, String>,
    pub signature: String,
}

/// GetGuardsRequest.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetGuardsRequest {
    pub project_client_token: String,
    pub environment: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub protected_context: Option<ProtectedContext>,
}

/// Parsed response from the guards endpoint.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetGuardsResponse {
    pub guards: Vec<Guard>,
    pub refresh_rate_seconds: u64,
    pub etag: String,
}

/// Trace context for OpenTelemetry correlation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceContext {
    pub trace_id: String,
    pub span_id: String,
    pub parent_span_id: String,
}

/// GuardCheckPerformance.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GuardCheckPerformance {
    pub rss_bytes: Option<i64>,
    pub heap_used_bytes: Option<i64>,
    pub heap_total_bytes: Option<i64>,
    pub cpu_time_ns: Option<i64>,
    pub gc_count: Option<i64>,
    pub thread_count: Option<i64>,
}

/// GuardExecutionPerformance.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GuardExecutionPerformance {
    pub duration_ns: i64,
    pub rss_end_bytes: Option<i64>,
    pub heap_used_end_bytes: Option<i64>,
    pub heap_total_end_bytes: Option<i64>,
    pub cpu_time_end_ns: Option<i64>,
    pub gc_count_end: Option<i64>,
    pub thread_count_end: Option<i64>,
    pub completed: bool,
    pub error_class: Option<String>,
}

/// SignalPerformance.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignalPerformance {
    pub guard_check: Option<GuardCheckPerformance>,
    pub guard_execution: Option<GuardExecutionPerformance>,
}

/// A buffered guard check signal.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Signal {
    pub guard_name: String,
    pub result: bool,
    pub properties: HashMap<String, PropertyValue>,
    pub timestamp_ms: i64,
    pub trace: Option<TraceContext>,
    pub signal_id: String,
    pub execution_id: String,
    pub parent_signal_id: Option<String>,
    pub sequence_number: i64,
    pub callsite_id: String,
    pub kind: String,
    pub dropped_signals_since_last: i32,
    pub measurement: Option<SignalPerformance>,
}

/// UnadoptedGuardObservation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UnadoptedGuardObservation {
    pub guard_name: String,
    pub first_seen_ms: i64,
    pub last_seen_ms: i64,
    pub check_count: i64,
    pub estimated_checks_per_minute: f64,
}

/// SendUnadoptedGuardsRequest.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendUnadoptedGuardsRequest {
    pub project_client_token: String,
    pub environment: String,
    pub observations: Vec<UnadoptedGuardObservation>,
}

/// SendUnadoptedGuardsResponse.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendUnadoptedGuardsResponse {
    pub accepted: bool,
}

/// Error returned from [`Client::init`].
#[derive(Debug)]
pub struct InitError(pub String);

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "liteguard init error: {}", self.0)
    }
}
impl std::error::Error for InitError {}