use std::sync::Arc;
use tokio::sync::RwLock;
use super::api::{ApiMethods, ApiOptions};
use super::types::AuthState;
impl ApiMethods {
pub(super) async fn build_auth_header(
auth: &Arc<RwLock<AuthState>>,
) -> (String, String, String) {
let (auth_token, auth_type) = {
let a = auth.read().await;
(a.auth_token.clone(), a.auth_type.clone())
};
let (name, value) = if auth_type == "oauth" {
("authorization".to_string(), format!("Bearer {}", auth_token))
} else {
("x-api-key".to_string(), auth_token)
};
(name, value, auth_type)
}
pub(super) fn build_beta_header(
auth_type: &str,
options: &ApiOptions,
model: &str,
) -> Option<String> {
let mut betas: Vec<&str> = Vec::new();
if auth_type == "oauth" {
betas.push("claude-code-20250219");
betas.push("oauth-2025-04-20");
}
if options.use_1m_context && crate::core::models::model_supports_1m(model) {
betas.push("context-1m-2025-08-07");
}
if auth_type != "oauth" && options.cache_ttl != crate::core::config::CacheTtl::FiveMinutes {
betas.push("extended-cache-ttl-2025-04-11");
}
if betas.is_empty() {
None
} else {
Some(betas.join(","))
}
}
}
#[cfg(test)]
mod beta_header_tests {
use super::*;
use crate::core::config::CacheTtl;
fn opts(ttl: CacheTtl) -> ApiOptions {
ApiOptions { cache_ttl: ttl, ..Default::default() }
}
const MODEL: &str = "claude-sonnet-4-6";
#[test]
fn api_key_5m_emits_no_header() {
assert_eq!(ApiMethods::build_beta_header("api_key", &opts(CacheTtl::FiveMinutes), MODEL), None);
}
#[test]
fn api_key_1h_and_hybrid_emit_extended_ttl_beta() {
for ttl in [CacheTtl::OneHour, CacheTtl::Hybrid] {
assert_eq!(
ApiMethods::build_beta_header("api_key", &opts(ttl), MODEL).as_deref(),
Some("extended-cache-ttl-2025-04-11"),
"under {ttl:?}"
);
}
}
#[test]
fn oauth_beta_set_unperturbed_by_cache_ttl() {
for ttl in [CacheTtl::FiveMinutes, CacheTtl::OneHour, CacheTtl::Hybrid] {
assert_eq!(
ApiMethods::build_beta_header("oauth", &opts(ttl), MODEL).as_deref(),
Some("claude-code-20250219,oauth-2025-04-20"),
"under {ttl:?}"
);
}
}
#[test]
fn extended_ttl_comma_joins_with_1m_context() {
let options = ApiOptions {
use_1m_context: true,
cache_ttl: CacheTtl::OneHour,
..Default::default()
};
assert!(
crate::core::models::model_supports_1m(MODEL),
"fixture model fell out of the 1M table — pick a 1M-capable fixture"
);
assert_eq!(
ApiMethods::build_beta_header("api_key", &options, MODEL).as_deref(),
Some("context-1m-2025-08-07,extended-cache-ttl-2025-04-11"),
);
}
}