edgee_sdk/
lib.rs

1use serde::{Deserialize, Serialize};
2
3pub mod token;
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct Autocapture {
7    #[serde(default)]
8    pub pageview: bool,
9    #[serde(default)]
10    pub spa_pageview: bool,
11    #[serde(default)]
12    pub engagement: bool,
13    #[serde(default)]
14    pub click: bool,
15    #[serde(default)]
16    pub form: bool,
17    #[serde(default)]
18    pub scroll: bool,
19}
20
21impl Default for Autocapture {
22    fn default() -> Self {
23        Self {
24            pageview: true,
25            spa_pageview: false,
26            engagement: false,
27            click: false,
28            form: false,
29            scroll: false,
30        }
31    }
32}
33
34/// Retrieves and customizes the SDK content.
35///
36/// This function gets the SDK content based on the URL and customizes it for the given host and autocapture settings.
37/// For URLs ending in "sdk.js", it returns the latest version. Otherwise, it extracts and returns a specific version.
38///
39/// # Arguments
40///
41/// * `url` - A string slice containing the URL path to get the SDK from (e.g. "/_edgee/sdk.js" or "/_edgee/edgee.v1.5.0.js")
42/// * `host` - A string slice containing the host domain to customize the SDK for
43/// * `autocapture` - An Autocapture struct specifying which events to automatically capture
44///
45/// # Returns
46///
47/// * `Ok(String)` - The customized SDK content if successful
48/// * `Err(&'static str)` - An error message if the SDK content could not be retrieved
49///
50/// # Example
51///
52/// ```rust
53/// use edgee_sdk::Autocapture;
54/// let url = "/_edgee/edgee.v1.5.0.js";
55/// let host = "example.com";
56/// let sdk_content = edgee_sdk::get_sdk(url, host, Autocapture::default());
57/// assert!(sdk_content.is_ok());
58/// ```
59pub fn get_sdk(url: &str, host: &str, autocapture: Autocapture) -> Result<String, &'static str> {
60    let content = get_sdk_content(url)?;
61    Ok(dynamize_sdk(content, host, autocapture))
62}
63
64pub fn get_sdk_for_unsafe_user(url: &str) -> Result<String, &'static str> {
65    let content = get_sdk_content(url)?;
66    Ok(content.replace("{{safe}}", "unsafe"))
67}
68
69fn get_sdk_content(url: &str) -> Result<&str, &'static str> {
70    if url.ends_with("sdk.js") {
71        return Ok(include_str!("../release/edgee.v1.6.0.js").trim());
72    }
73
74    let Some((_, part)) = url.rsplit_once("edgee.v") else {
75        return Err("Failed to read the JS SDK file");
76    };
77    let Some(part) = part.strip_suffix(".js") else {
78        return Err("Failed to read the JS SDK file");
79    };
80
81    let content = match part {
82        "1.3.2" => include_str!("../release/edgee.v1.3.2.js").trim(),
83        "1.4.0" => include_str!("../release/edgee.v1.4.0.js").trim(),
84        "1.5.0" => include_str!("../release/edgee.v1.5.0.js").trim(),
85        // Add more versions as needed
86        _ => return Err("Failed to read the JS SDK file"),
87    };
88
89    Ok(content)
90}
91
92fn dynamize_sdk(sdk: &str, host: &str, autocapture: Autocapture) -> String {
93    let token = token::generate(host);
94    let mut sdk = sdk.replace("{{token}}", token.as_str());
95
96    if !autocapture.pageview {
97        sdk = sdk.replace("{{ac_pageview}}", "n");
98    }
99    if autocapture.spa_pageview {
100        sdk = sdk.replace("{{ac_spa_pageview}}", "y");
101    }
102    if autocapture.engagement {
103        sdk = sdk.replace("{{ac_engagement}}", "y");
104    }
105    if autocapture.click {
106        sdk = sdk.replace("{{ac_click}}", "y");
107    }
108    if autocapture.form {
109        sdk = sdk.replace("{{ac_form}}", "y");
110    }
111    if autocapture.scroll {
112        sdk = sdk.replace("{{ac_scroll}}", "y");
113    }
114    sdk.to_string()
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn retrieves_sdk_content_for_valid_url() {
123        let url = "/sdk.js";
124        let host = "example.com";
125        let result = get_sdk(url, host, Autocapture::default());
126        assert!(result.is_ok());
127        assert!(result.unwrap().contains("{{side}}"));
128    }
129
130    #[test]
131    fn retrieves_versioned_sdk_content() {
132        let url = "/edgee.v1.5.0.js";
133        let host = "example.com";
134        let result = get_sdk(url, host, Autocapture::default());
135        assert!(result.is_ok());
136        assert!(result.unwrap().contains("{{side}}"));
137    }
138
139    #[test]
140    fn returns_error_for_invalid_url_format() {
141        let url = "/invalid.js";
142        let host = "example.com";
143        let result = get_sdk(url, host, Autocapture::default());
144        assert!(result.is_err());
145        assert_eq!(result.unwrap_err(), "Failed to read the JS SDK file");
146    }
147
148    #[test]
149    fn returns_error_for_unsupported_version() {
150        let url = "/edgee.v2.0.0.js";
151        let host = "example.com";
152        let result = get_sdk(url, host, Autocapture::default());
153        assert!(result.is_err());
154        assert_eq!(result.unwrap_err(), "Failed to read the JS SDK file");
155    }
156}