use serde::{Deserialize, Serialize};
pub mod token;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Autocapture {
#[serde(default)]
pub pageview: bool,
#[serde(default)]
pub spa_pageview: bool,
#[serde(default)]
pub engagement: bool,
#[serde(default)]
pub click: bool,
#[serde(default)]
pub form: bool,
#[serde(default)]
pub scroll: bool,
}
impl Default for Autocapture {
fn default() -> Self {
Self {
pageview: true,
spa_pageview: false,
engagement: false,
click: false,
form: false,
scroll: false,
}
}
}
pub fn get_sdk(
url: &str,
host: &str,
autocapture: Autocapture,
edgee_cookie: &str,
edgee_cookie_domain: &str,
cookies_for_sdk_injection: Option<String>,
) -> Result<String, &'static str> {
let content = match url.contains("shopify.") {
true => get_shopify_sdk_content(url)?,
false => get_sdk_content(url)?,
};
Ok(dynamize_sdk(
content,
host,
autocapture,
edgee_cookie,
edgee_cookie_domain,
cookies_for_sdk_injection,
))
}
pub fn get_sdk_for_unsafe_user(url: &str) -> Result<String, &'static str> {
let content = match url.contains("shopify.") {
true => get_shopify_sdk_content(url)?,
false => get_sdk_content(url)?,
};
Ok(content.replace("{{safe}}", "unsafe"))
}
fn get_sdk_content(url: &str) -> Result<&str, &'static str> {
let default_version = include_str!("../release/edgee.v1.8.1.js").trim();
if url.ends_with("sdk.js") {
return Ok(default_version);
}
let Some((_, part)) = url.rsplit_once("edgee.v") else {
return Ok(default_version);
};
let Some(part) = part.strip_suffix(".js") else {
return Ok(default_version);
};
let content = match part {
"1.7.6" => include_str!("../release/edgee.v1.7.6.js").trim(),
"1.7.7" => include_str!("../release/edgee.v1.7.7.js").trim(),
"1.7.8" => include_str!("../release/edgee.v1.7.8.js").trim(),
"1.7.9" => include_str!("../release/edgee.v1.7.9.js").trim(),
"1.8.0" => include_str!("../release/edgee.v1.8.0.js").trim(),
"1.8.1" => include_str!("../release/edgee.v1.8.1.js").trim(),
_ => return Ok(default_version),
};
Ok(content)
}
fn get_shopify_sdk_content(url: &str) -> Result<&str, &'static str> {
let default_version = include_str!("../release/shopify.v1.8.1.js").trim();
if url.ends_with("shopify.js") {
return Ok(default_version);
}
let Some((_, part)) = url.rsplit_once("shopify.v") else {
return Ok(default_version);
};
let Some(part) = part.strip_suffix(".js") else {
return Ok(default_version);
};
let content = match part {
"1.7.8" => include_str!("../release/shopify.v1.7.8.js").trim(),
"1.7.9" => include_str!("../release/shopify.v1.7.9.js").trim(),
"1.8.0" => include_str!("../release/shopify.v1.8.0.js").trim(),
"1.8.1" => include_str!("../release/shopify.v1.8.1.js").trim(),
_ => return Ok(default_version),
};
Ok(content)
}
fn dynamize_sdk(
sdk: &str,
host: &str,
autocapture: Autocapture,
edgee_cookie: &str,
edgee_cookie_domain: &str,
cookies_for_sdk_injection: Option<String>,
) -> String {
let token = token::generate(host);
let mut sdk = sdk.replace("{{token}}", token.as_str());
sdk = sdk.replace("{{ecn}}", edgee_cookie);
sdk = sdk.replace("{{ecd}}", edgee_cookie_domain);
let cookies_for_sdk_injection = cookies_for_sdk_injection.unwrap_or("".to_string());
sdk = sdk.replace("{{ctf}}", cookies_for_sdk_injection.as_str());
if !autocapture.pageview {
sdk = sdk.replace("{{ac_pageview}}", "n");
}
if autocapture.spa_pageview {
sdk = sdk.replace("{{ac_spa_pageview}}", "y");
}
if autocapture.engagement {
sdk = sdk.replace("{{ac_engagement}}", "y");
}
if autocapture.click {
sdk = sdk.replace("{{ac_click}}", "y");
}
if autocapture.form {
sdk = sdk.replace("{{ac_form}}", "y");
}
if autocapture.scroll {
sdk = sdk.replace("{{ac_scroll}}", "y");
}
sdk.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn retrieves_sdk_content_for_valid_url() {
let url = "/sdk.js";
let host = "example.com";
let result = get_sdk(
url,
host,
Autocapture::default(),
"edgee",
"example.com",
None,
);
assert!(result.is_ok());
assert!(result.unwrap().contains("{{side}}"));
}
#[test]
fn retrieves_sdk_with_custom_edgee_cookie_name() {
let url = "/sdk.js";
let host = "example.com";
let result = get_sdk(
url,
host,
Autocapture::default(),
"test_edgee_cookie_name",
"example.com",
None,
);
assert!(result.is_ok());
assert!(result.unwrap().contains("test_edgee_cookie_name"));
}
#[test]
fn retrieves_versioned_sdk_content() {
let url = "/edgee.v1.5.0.js";
let host = "example.com";
let result = get_sdk(
url,
host,
Autocapture::default(),
"edgee",
"example.com",
None,
);
assert!(result.is_ok());
assert!(result.unwrap().contains("{{side}}"));
}
#[test]
fn returns_error_for_invalid_url_format() {
let url = "/invalid.js";
let host = "example.com";
let result = get_sdk(
url,
host,
Autocapture::default(),
"edgee",
"example.com",
None,
);
assert!(result.is_ok());
}
#[test]
fn returns_error_for_unsupported_version() {
let url = "/edgee.v2.0.0.js";
let host = "example.com";
let result = get_sdk(
url,
host,
Autocapture::default(),
"edgee",
"example.com",
None,
);
assert!(result.is_ok());
}
#[test]
fn dynamizes_sdk_with_cookies_for_sdk_injection() {
let url = "/edgee.v2.0.0.js";
let host = "example.com";
let cookies_for_sdk_injection = Some("s,api_key_test".to_string());
let result = get_sdk(
url,
host,
Autocapture::default(),
"edgee",
"example.com",
cookies_for_sdk_injection,
);
assert!(result.is_ok());
assert!(result.unwrap().contains("s,api_key_test"));
}
}