Skip to main content

capsula_api_types/
lib.rs

1//! Shared API type definitions for Capsula client and server
2//!
3//! This crate defines the common types used in the Capsula HTTP API to ensure
4//! compile-time compatibility between the client and server implementations.
5
6use serde::{Deserialize, Serialize};
7
8/// Information about a vault
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
10pub struct VaultInfo {
11    pub name: String,
12    pub run_count: i64,
13}
14
15/// Response from the vaults list endpoint
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17pub struct VaultsResponse {
18    pub status: String,
19    pub vaults: Vec<VaultInfo>,
20}
21
22/// Response from the vault exists endpoint
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub struct VaultExistsResponse {
25    pub status: String,
26    pub exists: bool,
27    pub vault: Option<VaultInfo>,
28}
29
30/// Response from the upload run endpoint
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
32pub struct UploadResponse {
33    pub status: String,
34    pub files_processed: u64,
35    pub total_bytes: u64,
36    pub pre_run_hooks: u64,
37    pub post_run_hooks: u64,
38}
39
40/// Generic error response
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
42pub struct ErrorResponse {
43    pub status: String,
44    pub error: String,
45}
46
47// =============================================================================
48// Search API Types
49// =============================================================================
50
51/// A filter condition on a hook's config or output using `JSONPath`
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
53pub struct HookFilter {
54    /// The hook ID (e.g., "capture-git-repo", "capture-env")
55    pub hook_id: String,
56    /// `JSONPath` expression to match against hook's config (optional)
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub config_filter: Option<String>,
59    /// `JSONPath` expression to match against hook's output
60    pub output_filter: String,
61}
62
63/// Fields that can be included in search response
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
65#[serde(rename_all = "snake_case")]
66pub enum IncludeField {
67    Metadata,
68    Files,
69    Stdout,
70    Stderr,
71    Hooks,
72}
73
74/// Sort order for search results
75#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
76#[serde(rename_all = "snake_case")]
77pub enum SortOrder {
78    #[default]
79    LatestFirst,
80    OldestFirst,
81}
82
83/// Request body for POST /api/v1/runs/search
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct SearchRunsRequest {
86    /// Filter by vault name
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub vault: Option<String>,
89    /// Filter runs from this timestamp (ISO 8601)
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub from: Option<String>,
92    /// Filter runs until this timestamp (ISO 8601)
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub to: Option<String>,
95    /// Filter by exact exit code
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub exit_code: Option<i32>,
98    /// Filter by success (`exit_code` = 0) or failure (`exit_code` != 0)
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub success: Option<bool>,
101    /// Hook output filters (AND logic)
102    #[serde(default)]
103    pub hook_filters: Vec<HookFilter>,
104    /// What to include in response
105    #[serde(default)]
106    pub include: Vec<IncludeField>,
107    /// Sort order
108    #[serde(default)]
109    pub order: SortOrder,
110    /// Maximum number of results (default: 100)
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub limit: Option<i64>,
113    /// Offset for pagination
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub offset: Option<i64>,
116}
117
118/// File information in search results
119#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
120pub struct FileInfo {
121    pub path: String,
122    pub size: i64,
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub hash: Option<String>,
125    pub url: String,
126}