openlatch-provider 0.1.0

Self-service onboarding CLI + runtime daemon for OpenLatch Editors and Providers
//! Super-properties merged into every outbound event.
//!
//! Excluded by design (per `.claude/rules/telemetry.md`): IP, hostname,
//! username, working directory, file paths, command-arg values, env-var
//! values (other than telemetry toggles).

use serde_json::{json, Map, Value};

pub const EVENT_SCHEMA_VERSION: u32 = 1;

#[derive(Debug, Clone)]
pub struct SuperProps {
    pub provider_version: &'static str,
    pub os: &'static str,
    /// Stable per-machine id from `~/.openlatch/provider/config.toml` — used as the
    /// pre-auth PostHog `distinct_id`.
    pub machine_id: String,
    pub session_id: String,
    pub authenticated: bool,
}

impl SuperProps {
    pub fn new(machine_id: String, authenticated: bool) -> Self {
        Self {
            provider_version: env!("CARGO_PKG_VERSION"),
            os: os_tag(),
            machine_id,
            session_id: format!("sess_{}", uuid::Uuid::now_v7().simple()),
            authenticated,
        }
    }

    pub fn merge_into(&self, props: &mut Map<String, Value>) {
        props.insert("provider_version".into(), json!(self.provider_version));
        props.insert("os".into(), json!(self.os));
        props.insert("machine_id".into(), json!(self.machine_id));
        props.insert("session_id".into(), json!(self.session_id));
        props.insert("authenticated".into(), json!(self.authenticated));
        props.insert("event_schema_version".into(), json!(EVENT_SCHEMA_VERSION));
        props.insert(
            "$insert_id".into(),
            json!(format!("ins_{}", uuid::Uuid::now_v7().simple())),
        );
    }
}

const fn os_tag() -> &'static str {
    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
    {
        "darwin-arm64"
    }
    #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
    {
        "darwin-x64"
    }
    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    {
        "linux-x64"
    }
    #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
    {
        "linux-arm64"
    }
    #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
    {
        "win32-x64"
    }
    #[cfg(not(any(
        all(target_os = "macos", target_arch = "aarch64"),
        all(target_os = "macos", target_arch = "x86_64"),
        all(target_os = "linux", target_arch = "x86_64"),
        all(target_os = "linux", target_arch = "aarch64"),
        all(target_os = "windows", target_arch = "x86_64"),
    )))]
    {
        "unknown"
    }
}

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

    #[test]
    fn merge_into_attaches_all_fields() {
        let sp = SuperProps::new("mach_test".into(), false);
        let mut props = Map::new();
        sp.merge_into(&mut props);
        assert!(props.contains_key("provider_version"));
        assert!(props.contains_key("os"));
        assert_eq!(props["machine_id"], "mach_test");
        assert!(props.contains_key("session_id"));
        assert_eq!(props["authenticated"], false);
        assert_eq!(props["event_schema_version"], 1);
        assert!(props.contains_key("$insert_id"));
    }

    #[test]
    fn session_id_is_unique_per_instance() {
        let a = SuperProps::new("mach_x".into(), true);
        let b = SuperProps::new("mach_x".into(), true);
        assert_ne!(a.session_id, b.session_id);
    }
}