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}