use serde_json::{json, Map, Value};
#[derive(Debug, Clone)]
pub struct Event {
pub name: String,
pub properties: Map<String, Value>,
}
impl Event {
fn new(name: &str, properties: Map<String, Value>) -> Self {
Self {
name: name.into(),
properties,
}
}
pub fn cli_command_invoked(
command: &str,
output_mode: &str,
exit_code: i32,
duration_ms: u64,
) -> Self {
let mut p = Map::new();
p.insert("command".into(), json!(command));
p.insert("output_mode".into(), json!(output_mode));
p.insert("exit_code".into(), json!(exit_code));
p.insert("duration_ms".into(), json!(duration_ms));
Self::new("cli_command_invoked", p)
}
pub fn init_completed(
editor_present: bool,
tool_count: u32,
provider_count: u32,
binding_count: u32,
) -> Self {
let mut p = Map::new();
p.insert("editor_present".into(), json!(editor_present));
p.insert("tool_count".into(), json!(tool_count));
p.insert("provider_count".into(), json!(provider_count));
p.insert("binding_count".into(), json!(binding_count));
Self::new("init_completed", p)
}
pub fn login_succeeded(flow: &str, duration_ms: u64) -> Self {
let mut p = Map::new();
p.insert("flow".into(), json!(flow));
p.insert("duration_ms".into(), json!(duration_ms));
Self::new("login_succeeded", p)
}
pub fn login_failed(flow: &str, error_code: &str) -> Self {
let mut p = Map::new();
p.insert("flow".into(), json!(flow));
p.insert("error_code".into(), json!(error_code));
Self::new("login_failed", p)
}
pub fn tool_published(version_bump: &str, dry_run: bool, category_count: u32) -> Self {
let mut p = Map::new();
p.insert("version_bump".into(), json!(version_bump));
p.insert("dry_run".into(), json!(dry_run));
p.insert("category_count".into(), json!(category_count));
Self::new("tool_published", p)
}
pub fn provider_registered(region: &str, binding_count: u32, dry_run: bool) -> Self {
let mut p = Map::new();
p.insert("region".into(), json!(region));
p.insert("binding_count".into(), json!(binding_count));
p.insert("dry_run".into(), json!(dry_run));
Self::new("provider_registered", p)
}
pub fn binding_secret_rotated() -> Self {
Self::new("binding_secret_rotated", Map::new())
}
pub fn listen_started(port: u16, binding_count: u32, tls_mode: &str) -> Self {
let mut p = Map::new();
p.insert("port".into(), json!(port));
p.insert("binding_count".into(), json!(binding_count));
p.insert("tls_mode".into(), json!(tls_mode));
Self::new("listen_started", p)
}
pub fn listen_stopped(
reason: &str,
uptime_ms: u64,
events_processed: u64,
events_failed: u64,
) -> Self {
let mut p = Map::new();
p.insert("reason".into(), json!(reason));
p.insert("uptime_ms".into(), json!(uptime_ms));
p.insert("events_processed".into(), json!(events_processed));
p.insert("events_failed".into(), json!(events_failed));
Self::new("listen_stopped", p)
}
pub fn webhook_verify_failed(binding_id: &str, failure_kind: &str) -> Self {
let mut p = Map::new();
p.insert("binding_id".into(), json!(binding_id));
p.insert("failure_kind".into(), json!(failure_kind));
Self::new("webhook_verify_failed", p)
}
pub fn proxy_call_failed(binding_id: &str, failure_kind: &str) -> Self {
let mut p = Map::new();
p.insert("binding_id".into(), json!(binding_id));
p.insert("failure_kind".into(), json!(failure_kind));
Self::new("proxy_call_failed", p)
}
pub fn error_emitted(code: &str, command_or_path: &str) -> Self {
let mut p = Map::new();
p.insert("code".into(), json!(code));
p.insert("command_or_path".into(), json!(command_or_path));
Self::new("error_emitted", p)
}
pub fn create_alias(machine_id: &str, editor_id: &str) -> Self {
let mut p = Map::new();
p.insert("alias".into(), json!(machine_id));
p.insert("distinct_id".into(), json!(editor_id));
Self::new("$create_alias", p)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cli_command_invoked_carries_required_fields() {
let e = Event::cli_command_invoked("tools.list", "table", 0, 42);
assert_eq!(e.name, "cli_command_invoked");
assert_eq!(e.properties["command"], "tools.list");
assert_eq!(e.properties["output_mode"], "table");
assert_eq!(e.properties["exit_code"], 0);
assert_eq!(e.properties["duration_ms"], 42);
}
#[test]
fn create_alias_event_shape() {
let e = Event::create_alias("mach_x", "edt_y");
assert_eq!(e.name, "$create_alias");
assert_eq!(e.properties["alias"], "mach_x");
assert_eq!(e.properties["distinct_id"], "edt_y");
}
}