1use std::collections::HashMap;
2
3use crate::headers::Headers;
4use crate::http::Method;
5
6use js_sys::{self, Object};
7use serde::Serialize;
8use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
9
10#[derive(Debug)]
12pub struct RequestInit {
13 pub body: Option<JsValue>,
15 pub headers: Headers,
17 pub cf: CfProperties,
20 pub method: Method,
22 pub redirect: RequestRedirect,
26}
27
28impl RequestInit {
29 pub fn new() -> Self {
30 Default::default()
31 }
32
33 pub fn with_headers(&mut self, headers: Headers) -> &mut Self {
34 self.headers = headers;
35 self
36 }
37
38 pub fn with_method(&mut self, method: Method) -> &mut Self {
39 self.method = method;
40 self
41 }
42
43 pub fn with_redirect(&mut self, redirect: RequestRedirect) -> &mut Self {
44 self.redirect = redirect;
45 self
46 }
47
48 pub fn with_body(&mut self, body: Option<JsValue>) -> &mut Self {
49 self.body = body;
50 self
51 }
52
53 pub fn with_cf_properties(&mut self, props: CfProperties) -> &mut Self {
54 self.cf = props;
55 self
56 }
57}
58
59impl From<&RequestInit> for web_sys::RequestInit {
60 fn from(req: &RequestInit) -> Self {
61 let inner = web_sys::RequestInit::new();
62 inner.set_headers(req.headers.as_ref());
63 inner.set_method(req.method.as_ref());
64 inner.set_redirect(req.redirect.into());
65 if let Some(body) = req.body.as_ref() {
66 inner.set_body(body);
67 }
68
69 let r = ::js_sys::Reflect::set(
71 inner.as_ref(),
72 &JsValue::from("cf"),
73 &JsValue::from(&req.cf),
74 );
75 debug_assert!(
76 r.is_ok(),
77 "setting properties should never fail on our dictionary objects"
78 );
79 let _ = r;
80
81 inner
82 }
83}
84
85impl Default for RequestInit {
86 fn default() -> Self {
87 Self {
88 body: None,
89 headers: Headers::new(),
90 cf: CfProperties::default(),
91 method: Method::Get,
92 redirect: RequestRedirect::default(),
93 }
94 }
95}
96
97#[derive(Debug)]
99pub struct CfProperties {
100 pub apps: Option<bool>,
102 pub cache_everything: Option<bool>,
106 pub cache_key: Option<String>,
110 pub cache_ttl: Option<u32>,
115 pub cache_ttl_by_status: Option<HashMap<String, i32>>,
122 pub image: Option<ResizeConfig>,
124 pub minify: Option<MinifyConfig>,
127 pub mirage: Option<bool>,
130 pub polish: Option<PolishConfig>,
132 pub resolve_override: Option<String>,
147 pub scrape_shield: Option<bool>,
150}
151
152impl From<&CfProperties> for JsValue {
153 fn from(props: &CfProperties) -> Self {
154 let obj = js_sys::Object::new();
155 let defaults = CfProperties::default();
156 let serializer = serde_wasm_bindgen::Serializer::new().serialize_maps_as_objects(true);
157
158 set_prop(
159 &obj,
160 &JsValue::from("apps"),
161 &JsValue::from(props.apps.unwrap_or(defaults.apps.unwrap_or_default())),
162 );
163
164 set_prop(
165 &obj,
166 &JsValue::from("cacheEverything"),
167 &JsValue::from(
168 props
169 .cache_everything
170 .unwrap_or(defaults.cache_everything.unwrap_or_default()),
171 ),
172 );
173
174 set_prop(
175 &obj,
176 &JsValue::from("cacheKey"),
177 &JsValue::from(
178 props
179 .cache_key
180 .clone()
181 .unwrap_or(defaults.cache_key.unwrap_or_default()),
182 ),
183 );
184
185 set_prop(
186 &obj,
187 &JsValue::from("cacheTtl"),
188 &JsValue::from(
189 props
190 .cache_ttl
191 .unwrap_or(defaults.cache_ttl.unwrap_or_default()),
192 ),
193 );
194
195 let ttl_status_map = props
196 .cache_ttl_by_status
197 .clone()
198 .unwrap_or(defaults.cache_ttl_by_status.unwrap_or_default());
199 set_prop(
200 &obj,
201 &JsValue::from("cacheTtlByStatus"),
202 &ttl_status_map.serialize(&serializer).unwrap_or_default(),
203 );
204
205 set_prop(
206 &obj,
207 &JsValue::from("minify"),
208 &JsValue::from(props.minify.unwrap_or(defaults.minify.unwrap_or_default())),
209 );
210
211 set_prop(
212 &obj,
213 &JsValue::from("mirage"),
214 &JsValue::from(props.mirage.unwrap_or(defaults.mirage.unwrap_or_default())),
215 );
216
217 let polish_val = props.polish.unwrap_or(defaults.polish.unwrap_or_default());
218 set_prop(
219 &obj,
220 &JsValue::from("polish"),
221 &serde_wasm_bindgen::to_value(&polish_val).unwrap(),
222 );
223
224 set_prop(
225 &obj,
226 &JsValue::from("resolveOverride"),
227 &JsValue::from(
228 props
229 .resolve_override
230 .clone()
231 .unwrap_or(defaults.resolve_override.unwrap_or_default()),
232 ),
233 );
234
235 set_prop(
236 &obj,
237 &JsValue::from("scrapeShield"),
238 &JsValue::from(
239 props
240 .scrape_shield
241 .unwrap_or(defaults.scrape_shield.unwrap_or_default()),
242 ),
243 );
244
245 if let Some(image) = &props.image {
246 set_prop(
247 &obj,
248 &JsValue::from("image"),
249 &serde_wasm_bindgen::to_value(&image).unwrap(),
250 );
251 }
252
253 obj.into()
254 }
255}
256
257fn set_prop(target: &Object, key: &JsValue, val: &JsValue) {
258 let r = ::js_sys::Reflect::set(target, key, val);
259 debug_assert!(
260 r.is_ok(),
261 "setting properties should never fail on our dictionary objects"
262 );
263 let _ = r;
264}
265
266impl CfProperties {
267 pub fn new() -> Self {
268 Default::default()
269 }
270}
271
272impl Default for CfProperties {
273 fn default() -> Self {
274 Self {
275 apps: Some(true),
276 cache_everything: Some(false),
277 cache_key: None,
278 cache_ttl: None,
279 cache_ttl_by_status: None,
280 minify: None,
281 mirage: Some(true),
282 image: None,
283 polish: None,
284 resolve_override: None,
285 scrape_shield: Some(true),
286 }
287 }
288}
289
290#[wasm_bindgen]
293#[derive(Clone, Copy, Debug, Default, Serialize)]
294#[serde(rename_all = "kebab-case")]
295pub struct MinifyConfig {
296 pub js: bool,
297 pub html: bool,
298 pub css: bool,
299}
300
301#[derive(Clone, Copy, Debug, Default, Serialize)]
304#[serde(rename_all = "kebab-case")]
305pub enum PolishConfig {
306 #[default]
307 Off,
308 Lossy,
309 Lossless,
310}
311
312#[derive(Clone, Debug, serde::Serialize)]
313#[serde(untagged)]
314pub enum ResizeBorder {
315 Uniform {
316 color: String,
317 width: usize,
318 },
319 Varying {
320 color: String,
321 top: usize,
322 right: usize,
323 bottom: usize,
324 left: usize,
325 },
326}
327
328#[derive(Clone, Debug, Serialize)]
329#[serde(rename_all = "kebab-case")]
330pub enum ResizeOriginAuth {
331 SharePublicly,
332}
333
334#[derive(Clone, Debug, Default, Serialize)]
337#[serde(rename_all = "kebab-case")]
338pub struct ResizeConfig {
339 pub anim: Option<bool>,
341 pub background: Option<String>,
343 pub blur: Option<u8>,
345 pub border: Option<ResizeBorder>,
347 pub brightness: Option<f64>,
349 pub compression: Option<ResizeCompression>,
351 pub contrast: Option<f64>,
353 pub dpr: Option<f64>,
355 pub draw: Option<ResizeDraw>,
357 pub fit: Option<ResizeFit>,
359 pub flip: Option<ResizeFlip>,
361 pub format: Option<ResizeFormat>,
363 pub gamma: Option<f64>,
365 pub gravity: Option<ResizeGravity>,
367 pub height: Option<usize>,
369 pub metadata: Option<ResizeMetadata>,
371 pub origin_auth: Option<ResizeOriginAuth>,
373 pub onerror: Option<ResizeOnerror>,
375 pub quality: Option<ResizeQuality>,
377 pub rotate: Option<usize>,
379 pub saturation: Option<f64>,
381 pub sharpen: Option<f64>,
383 pub trim: Option<ResizeTrim>,
385 pub width: Option<usize>,
387}
388
389#[derive(Clone, Copy, Debug, Serialize)]
390#[serde(rename_all = "kebab-case")]
391pub enum ResizeCompression {
392 Fast,
393}
394
395#[derive(Clone, Debug, Serialize)]
396#[serde(untagged)]
397pub enum ResizeDrawRepeat {
398 Uniform(bool),
399 Axis(String),
400}
401
402#[derive(Clone, Debug, Serialize)]
403#[serde(rename_all = "kebab-case")]
404pub struct ResizeDraw {
405 url: String,
406 opacity: Option<f64>,
407 repeat: Option<ResizeDrawRepeat>,
408 top: Option<usize>,
409 bottom: Option<usize>,
410 left: Option<usize>,
411 right: Option<usize>,
412}
413
414#[derive(Clone, Copy, Debug, Serialize)]
415#[serde(rename_all = "kebab-case")]
416pub enum ResizeFit {
417 ScaleDown,
418 Contain,
419 Cover,
420 Crop,
421 Pad,
422}
423
424#[derive(Clone, Copy, Debug, Serialize)]
425pub enum ResizeFlip {
426 #[serde(rename = "h")]
427 Horizontally,
428 #[serde(rename = "v")]
429 Vertically,
430 #[serde(rename = "hv")]
431 Both,
432}
433
434#[derive(Clone, Copy, Debug, Serialize)]
435#[serde(rename_all = "kebab-case")]
436pub enum ResizeFormat {
437 Avif,
438 Webp,
439 Json,
440 Jpeg,
441 Png,
442 BaselineJpeg,
443 PngForce,
444 Svg,
445}
446
447#[derive(Clone, Copy, Debug, Serialize)]
448#[serde(rename_all = "kebab-case")]
449pub enum ResizeGravitySide {
450 Auto,
451 Left,
452 Right,
453 Top,
454 Bottom,
455}
456
457#[derive(Clone, Copy, Debug, Serialize)]
458#[serde(rename_all = "kebab-case")]
459#[serde(untagged)]
460pub enum ResizeGravity {
461 Side(ResizeGravitySide),
462 Coords { x: f64, y: f64 },
463}
464
465#[derive(Clone, Copy, Debug, Serialize)]
466#[serde(rename_all = "kebab-case")]
467pub enum ResizeQualityLiteral {
468 Low,
469 MediumLow,
470 MediumHigh,
471 High,
472}
473
474#[derive(Clone, Copy, Debug, Serialize)]
475#[serde(rename_all = "kebab-case")]
476#[serde(untagged)]
477pub enum ResizeQuality {
478 Literal(ResizeQualityLiteral),
479 Specific { value: usize },
480}
481
482#[derive(Clone, Copy, Debug, Serialize)]
483#[serde(rename_all = "kebab-case")]
484pub enum ResizeMetadata {
485 Keep,
486 Copyright,
487 None,
488}
489
490#[derive(Clone, Copy, Debug, Serialize)]
491#[serde(rename_all = "kebab-case")]
492pub enum ResizeOnerror {
493 Redirect,
494}
495
496#[derive(Clone, Copy, Debug, Serialize)]
497#[serde(rename_all = "kebab-case")]
498pub struct ResizeTrim {
499 #[serde(skip_serializing_if = "Option::is_none")]
500 pub top: Option<usize>,
501 #[serde(skip_serializing_if = "Option::is_none")]
502 pub bottom: Option<usize>,
503 #[serde(skip_serializing_if = "Option::is_none")]
504 pub left: Option<usize>,
505 #[serde(skip_serializing_if = "Option::is_none")]
506 pub right: Option<usize>,
507 #[serde(skip_serializing_if = "Option::is_none")]
508 pub width: Option<usize>,
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub height: Option<usize>,
511}
512
513#[derive(Clone, Copy, Debug, Default, Serialize)]
514#[serde(rename_all = "kebab-case")]
515pub enum RequestRedirect {
516 Error,
517 #[default]
518 Follow,
519 Manual,
520}
521
522impl From<RequestRedirect> for &str {
523 fn from(redirect: RequestRedirect) -> Self {
524 match redirect {
525 RequestRedirect::Error => "error",
526 RequestRedirect::Follow => "follow",
527 RequestRedirect::Manual => "manual",
528 }
529 }
530}
531
532impl From<RequestRedirect> for web_sys::RequestRedirect {
533 fn from(redir: RequestRedirect) -> Self {
534 match redir {
535 RequestRedirect::Error => web_sys::RequestRedirect::Error,
536 RequestRedirect::Follow => web_sys::RequestRedirect::Follow,
537 RequestRedirect::Manual => web_sys::RequestRedirect::Manual,
538 }
539 }
540}