xbp 10.40.0

XBP is a zero-config build pack that can also interact with proxies, kafka, sockets, synthetic monitors.
Documentation
//! No-op Athena persistence when the `athena` Cargo feature is disabled.
//!
//! Call sites keep the same API; nothing is written to Athena/Supabase unless
//! `xbp` is built with `--features athena`.

use crate::logging::LogEntry;
use crate::strategies::XbpConfig;
use serde_json::Value;
use std::path::Path;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AthenaRuntimeConfig {
    pub backend: String,
    pub url: String,
    pub key: String,
    pub schema: String,
}

pub async fn persist_project_snapshot(
    _project_root: &Path,
    _config: &XbpConfig,
    _config_kind: Option<&str>,
) {
}

pub async fn persist_log_entry(_entry: &LogEntry) {}

pub async fn persist_nginx_config_snapshot(
    _domain: &str,
    _config_path: &Path,
    _content: &str,
    _upstream_ports: &[u16],
    _listen_ports: &[u16],
    _source: &str,
) {
}

pub async fn persist_nginx_log(
    _domain: Option<&str>,
    _action: &str,
    _success: bool,
    _message: &str,
    _details: Option<&str>,
    _metadata: Value,
) {
}

pub async fn persist_nginx_edit_audit_log(
    _domain: Option<&str>,
    _config_path: Option<&Path>,
    _actor: Option<&str>,
    _action: &str,
    _old_content: Option<&str>,
    _new_content: Option<&str>,
    _metadata: Value,
) {
}

pub async fn persist_docker_container_snapshot(
    _container_id: &str,
    _container_name: &str,
    _status: Option<&str>,
    _ports: Option<&str>,
    _metadata: Value,
) {
}

pub async fn persist_docker_log(
    _container_id: Option<&str>,
    _command: Option<&str>,
    _stream: &str,
    _message: &str,
    _metadata: Value,
) {
}

pub async fn persist_schedule(
    _schedule_type: &str,
    _target_kind: &str,
    _target_ref: Option<&str>,
    _expression: &str,
    _enabled: bool,
    _metadata: Value,
) {
}

/// Pure PM2 flag parse — does not require Athena connectivity.
pub fn extract_cron_restart_expression(args: &[String]) -> Option<String> {
    for (index, arg) in args.iter().enumerate() {
        if arg == "--cron-restart" {
            if let Some(value) = args.get(index + 1) {
                let value = value.trim();
                if !value.is_empty() {
                    return Some(value.to_string());
                }
            }
        } else if let Some(value) = arg.strip_prefix("--cron-restart=") {
            let value = value.trim();
            if !value.is_empty() {
                return Some(value.to_string());
            }
        }
    }
    None
}

pub fn resolve_runtime_config(_config: Option<&XbpConfig>) -> Option<AthenaRuntimeConfig> {
    None
}

pub fn sql_literal(value: &Value) -> String {
    match value {
        Value::Null => "NULL".to_string(),
        Value::Bool(boolean) => boolean.to_string(),
        Value::Number(number) => number.to_string(),
        Value::String(text) => format!("'{}'", text.replace('\'', "''")),
        Value::Array(_) | Value::Object(_) => {
            format!("'{}'::jsonb", value.to_string().replace('\'', "''"))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::extract_cron_restart_expression;

    #[test]
    fn extract_cron_restart_expression_parses_space_and_equals_forms() {
        let spaced = vec![
            "npm".to_string(),
            "start".to_string(),
            "--cron-restart".to_string(),
            "0 * * * *".to_string(),
        ];
        assert_eq!(
            extract_cron_restart_expression(&spaced).as_deref(),
            Some("0 * * * *")
        );

        let equals = vec![
            "npm".to_string(),
            "start".to_string(),
            "--cron-restart=15 * * * *".to_string(),
        ];
        assert_eq!(
            extract_cron_restart_expression(&equals).as_deref(),
            Some("15 * * * *")
        );
    }
}