use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookConfig {
pub provider: Option<String>,
pub path: Option<String>,
pub secret_env: String,
pub signature_scheme: Option<String>,
pub signature_header: Option<String>,
pub timestamp_header: Option<String>,
#[serde(default = "default_timestamp_tolerance")]
pub timestamp_tolerance: u64,
#[serde(default = "default_idempotent")]
pub idempotent: bool,
#[serde(default)]
pub events: HashMap<String, WebhookEventConfig>,
}
fn default_timestamp_tolerance() -> u64 {
300
}
fn default_idempotent() -> bool {
true
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookEventConfig {
pub function: String,
#[serde(default)]
pub mapping: HashMap<String, String>,
pub condition: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_values() {
let json = r#"{
"secret_env": "WEBHOOK_SECRET",
"events": {}
}"#;
let config: WebhookConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.timestamp_tolerance, 300);
assert!(config.idempotent);
}
#[test]
fn test_custom_values() {
let json = r#"{
"provider": "stripe",
"secret_env": "STRIPE_SECRET",
"timestamp_tolerance": 600,
"idempotent": false,
"events": {
"payment_intent.succeeded": {
"function": "handle_payment",
"mapping": {
"payment_id": "data.object.id"
}
}
}
}"#;
let config: WebhookConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.provider, Some("stripe".to_string()));
assert_eq!(config.timestamp_tolerance, 600);
assert!(!config.idempotent);
assert_eq!(config.events.len(), 1);
}
}