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
34pub 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.1.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 "1.6.0" => include_str!("../release/edgee.v1.6.0.js").trim(),
86 "1.6.1" => include_str!("../release/edgee.v1.6.1.js").trim(),
87 _ => return Err("Failed to read the JS SDK file"),
89 };
90
91 Ok(content)
92}
93
94fn dynamize_sdk(sdk: &str, host: &str, autocapture: Autocapture) -> String {
95 let token = token::generate(host);
96 let mut sdk = sdk.replace("{{token}}", token.as_str());
97
98 if !autocapture.pageview {
99 sdk = sdk.replace("{{ac_pageview}}", "n");
100 }
101 if autocapture.spa_pageview {
102 sdk = sdk.replace("{{ac_spa_pageview}}", "y");
103 }
104 if autocapture.engagement {
105 sdk = sdk.replace("{{ac_engagement}}", "y");
106 }
107 if autocapture.click {
108 sdk = sdk.replace("{{ac_click}}", "y");
109 }
110 if autocapture.form {
111 sdk = sdk.replace("{{ac_form}}", "y");
112 }
113 if autocapture.scroll {
114 sdk = sdk.replace("{{ac_scroll}}", "y");
115 }
116 sdk.to_string()
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn retrieves_sdk_content_for_valid_url() {
125 let url = "/sdk.js";
126 let host = "example.com";
127 let result = get_sdk(url, host, Autocapture::default());
128 assert!(result.is_ok());
129 assert!(result.unwrap().contains("{{side}}"));
130 }
131
132 #[test]
133 fn retrieves_versioned_sdk_content() {
134 let url = "/edgee.v1.5.0.js";
135 let host = "example.com";
136 let result = get_sdk(url, host, Autocapture::default());
137 assert!(result.is_ok());
138 assert!(result.unwrap().contains("{{side}}"));
139 }
140
141 #[test]
142 fn returns_error_for_invalid_url_format() {
143 let url = "/invalid.js";
144 let host = "example.com";
145 let result = get_sdk(url, host, Autocapture::default());
146 assert!(result.is_err());
147 assert_eq!(result.unwrap_err(), "Failed to read the JS SDK file");
148 }
149
150 #[test]
151 fn returns_error_for_unsupported_version() {
152 let url = "/edgee.v2.0.0.js";
153 let host = "example.com";
154 let result = get_sdk(url, host, Autocapture::default());
155 assert!(result.is_err());
156 assert_eq!(result.unwrap_err(), "Failed to read the JS SDK file");
157 }
158}