Skip to main content

clawser_browser/
types.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use std::collections::HashMap;
3
4/// Deserialize u64 from either a JSON number or a string like "12345".
5fn deserialize_u64_flexible<'de, D>(deserializer: D) -> Result<u64, D::Error>
6where
7    D: Deserializer<'de>,
8{
9    use serde::de;
10    let v = serde_json::Value::deserialize(deserializer)?;
11    match &v {
12        serde_json::Value::Number(n) => n.as_u64().ok_or_else(|| {
13            de::Error::custom(format!("number out of u64 range: {}", n))
14        }),
15        serde_json::Value::String(s) => {
16            s.parse::<u64>().map_err(de::Error::custom)
17        }
18        _ => Err(de::Error::custom(format!("expected number or string, got {}", v))),
19    }
20}
21
22fn serialize_u64_as_string<S>(val: &u64, serializer: S) -> Result<S::Ok, S::Error>
23where
24    S: Serializer,
25{
26    serializer.serialize_str(&val.to_string())
27}
28
29/// Deterministic seed for antidetect profile. Same seed = same fingerprint.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct Seed {
32    #[serde(deserialize_with = "deserialize_u64_flexible", serialize_with = "serialize_u64_as_string")]
33    pub hw_seed: u64,
34    #[serde(deserialize_with = "deserialize_u64_flexible", serialize_with = "serialize_u64_as_string")]
35    pub canvas_seed: u64,
36    #[serde(deserialize_with = "deserialize_u64_flexible", serialize_with = "serialize_u64_as_string")]
37    pub webgl_seed: u64,
38    #[serde(deserialize_with = "deserialize_u64_flexible", serialize_with = "serialize_u64_as_string")]
39    pub audio_seed: u64,
40    #[serde(deserialize_with = "deserialize_u64_flexible", serialize_with = "serialize_u64_as_string")]
41    pub client_rects_seed: u64,
42}
43
44/// A captured API call — either HTTP or WebSocket.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46#[serde(tag = "type")]
47pub enum CapturedCall {
48    #[serde(rename = "http")]
49    Http {
50        method: String,
51        url: String,
52        headers: HashMap<String, String>,
53        body: Option<String>,
54        #[serde(default)]
55        caller_fn_id: String,
56    },
57    #[serde(rename = "websocket")]
58    WebSocket {
59        url: String,
60        #[serde(default)]
61        messages: Vec<WsEvent>,
62        #[serde(default)]
63        caller_fn_id: String,
64    },
65}
66
67/// A WebSocket event (sent or received message).
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct WsEvent {
70    pub direction: String,
71    pub data: String,
72    #[serde(default)]
73    pub timestamp: u64,
74}
75
76/// HTTP response from the browser's network stack.
77#[derive(Debug, Clone)]
78pub struct Response {
79    pub status: u16,
80    pub headers: HashMap<String, String>,
81    pub body: Vec<u8>,
82    pub url: String,
83}
84
85/// A browser cookie.
86#[derive(Debug, Clone, Serialize, Deserialize, Default)]
87pub struct Cookie {
88    pub name: String,
89    pub value: String,
90    #[serde(default)]
91    pub domain: String,
92    #[serde(default)]
93    pub path: String,
94    #[serde(default)]
95    pub secure: bool,
96    #[serde(default)]
97    pub httponly: bool,
98}