xbp 10.57.0

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
use crate::cli::commands::{DomainsCmd, DomainsProviderKind, DomainsSubCommand};
use crate::commands::cloudflare_credentials::{
    build_cloudflare_client, CloudflareCredentialOverrides,
};
use crate::config::update_dns_inventory_cache;
use xbp_providers::cloudflare::CloudflareRegisteredDomainListFilters;

pub async fn run_domains(cmd: DomainsCmd, _debug: bool) -> Result<(), String> {
    if cmd.provider != DomainsProviderKind::Cloudflare {
        return Err("Only Cloudflare is supported for `xbp domains` in this release.".to_string());
    }

    let account_id_override = cmd.account_id.clone();
    let client = build_cloudflare_client(
        CloudflareCredentialOverrides {
            token: cmd.token.clone(),
            account_id: account_id_override.clone(),
        },
        true,
    )
    .await?;
    let account_id = account_id_override;

    match cmd.command {
        DomainsSubCommand::Search(args) => {
            let limit = args.limit.map(|n| n as u32);
            let mut results = client.search_domains(&args.query, limit).await?;
            // Optional local filter for requested TLD extensions (API search is free-text).
            if !args.extensions.is_empty() {
                results.retain(|item| {
                    args.extensions.iter().any(|ext| {
                        let needle = ext.trim_start_matches('.').to_ascii_lowercase();
                        item.name
                            .to_ascii_lowercase()
                            .ends_with(&format!(".{needle}"))
                    })
                });
            }
            if let Some(limit) = args.limit {
                results.truncate(limit);
            }
            update_dns_inventory_cache(|cache| {
                cache.record_cloudflare_domain_availability(account_id, &results)
            })?;
            print_json(&results)
        }
        DomainsSubCommand::Check(args) => {
            let results = client.check_domains(&args.domains).await?;
            update_dns_inventory_cache(|cache| {
                cache.record_cloudflare_domain_availability(account_id, &results)
            })?;
            print_json(&results)
        }
        DomainsSubCommand::List(_) => {
            let (domains, result_info) = client
                .list_registered_domains(&CloudflareRegisteredDomainListFilters::default())
                .await?;
            update_dns_inventory_cache(|cache| {
                cache.record_cloudflare_registered_domains(account_id, &domains)
            })?;
            print_json(&serde_json::json!({
                "provider": "cloudflare",
                "domains": domains,
                "result_info": result_info
            }))
        }
    }
}

fn print_json(value: &impl serde::Serialize) -> Result<(), String> {
    println!(
        "{}",
        serde_json::to_string_pretty(value)
            .map_err(|error| format!("Failed to encode JSON output: {}", error))?
    );
    Ok(())
}