From 22321556dd97865a251276154d3aee5fc1901a6a Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Mon, 11 May 2026 20:25:43 +0000 Subject: [PATCH] chore(api): remove dead bundle module and CAS read endpoint ApiClient::create_bundle (api/bundle.rs) and ApiClient::read_ca_prompt_store (api/cas.rs) were never called from any production code path or test. Remove both implementations along with the types they exclusively required (BundleData, CreateBundleRequest, CreateBundleResponse, CasMessagesObject, CAPromptStoreReadResult, CAPromptStoreReadResponse) and their unit tests. Co-Authored-By: Claude Sonnet 4.6 --- src/api/bundle.rs | 66 ------------------------------------ src/api/cas.rs | 57 +------------------------------ src/api/mod.rs | 1 - src/api/types.rs | 86 +---------------------------------------------- 4 files changed, 2 insertions(+), 208 deletions(-) delete mode 100644 src/api/bundle.rs diff --git a/src/api/bundle.rs b/src/api/bundle.rs deleted file mode 100644 index 317da353b3..0000000000 --- a/src/api/bundle.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::api::client::ApiClient; -use crate::api::types::{ApiErrorResponse, CreateBundleRequest, CreateBundleResponse}; -use crate::error::GitAiError; - -/// Bundle API endpoints -impl ApiClient { - /// Create a new bundle by posting to /api/bundle - /// - /// # Arguments - /// * `request` - The bundle creation request - /// - /// # Returns - /// * `Ok(CreateBundleResponse)` - Success response with bundle ID and URL - /// * `Err(GitAiError)` - Error response - /// - /// # Errors - /// * Returns `GitAiError::Generic` for HTTP errors - /// * Returns `GitAiError::JsonError` for JSON parsing errors - /// * Returns `GitAiError::Generic` with error details for API errors (400, 500, etc.) - pub fn create_bundle( - &self, - request: CreateBundleRequest, - ) -> Result { - let response = self.context().post_json("/api/bundles", &request)?; - let status_code = response.status_code; - - let body = response - .as_str() - .map_err(|e| GitAiError::Generic(format!("Failed to read response body: {}", e)))?; - - match status_code { - 200 => { - let bundle_response: CreateBundleResponse = - serde_json::from_str(body).map_err(GitAiError::JsonError)?; - Ok(bundle_response) - } - 400 => { - // Try to parse error response - let error_response: ApiErrorResponse = - serde_json::from_str(body).unwrap_or_else(|_| ApiErrorResponse { - error: "Invalid request body".to_string(), - details: Some(serde_json::Value::String(body.to_string())), - }); - Err(GitAiError::Generic(format!( - "Bad Request: {}", - error_response.error - ))) - } - 500 => { - let error_response: ApiErrorResponse = - serde_json::from_str(body).unwrap_or_else(|_| ApiErrorResponse { - error: "Internal server error".to_string(), - details: None, - }); - Err(GitAiError::Generic(format!( - "Internal Server Error: {}", - error_response.error - ))) - } - _ => Err(GitAiError::Generic(format!( - "Unexpected status code {}: {}", - status_code, body - ))), - } - } -} diff --git a/src/api/cas.rs b/src/api/cas.rs index 7497fd07c5..39279bae5f 100644 --- a/src/api/cas.rs +++ b/src/api/cas.rs @@ -1,7 +1,5 @@ use crate::api::client::ApiClient; -use crate::api::types::{ - ApiErrorResponse, CAPromptStoreReadResponse, CasUploadRequest, CasUploadResponse, -}; +use crate::api::types::{ApiErrorResponse, CasUploadRequest, CasUploadResponse}; use crate::error::GitAiError; /// CAS API endpoints @@ -56,57 +54,4 @@ impl ApiClient { ))), } } - - /// Read CAS objects by hash from the server - /// - /// # Arguments - /// * `hashes` - Slice of CAS hashes to fetch (max 100 per call) - /// - /// # Returns - /// * `Ok(CAPromptStoreReadResponse)` - Response with results for each hash - /// * `Err(GitAiError)` - On network or server errors - pub fn read_ca_prompt_store( - &self, - hashes: &[&str], - ) -> Result { - // Validate all hashes are hex-only before building the URL to prevent - // injection via crafted hash values in the query string. - for hash in hashes { - if !hash.chars().all(|c| c.is_ascii_hexdigit()) { - return Err(GitAiError::Generic(format!( - "CAS hash contains non-hex characters: {}", - hash - ))); - } - } - - let query = hashes.join(","); - let endpoint = format!("/worker/cas/?hashes={}", query); - let response = self.context().get(&endpoint)?; - let status_code = response.status_code; - - let body = response - .as_str() - .map_err(|e| GitAiError::Generic(format!("Failed to read response body: {}", e)))?; - - match status_code { - 200 => { - let cas_response: CAPromptStoreReadResponse = - serde_json::from_str(body).map_err(GitAiError::JsonError)?; - Ok(cas_response) - } - 404 => { - // All hashes not found — return empty response gracefully - Ok(CAPromptStoreReadResponse { - results: Vec::new(), - success_count: 0, - failure_count: hashes.len(), - }) - } - _ => Err(GitAiError::Generic(format!( - "CAS read failed with status {}: {}", - status_code, body - ))), - } - } } diff --git a/src/api/mod.rs b/src/api/mod.rs index e8de28efe3..fbf7447350 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,4 +1,3 @@ -pub mod bundle; pub mod cas; pub mod client; pub mod metrics; diff --git a/src/api/types.rs b/src/api/types.rs index 0f0b92b10d..58be99b509 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -1,4 +1,4 @@ -use crate::authorship::authorship_log::{LineRange, PromptRecord}; +use crate::authorship::authorship_log::LineRange; use crate::commands::diff::FileDiffJson; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -44,34 +44,6 @@ impl From<&FileDiffJson> for ApiFileRecord { } } -/// Bundle data containing prompts and optional files -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct BundleData { - /// REQUIRED: At least one prompt - pub prompts: HashMap, - /// OPTIONAL: File diffs and annotations - #[serde(default, skip_serializing_if = "HashMap::is_empty")] - pub files: HashMap, -} - -/// Request body for creating a bundle -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CreateBundleRequest { - /// Bundle title (min 1 character) - pub title: String, - /// Bundle data containing prompts and optional files - pub data: BundleData, - // TODO PR Metadata if linked to PR -} - -/// Success response from bundle creation -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct CreateBundleResponse { - pub success: bool, - pub id: String, - pub url: String, -} - /// Error response from API #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct ApiErrorResponse { @@ -112,12 +84,6 @@ pub struct CasUploadResponse { pub failure_count: usize, } -/// Wrapper for messages stored in CAS -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CasMessagesObject { - pub messages: Vec, -} - /// A single authorship note entry (commit SHA + content). #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct NoteEntry { @@ -144,25 +110,6 @@ pub struct NotesReadResponse { pub notes: std::collections::HashMap, } -/// Single result from CA prompt store batch read -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CAPromptStoreReadResult { - pub hash: String, - pub status: String, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub content: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - pub error: Option, -} - -/// Response from CA prompt store batch read -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CAPromptStoreReadResponse { - pub results: Vec, - pub success_count: usize, - pub failure_count: usize, -} - #[cfg(test)] mod tests { use super::*; @@ -280,20 +227,6 @@ mod tests { assert_eq!(ranges[2], serde_json::Value::Number(20.into())); } - #[test] - fn test_create_bundle_response_deserialization() { - let json = r#"{ - "success": true, - "id": "bundle123", - "url": "https://example.com/bundle123" - }"#; - - let response: CreateBundleResponse = serde_json::from_str(json).unwrap(); - assert!(response.success); - assert_eq!(response.id, "bundle123"); - assert_eq!(response.url, "https://example.com/bundle123"); - } - #[test] fn test_api_error_response_serialization() { let error = ApiErrorResponse { @@ -428,21 +361,4 @@ mod tests { let cloned = record.clone(); assert_eq!(record, cloned); } - - #[test] - fn test_cas_messages_object() { - use crate::authorship::transcript::Message; - - let messages = vec![Message::user("test".to_string(), None)]; - - let cas_msg = CasMessagesObject { - messages: messages.clone(), - }; - - let json = serde_json::to_string(&cas_msg).unwrap(); - assert!(json.contains("test")); - - let deserialized: CasMessagesObject = serde_json::from_str(&json).unwrap(); - assert_eq!(deserialized.messages.len(), 1); - } }