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) -> Result<String, &'static str> {
67 let content = match url.contains("shopify.") {
68 true => get_shopify_sdk_content(url)?,
69 false => get_sdk_content(url)?,
70 };
71 Ok(dynamize_sdk(
72 content,
73 host,
74 autocapture,
75 edgee_cookie,
76 edgee_cookie_domain,
77 ))
78}
79
80pub fn get_sdk_for_unsafe_user(url: &str) -> Result<String, &'static str> {
81 let content = match url.contains("shopify.") {
82 true => get_shopify_sdk_content(url)?,
83 false => get_sdk_content(url)?,
84 };
85 Ok(content.replace("{{safe}}", "unsafe"))
86}
87
88fn get_sdk_content(url: &str) -> Result<&str, &'static str> {
89 let default_version = include_str!("../release/edgee.v1.7.8.js").trim();
90 if url.ends_with("sdk.js") {
91 return Ok(default_version);
92 }
93
94 let Some((_, part)) = url.rsplit_once("edgee.v") else {
95 return Ok(default_version);
96 };
97 let Some(part) = part.strip_suffix(".js") else {
98 return Ok(default_version);
99 };
100
101 let content = match part {
102 "1.7.6" => include_str!("../release/edgee.v1.7.6.js").trim(),
103 "1.7.7" => include_str!("../release/edgee.v1.7.7.js").trim(),
104 "1.7.8" => include_str!("../release/edgee.v1.7.8.js").trim(),
105 _ => return Ok(default_version),
107 };
108
109 Ok(content)
110}
111
112fn get_shopify_sdk_content(url: &str) -> Result<&str, &'static str> {
113 let default_version = include_str!("../release/shopify.v1.7.8.js").trim();
114 if url.ends_with("shopify.js") {
115 return Ok(default_version);
116 }
117
118 let Some((_, part)) = url.rsplit_once("shopify.v") else {
119 return Ok(default_version);
120 };
121 let Some(part) = part.strip_suffix(".js") else {
122 return Ok(default_version);
123 };
124
125 let content = match part {
126 "1.7.8" => include_str!("../release/shopify.v1.7.8.js").trim(),
127 _ => return Ok(default_version),
129 };
130 Ok(content)
131}
132
133fn dynamize_sdk(
134 sdk: &str,
135 host: &str,
136 autocapture: Autocapture,
137 edgee_cookie: &str,
138 edgee_cookie_domain: &str,
139) -> String {
140 let token = token::generate(host);
141 let mut sdk = sdk.replace("{{token}}", token.as_str());
142 sdk = sdk.replace("{{ecn}}", edgee_cookie);
143 sdk = sdk.replace("{{ecd}}", edgee_cookie_domain);
144
145 if !autocapture.pageview {
146 sdk = sdk.replace("{{ac_pageview}}", "n");
147 }
148 if autocapture.spa_pageview {
149 sdk = sdk.replace("{{ac_spa_pageview}}", "y");
150 }
151 if autocapture.engagement {
152 sdk = sdk.replace("{{ac_engagement}}", "y");
153 }
154 if autocapture.click {
155 sdk = sdk.replace("{{ac_click}}", "y");
156 }
157 if autocapture.form {
158 sdk = sdk.replace("{{ac_form}}", "y");
159 }
160 if autocapture.scroll {
161 sdk = sdk.replace("{{ac_scroll}}", "y");
162 }
163 sdk.to_string()
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn retrieves_sdk_content_for_valid_url() {
172 let url = "/sdk.js";
173 let host = "example.com";
174 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
175 assert!(result.is_ok());
176 assert!(result.unwrap().contains("{{side}}"));
177 }
178
179 #[test]
180 fn retrieves_sdk_with_custom_edgee_cookie_name() {
181 let url = "/sdk.js";
182 let host = "example.com";
183 let result = get_sdk(
184 url,
185 host,
186 Autocapture::default(),
187 "test_edgee_cookie_name",
188 "example.com",
189 );
190 assert!(result.is_ok());
191 assert!(result.unwrap().contains("test_edgee_cookie_name"));
192 }
193
194 #[test]
195 fn retrieves_versioned_sdk_content() {
196 let url = "/edgee.v1.5.0.js";
197 let host = "example.com";
198 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
199 assert!(result.is_ok());
200 assert!(result.unwrap().contains("{{side}}"));
201 }
202 #[test]
203 fn returns_error_for_invalid_url_format() {
204 let url = "/invalid.js";
205 let host = "example.com";
206 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
207 assert!(result.is_ok());
208 }
209
210 #[test]
211 fn returns_error_for_unsupported_version() {
212 let url = "/edgee.v2.0.0.js";
213 let host = "example.com";
214 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
215 assert!(result.is_ok());
216 }
217}