Skip to main content

aperture_cli/cache/
models.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
5pub struct CachedSpec {
6    /// Cache format version to detect incompatible changes
7    pub cache_format_version: u32,
8    pub name: String,
9    pub version: String,
10    pub commands: Vec<CachedCommand>,
11    /// Base URL extracted from the first server in the `OpenAPI` spec
12    pub base_url: Option<String>,
13    /// All server URLs from the `OpenAPI` spec for future multi-environment support
14    pub servers: Vec<String>,
15    /// Security schemes defined in the `OpenAPI` spec with `x-aperture-secret` mappings
16    pub security_schemes: HashMap<String, CachedSecurityScheme>,
17    /// Endpoints skipped during validation due to unsupported features (added in v0.1.2)
18    #[serde(default)]
19    pub skipped_endpoints: Vec<SkippedEndpoint>,
20    /// Server variables defined in the `OpenAPI` spec for URL template resolution (added in v0.1.3)
21    #[serde(default)]
22    pub server_variables: HashMap<String, ServerVariable>,
23}
24
25impl CachedSpec {
26    /// Creates a new `CachedSpec` with default values for testing
27    #[cfg(test)]
28    #[must_use]
29    pub fn new_for_test(name: &str) -> Self {
30        Self {
31            cache_format_version: CACHE_FORMAT_VERSION,
32            name: name.to_string(),
33            version: "1.0.0".to_string(),
34            commands: vec![],
35            base_url: None,
36            servers: vec![],
37            security_schemes: HashMap::new(),
38            skipped_endpoints: vec![],
39            server_variables: HashMap::new(),
40        }
41    }
42}
43
44/// Pagination strategy detected from the `OpenAPI` spec for an operation.
45///
46/// Stored at cache time to avoid re-parsing the spec on each request.
47#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Default)]
48#[serde(rename_all = "kebab-case")]
49pub enum PaginationStrategy {
50    /// No pagination detected; `--auto-paginate` will warn and execute once.
51    #[default]
52    None,
53    /// Cursor-based: a field in the response body carries the next-page token.
54    Cursor,
55    /// Offset/page-based: incrementing a `page` or `offset` query parameter.
56    Offset,
57    /// RFC 5988 `Link: <url>; rel="next"` header drives the next request URL.
58    LinkHeader,
59}
60
61/// Detected pagination configuration for a single operation.
62///
63/// All `Option` fields are serialized without `skip_serializing_if` so that
64/// postcard binary encoding remains position-stable across reads and writes.
65/// JSON compactness is handled by [`PaginationManifestInfo`] in the agent layer.
66#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Default)]
67pub struct PaginationInfo {
68    /// How pagination is driven for this operation.
69    pub strategy: PaginationStrategy,
70    /// Response body field containing the next cursor (`cursor` strategy).
71    pub cursor_field: Option<String>,
72    /// Query parameter to inject the cursor into (`cursor` strategy).
73    pub cursor_param: Option<String>,
74    /// Query parameter to increment (`offset` strategy, e.g. `"page"`, `"offset"`).
75    pub page_param: Option<String>,
76    /// Query parameter carrying the page size (`offset` strategy).
77    pub limit_param: Option<String>,
78}
79
80/// Example usage for a command
81#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
82pub struct CommandExample {
83    /// Brief description of what this example demonstrates
84    pub description: String,
85    /// The complete command line example
86    pub command_line: String,
87    /// Optional explanation of the parameters used
88    pub explanation: Option<String>,
89}
90
91/// Information about an endpoint that was skipped during spec validation
92#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
93pub struct SkippedEndpoint {
94    pub path: String,
95    pub method: String,
96    pub content_type: String,
97    pub reason: String,
98}
99
100/// Current cache format version - increment when making breaking changes to `CachedSpec`
101///
102/// Version 2: Added `skipped_endpoints` field to track endpoints skipped during validation
103/// Version 3: Added `server_variables` field to support `OpenAPI` server URL template variables
104/// Version 4: Added `example` field to `CachedResponse` for response schema examples
105/// Version 5: Added `display_group`, `display_name`, `aliases`, `hidden` fields for command mapping
106/// Version 6: Added `pagination` field to `CachedCommand` for auto-pagination support
107pub const CACHE_FORMAT_VERSION: u32 = 6;
108
109/// Global cache metadata for all cached specifications
110#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
111pub struct GlobalCacheMetadata {
112    /// Cache format version for all specs
113    pub cache_format_version: u32,
114    /// Individual spec metadata
115    pub specs: std::collections::HashMap<String, SpecMetadata>,
116}
117
118/// Metadata for a single cached specification
119#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
120pub struct SpecMetadata {
121    /// When this spec cache was created/updated
122    pub updated_at: String, // Using String for simplicity in serialization
123    /// Size of the cached spec file in bytes
124    pub file_size: u64,
125    /// SHA-256 hash of the original spec file content for cache invalidation
126    #[serde(default)]
127    pub content_hash: Option<String>,
128    /// File modification time (seconds since epoch) for fast staleness checks
129    #[serde(default)]
130    pub mtime_secs: Option<u64>,
131    /// Size of the original spec file in bytes (distinct from cached binary size)
132    #[serde(default)]
133    pub spec_file_size: Option<u64>,
134}
135
136impl Default for GlobalCacheMetadata {
137    fn default() -> Self {
138        Self {
139            cache_format_version: CACHE_FORMAT_VERSION,
140            specs: std::collections::HashMap::new(),
141        }
142    }
143}
144
145#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
146pub struct CachedCommand {
147    pub name: String,
148    pub description: Option<String>,
149    pub summary: Option<String>,
150    pub operation_id: String,
151    pub method: String,
152    pub path: String,
153    pub parameters: Vec<CachedParameter>,
154    pub request_body: Option<CachedRequestBody>,
155    pub responses: Vec<CachedResponse>,
156    /// Security requirements for this operation (references to security scheme names)
157    pub security_requirements: Vec<String>,
158    /// All tags associated with this operation
159    pub tags: Vec<String>,
160    /// Whether this operation is deprecated
161    pub deprecated: bool,
162    /// External documentation URL if available
163    pub external_docs_url: Option<String>,
164    /// Usage examples for this command (added in v0.1.6)
165    #[serde(default)]
166    pub examples: Vec<CommandExample>,
167    /// Display name override for the command group (tag), from command mapping (added in v5)
168    #[serde(default)]
169    pub display_group: Option<String>,
170    /// Display name override for the subcommand (operation), from command mapping (added in v5)
171    #[serde(default)]
172    pub display_name: Option<String>,
173    /// Additional subcommand aliases from command mapping (added in v5)
174    #[serde(default)]
175    pub aliases: Vec<String>,
176    /// Whether this command is hidden from help output, from command mapping (added in v5)
177    #[serde(default)]
178    pub hidden: bool,
179    /// Pagination configuration detected from the `OpenAPI` spec (added in v6)
180    #[serde(default)]
181    pub pagination: PaginationInfo,
182}
183
184#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
185pub struct CachedParameter {
186    pub name: String,
187    pub location: String,
188    pub required: bool,
189    pub description: Option<String>,
190    pub schema: Option<String>,
191    pub schema_type: Option<String>,
192    pub format: Option<String>,
193    pub default_value: Option<String>,
194    pub enum_values: Vec<String>,
195    pub example: Option<String>,
196}
197
198#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
199pub struct CachedRequestBody {
200    pub content_type: String,
201    pub schema: String,
202    pub required: bool,
203    pub description: Option<String>,
204    pub example: Option<String>,
205}
206
207#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
208pub struct CachedResponse {
209    pub status_code: String,
210    pub description: Option<String>,
211    pub content_type: Option<String>,
212    pub schema: Option<String>,
213    /// Example response value (JSON-serialized)
214    #[serde(default)]
215    pub example: Option<String>,
216}
217
218/// Cached representation of a security scheme with x-aperture-secret mapping
219#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
220pub struct CachedSecurityScheme {
221    /// Security scheme name from the `OpenAPI` spec
222    pub name: String,
223    /// Type of security scheme (apiKey, http, oauth2, etc.)
224    pub scheme_type: String,
225    /// Subtype for http schemes (bearer, basic, etc.)
226    pub scheme: Option<String>,
227    /// Location for apiKey schemes (header, query, cookie)
228    pub location: Option<String>,
229    /// Parameter name for apiKey schemes (e.g., "Authorization", "X-API-Key")
230    pub parameter_name: Option<String>,
231    /// Description of the security scheme from `OpenAPI` spec
232    pub description: Option<String>,
233    /// Bearer format for HTTP bearer schemes (e.g., "JWT")
234    pub bearer_format: Option<String>,
235    /// x-aperture-secret mapping for environment variable resolution
236    pub aperture_secret: Option<CachedApertureSecret>,
237}
238
239/// Cached representation of x-aperture-secret extension
240#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
241pub struct CachedApertureSecret {
242    /// Source of the secret (currently only "env" supported)
243    pub source: String,
244    /// Environment variable name to read the secret from
245    pub name: String,
246}
247
248/// Cached representation of an `OpenAPI` server variable for URL template resolution
249#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
250pub struct ServerVariable {
251    /// Default value for the variable if not provided via CLI
252    pub default: Option<String>,
253    /// Allowed values for the variable (enum constraint)
254    pub enum_values: Vec<String>,
255    /// Description of the server variable from `OpenAPI` spec
256    pub description: Option<String>,
257}