versa 1.9.0-rc1

Versa types and utilities for developing Versa client applications in Rust
Documentation
//! Client functionality for interacting with the Versa registry.
//!
//! This module provides the core [`VersaClient`] type and related functionality
//! for communicating with the Versa registry API.

pub mod check_registry;
pub mod constants;
pub mod customer_registration;

/// Main client for interacting with the Versa registry.
///
/// The `VersaClient` handles authentication and provides methods for
/// registering receipts, checking receiver configurations, and managing
/// customer registrations.
///
/// # Example
///
/// ```rust
/// use versa::client::VersaClient;
///
/// let client = VersaClient::new(
///     "client_id".to_string(),
///     "client_secret".to_string()
/// );
///
/// // Optionally set a custom registry URL (defaults to production)
/// let client = client.with_registry_url("https://registry.versa.org");
/// ```
pub struct VersaClient {
  client_string: Option<String>,
  client_id: String,
  client_secret: String,
  pub registry_url: String,
}

/// Error indicating an invalid schema version was provided.
#[derive(Debug)]
pub struct InvalidSchemaVersion(pub String);

/// Errors that can occur during client operations.
#[derive(Debug)]
pub enum ClientError {
  /// The requested schema version was not found
  SchemaNotFound(String),
  /// Error deserializing response data
  DeserializationError(reqwest::Error),
  /// Network communication error
  NetworkError(reqwest::Error),
  /// Error response from the Versa registry
  RegistryError(http::StatusCode, String),
  /// Error response from a remote client (receiver)
  RemoteClientError(http::StatusCode, String),
  /// HMAC signature verification failed
  HmacVerificationError,
}

impl VersaClient {
  /// Creates a new Versa client with the given credentials.
  ///
  /// Uses the default production registry URL. Use [`with_registry_url`](Self::with_registry_url)
  /// to override.
  ///
  /// # Arguments
  ///
  /// * `client_id` - Your Versa client ID
  /// * `client_secret` - Your Versa client secret
  pub fn new(client_id: String, client_secret: String) -> Self {
    let registry_url = constants::REGISTRY_URL.to_string();
    Self {
      client_string: None,
      client_id,
      client_secret,
      registry_url,
    }
  }

  /// Sets a custom registry URL.
  ///
  /// Useful for testing or using alternative Versa registry instances.
  ///
  /// # Example
  ///
  /// ```rust
  /// # use versa::client::VersaClient;
  /// let client = VersaClient::new("id".to_string(), "secret".to_string())
  ///     .with_registry_url("https://test-registry.versa.org");
  /// ```
  pub fn with_registry_url(mut self, registry_url: &str) -> Self {
    self.registry_url = registry_url.to_string();
    self
  }

  /// Returns the authorization header value for API requests.
  ///
  /// This is used internally for authenticating with the Versa registry.
  pub fn authorization_header_val(&self) -> String {
    format!("Basic {}:{}", self.client_id, self.client_secret)
  }

  /// Returns a copy of the client ID.
  pub fn client_id(&self) -> String {
    self.client_id.clone()
  }

  /// Sets an optional client string for identifying your software.
  ///
  /// The client string helps Versa track different implementations
  /// and can be useful for debugging.
  ///
  /// # Example
  ///
  /// ```rust
  /// # use versa::client::VersaClient;
  /// let client = VersaClient::new("id".to_string(), "secret".to_string())
  ///     .with_client_string("MyApp/1.0.0");
  /// ```
  pub fn with_client_string(mut self, client_string: &str) -> Self {
    self.client_string = Some(client_string.to_string());
    self
  }

  /// Returns the client string if set.
  pub fn client_string(&self) -> Option<String> {
    self.client_string.clone()
  }
}