use super::{InstallError, InstallKind};
fn check_repository_name(repository: &str) -> Result<(), InstallError> {
if repository.eq_ignore_ascii_case("objectiveai") {
return Err(InstallError::ReservedRepositoryName {
repository: repository.to_string(),
});
}
Ok(())
}
fn validate_identifier(
kind: &'static str,
value: &str,
) -> Result<(), InstallError> {
let valid_len = !value.is_empty() && value.len() <= 128;
let valid_chars = value
.chars()
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.'));
if !valid_len || !valid_chars {
return Err(InstallError::InvalidIdentifier {
kind,
value: value.to_string(),
});
}
Ok(())
}
pub(crate) fn validate_install_inputs(
kind: InstallKind,
owner: &str,
repository: &str,
commit_sha: Option<&str>,
) -> Result<(), InstallError> {
if matches!(kind, InstallKind::Plugin) {
check_repository_name(repository)?;
}
validate_identifier("owner", owner)?;
validate_identifier("repository", repository)?;
if let Some(sha) = commit_sha {
validate_identifier("commit", sha)?;
}
Ok(())
}
pub fn raw_manifest_url(
owner: &str,
repository: &str,
commit_sha: Option<&str>,
) -> String {
let reference = commit_sha.unwrap_or("HEAD");
format!(
"https://raw.githubusercontent.com/{owner}/{repository}/{reference}/objectiveai.json"
)
}
pub(crate) fn build_headers(
headers: Option<&indexmap::IndexMap<String, String>>,
) -> Result<reqwest::header::HeaderMap, InstallError> {
let mut out = reqwest::header::HeaderMap::new();
let Some(h) = headers else {
return Ok(out);
};
for (k, v) in h {
let name = reqwest::header::HeaderName::from_bytes(k.as_bytes())
.map_err(|e| InstallError::InvalidHeaderName {
name: k.clone(),
reason: e.to_string(),
})?;
let value = reqwest::header::HeaderValue::from_str(v).map_err(|e| {
InstallError::InvalidHeaderValue {
name: k.clone(),
reason: e.to_string(),
}
})?;
out.insert(name, value);
}
Ok(out)
}