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(
61 url: &str,
62 host: &str,
63 autocapture: Autocapture,
64 edgee_cookie: &str,
65 edgee_cookie_domain: &str,
66 cookies_for_sdk_injection: Option<String>,
67) -> Result<String, &'static str> {
68 let content = match url.contains("shopify.") {
69 true => get_shopify_sdk_content(url)?,
70 false => get_sdk_content(url)?,
71 };
72 Ok(dynamize_sdk(
73 content,
74 host,
75 autocapture,
76 edgee_cookie,
77 edgee_cookie_domain,
78 cookies_for_sdk_injection,
79 ))
80}
81
82pub fn get_sdk_for_unsafe_user(url: &str) -> Result<String, &'static str> {
83 let content = match url.contains("shopify.") {
84 true => get_shopify_sdk_content(url)?,
85 false => get_sdk_content(url)?,
86 };
87 Ok(content.replace("{{safe}}", "unsafe"))
88}
89
90fn get_sdk_content(url: &str) -> Result<&str, &'static str> {
91 let default_version = include_str!("../release/edgee.v1.8.2.js").trim();
92 if url.ends_with("sdk.js") {
93 return Ok(default_version);
94 }
95
96 let Some((_, part)) = url.rsplit_once("edgee.v") else {
97 return Ok(default_version);
98 };
99 let Some(part) = part.strip_suffix(".js") else {
100 return Ok(default_version);
101 };
102
103 let content = match part {
104 "1.7.6" => include_str!("../release/edgee.v1.7.6.js").trim(),
105 "1.7.7" => include_str!("../release/edgee.v1.7.7.js").trim(),
106 "1.7.8" => include_str!("../release/edgee.v1.7.8.js").trim(),
107 "1.7.9" => include_str!("../release/edgee.v1.7.9.js").trim(),
108 "1.8.0" => include_str!("../release/edgee.v1.8.0.js").trim(),
109 "1.8.1" => include_str!("../release/edgee.v1.8.1.js").trim(),
110 "1.8.2" => include_str!("../release/edgee.v1.8.2.js").trim(),
111 _ => return Ok(default_version),
113 };
114
115 Ok(content)
116}
117
118fn get_shopify_sdk_content(url: &str) -> Result<&str, &'static str> {
119 let default_version = include_str!("../release/shopify.v1.8.2.js").trim();
120 if url.ends_with("shopify.js") {
121 return Ok(default_version);
122 }
123
124 let Some((_, part)) = url.rsplit_once("shopify.v") else {
125 return Ok(default_version);
126 };
127 let Some(part) = part.strip_suffix(".js") else {
128 return Ok(default_version);
129 };
130
131 let content = match part {
132 "1.7.8" => include_str!("../release/shopify.v1.7.8.js").trim(),
133 "1.7.9" => include_str!("../release/shopify.v1.7.9.js").trim(),
134 "1.8.0" => include_str!("../release/shopify.v1.8.0.js").trim(),
135 "1.8.1" => include_str!("../release/shopify.v1.8.1.js").trim(),
136 "1.8.2" => include_str!("../release/shopify.v1.8.2.js").trim(),
137 _ => return Ok(default_version),
139 };
140 Ok(content)
141}
142
143fn dynamize_sdk(
144 sdk: &str,
145 host: &str,
146 autocapture: Autocapture,
147 edgee_cookie: &str,
148 edgee_cookie_domain: &str,
149 cookies_for_sdk_injection: Option<String>,
150) -> String {
151 let token = token::generate(host);
152 let mut sdk = sdk.replace("{{token}}", token.as_str());
153 sdk = sdk.replace("{{ecn}}", edgee_cookie);
154 sdk = sdk.replace("{{ecd}}", edgee_cookie_domain);
155
156 let cookies_for_sdk_injection = cookies_for_sdk_injection.unwrap_or("".to_string());
157 sdk = sdk.replace("{{ctf}}", cookies_for_sdk_injection.as_str());
158
159 if !autocapture.pageview {
160 sdk = sdk.replace("{{ac_pageview}}", "n");
161 }
162 if autocapture.spa_pageview {
163 sdk = sdk.replace("{{ac_spa_pageview}}", "y");
164 }
165 if autocapture.engagement {
166 sdk = sdk.replace("{{ac_engagement}}", "y");
167 }
168 if autocapture.click {
169 sdk = sdk.replace("{{ac_click}}", "y");
170 }
171 if autocapture.form {
172 sdk = sdk.replace("{{ac_form}}", "y");
173 }
174 if autocapture.scroll {
175 sdk = sdk.replace("{{ac_scroll}}", "y");
176 }
177 sdk.to_string()
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn retrieves_sdk_content_for_valid_url() {
186 let url = "/sdk.js";
187 let host = "example.com";
188 let result = get_sdk(
189 url,
190 host,
191 Autocapture::default(),
192 "edgee",
193 "example.com",
194 None,
195 );
196 assert!(result.is_ok());
197 assert!(result.unwrap().contains("{{side}}"));
198 }
199
200 #[test]
201 fn retrieves_sdk_with_custom_edgee_cookie_name() {
202 let url = "/sdk.js";
203 let host = "example.com";
204 let result = get_sdk(
205 url,
206 host,
207 Autocapture::default(),
208 "test_edgee_cookie_name",
209 "example.com",
210 None,
211 );
212 assert!(result.is_ok());
213 assert!(result.unwrap().contains("test_edgee_cookie_name"));
214 }
215
216 #[test]
217 fn retrieves_versioned_sdk_content() {
218 let url = "/edgee.v1.5.0.js";
219 let host = "example.com";
220 let result = get_sdk(
221 url,
222 host,
223 Autocapture::default(),
224 "edgee",
225 "example.com",
226 None,
227 );
228 assert!(result.is_ok());
229 assert!(result.unwrap().contains("{{side}}"));
230 }
231 #[test]
232 fn returns_error_for_invalid_url_format() {
233 let url = "/invalid.js";
234 let host = "example.com";
235 let result = get_sdk(
236 url,
237 host,
238 Autocapture::default(),
239 "edgee",
240 "example.com",
241 None,
242 );
243 assert!(result.is_ok());
244 }
245
246 #[test]
247 fn returns_error_for_unsupported_version() {
248 let url = "/edgee.v2.0.0.js";
249 let host = "example.com";
250 let result = get_sdk(
251 url,
252 host,
253 Autocapture::default(),
254 "edgee",
255 "example.com",
256 None,
257 );
258 assert!(result.is_ok());
259 }
260
261 #[test]
262 fn dynamizes_sdk_with_cookies_for_sdk_injection() {
263 let url = "/edgee.v2.0.0.js";
264 let host = "example.com";
265 let cookies_for_sdk_injection = Some("s,api_key_test".to_string());
266 let result = get_sdk(
267 url,
268 host,
269 Autocapture::default(),
270 "edgee",
271 "example.com",
272 cookies_for_sdk_injection,
273 );
274 assert!(result.is_ok());
275 assert!(result.unwrap().contains("s,api_key_test"));
276 }
277}