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.9.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 "1.7.9" => include_str!("../release/edgee.v1.7.9.js").trim(),
106 _ => return Ok(default_version),
108 };
109
110 Ok(content)
111}
112
113fn get_shopify_sdk_content(url: &str) -> Result<&str, &'static str> {
114 let default_version = include_str!("../release/shopify.v1.7.9.js").trim();
115 if url.ends_with("shopify.js") {
116 return Ok(default_version);
117 }
118
119 let Some((_, part)) = url.rsplit_once("shopify.v") else {
120 return Ok(default_version);
121 };
122 let Some(part) = part.strip_suffix(".js") else {
123 return Ok(default_version);
124 };
125
126 let content = match part {
127 "1.7.8" => include_str!("../release/shopify.v1.7.8.js").trim(),
128 "1.7.9" => include_str!("../release/shopify.v1.7.9.js").trim(),
129 _ => return Ok(default_version),
131 };
132 Ok(content)
133}
134
135fn dynamize_sdk(
136 sdk: &str,
137 host: &str,
138 autocapture: Autocapture,
139 edgee_cookie: &str,
140 edgee_cookie_domain: &str,
141) -> String {
142 let token = token::generate(host);
143 let mut sdk = sdk.replace("{{token}}", token.as_str());
144 sdk = sdk.replace("{{ecn}}", edgee_cookie);
145 sdk = sdk.replace("{{ecd}}", edgee_cookie_domain);
146
147 if !autocapture.pageview {
148 sdk = sdk.replace("{{ac_pageview}}", "n");
149 }
150 if autocapture.spa_pageview {
151 sdk = sdk.replace("{{ac_spa_pageview}}", "y");
152 }
153 if autocapture.engagement {
154 sdk = sdk.replace("{{ac_engagement}}", "y");
155 }
156 if autocapture.click {
157 sdk = sdk.replace("{{ac_click}}", "y");
158 }
159 if autocapture.form {
160 sdk = sdk.replace("{{ac_form}}", "y");
161 }
162 if autocapture.scroll {
163 sdk = sdk.replace("{{ac_scroll}}", "y");
164 }
165 sdk.to_string()
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn retrieves_sdk_content_for_valid_url() {
174 let url = "/sdk.js";
175 let host = "example.com";
176 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
177 assert!(result.is_ok());
178 assert!(result.unwrap().contains("{{side}}"));
179 }
180
181 #[test]
182 fn retrieves_sdk_with_custom_edgee_cookie_name() {
183 let url = "/sdk.js";
184 let host = "example.com";
185 let result = get_sdk(
186 url,
187 host,
188 Autocapture::default(),
189 "test_edgee_cookie_name",
190 "example.com",
191 );
192 assert!(result.is_ok());
193 assert!(result.unwrap().contains("test_edgee_cookie_name"));
194 }
195
196 #[test]
197 fn retrieves_versioned_sdk_content() {
198 let url = "/edgee.v1.5.0.js";
199 let host = "example.com";
200 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
201 assert!(result.is_ok());
202 assert!(result.unwrap().contains("{{side}}"));
203 }
204 #[test]
205 fn returns_error_for_invalid_url_format() {
206 let url = "/invalid.js";
207 let host = "example.com";
208 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
209 assert!(result.is_ok());
210 }
211
212 #[test]
213 fn returns_error_for_unsupported_version() {
214 let url = "/edgee.v2.0.0.js";
215 let host = "example.com";
216 let result = get_sdk(url, host, Autocapture::default(), "edgee", "example.com");
217 assert!(result.is_ok());
218 }
219}