crawlberg 1.7.2 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  // This file is auto-generated by alef. DO NOT EDIT.
2
- // alef:hash:9563e80a11ae24fda8f480033a40a3dd9382715d77f7a2e60c254f7f3ab71ad5
2
+ // alef:hash:51d55e2247bdc2514829f3eaafb5c8524624f269469856210cf0950e6c206e7f
3
3
  // Re-generate with: alef generate
4
4
  #![allow(dead_code, unused_imports, unused_variables)]
5
5
  #![allow(
@@ -821,7 +821,7 @@ impl BatchScrapeResults {
821
821
  }
822
822
  }
823
823
 
824
- #[derive(Clone, Debug, serde::Serialize)]
824
+ #[derive(Clone, serde::Serialize)]
825
825
  #[serde(default)]
826
826
  #[magnus::wrap(class = "Crawlberg::BrowserConfig")]
827
827
  pub struct BrowserConfig {
@@ -830,6 +830,8 @@ pub struct BrowserConfig {
830
830
  endpoint: Option<String>,
831
831
  #[serde(default = "default_timeout")]
832
832
  timeout: u64,
833
+ overall_timeout: u64,
834
+ shutdown_timeout: u64,
833
835
  wait: BrowserWait,
834
836
  wait_selector: Option<String>,
835
837
  extra_wait: Option<u64>,
@@ -839,6 +841,8 @@ pub struct BrowserConfig {
839
841
  robots_user_agent: Option<String>,
840
842
  capture_network_events: bool,
841
843
  session_affinity: bool,
844
+ chrome_path: Option<String>,
845
+ chrome_args: Vec<String>,
842
846
  }
843
847
 
844
848
  unsafe impl IntoValueFromNative for BrowserConfig {}
@@ -868,6 +872,29 @@ impl magnus::TryConvert for BrowserConfig {
868
872
  }
869
873
 
870
874
  unsafe impl TryConvertOwned for BrowserConfig {}
875
+ impl std::fmt::Debug for BrowserConfig {
876
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
877
+ let mut debug = f.debug_struct("BrowserConfig");
878
+ debug.field("mode", &self.mode);
879
+ debug.field("backend", &self.backend);
880
+ debug.field("endpoint", &"<redacted>");
881
+ debug.field("timeout", &self.timeout);
882
+ debug.field("overall_timeout", &self.overall_timeout);
883
+ debug.field("shutdown_timeout", &self.shutdown_timeout);
884
+ debug.field("wait", &self.wait);
885
+ debug.field("wait_selector", &self.wait_selector);
886
+ debug.field("extra_wait", &self.extra_wait);
887
+ debug.field("proxy", &self.proxy);
888
+ debug.field("block_url_patterns", &self.block_url_patterns);
889
+ debug.field("eval_script", &"<redacted>");
890
+ debug.field("robots_user_agent", &self.robots_user_agent);
891
+ debug.field("capture_network_events", &self.capture_network_events);
892
+ debug.field("session_affinity", &self.session_affinity);
893
+ debug.field("chrome_path", &self.chrome_path);
894
+ debug.field("chrome_args", &"<redacted>");
895
+ debug.finish()
896
+ }
897
+ }
871
898
  impl<'de> serde::Deserialize<'de> for BrowserConfig {
872
899
  fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
873
900
  where
@@ -926,6 +953,24 @@ impl BrowserConfig {
926
953
  })?,
927
954
  None => 30000,
928
955
  },
956
+ overall_timeout: match kwargs.get(ruby.to_symbol("overall_timeout")) {
957
+ Some(v) => u64::try_convert(v).map_err(|e| {
958
+ magnus::Error::new(
959
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
960
+ format!("invalid value for `overall_timeout`: {}", e),
961
+ )
962
+ })?,
963
+ None => 60000,
964
+ },
965
+ shutdown_timeout: match kwargs.get(ruby.to_symbol("shutdown_timeout")) {
966
+ Some(v) => u64::try_convert(v).map_err(|e| {
967
+ magnus::Error::new(
968
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
969
+ format!("invalid value for `shutdown_timeout`: {}", e),
970
+ )
971
+ })?,
972
+ None => 5000,
973
+ },
929
974
  wait: match kwargs.get(ruby.to_symbol("wait")) {
930
975
  Some(v) => BrowserWait::try_convert(v).map_err(|e| {
931
976
  magnus::Error::new(
@@ -1007,6 +1052,24 @@ impl BrowserConfig {
1007
1052
  })?,
1008
1053
  None => true,
1009
1054
  },
1055
+ chrome_path: match kwargs.get(ruby.to_symbol("chrome_path")).filter(|v| !v.is_nil()) {
1056
+ Some(v) => Some(String::try_convert(v).map_err(|e| {
1057
+ magnus::Error::new(
1058
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
1059
+ format!("invalid value for `chrome_path`: {}", e),
1060
+ )
1061
+ })?),
1062
+ None => None,
1063
+ },
1064
+ chrome_args: match kwargs.get(ruby.to_symbol("chrome_args")) {
1065
+ Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
1066
+ magnus::Error::new(
1067
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
1068
+ format!("invalid value for `chrome_args`: {}", e),
1069
+ )
1070
+ })?,
1071
+ None => Default::default(),
1072
+ },
1010
1073
  })
1011
1074
  }
1012
1075
 
@@ -1026,6 +1089,14 @@ impl BrowserConfig {
1026
1089
  self.timeout.clone()
1027
1090
  }
1028
1091
 
1092
+ fn overall_timeout(&self) -> u64 {
1093
+ self.overall_timeout.clone()
1094
+ }
1095
+
1096
+ fn shutdown_timeout(&self) -> u64 {
1097
+ self.shutdown_timeout.clone()
1098
+ }
1099
+
1029
1100
  fn wait(&self) -> BrowserWait {
1030
1101
  self.wait.clone()
1031
1102
  }
@@ -1061,6 +1132,14 @@ impl BrowserConfig {
1061
1132
  fn session_affinity(&self) -> bool {
1062
1133
  self.session_affinity
1063
1134
  }
1135
+
1136
+ fn chrome_path(&self) -> Option<String> {
1137
+ self.chrome_path.clone()
1138
+ }
1139
+
1140
+ fn chrome_args(&self) -> Vec<String> {
1141
+ self.chrome_args.clone()
1142
+ }
1064
1143
  }
1065
1144
 
1066
1145
  #[derive(Clone, Debug, serde::Serialize)]
@@ -1357,6 +1436,7 @@ pub struct ContentConfig {
1357
1436
  wrap: bool,
1358
1437
  wrap_width: usize,
1359
1438
  include_document_structure: bool,
1439
+ extract_metadata: bool,
1360
1440
  }
1361
1441
 
1362
1442
  unsafe impl IntoValueFromNative for ContentConfig {}
@@ -1516,6 +1596,15 @@ impl ContentConfig {
1516
1596
  })?,
1517
1597
  None => true,
1518
1598
  },
1599
+ extract_metadata: match kwargs.get(ruby.to_symbol("extract_metadata")) {
1600
+ Some(v) => bool::try_convert(v).map_err(|e| {
1601
+ magnus::Error::new(
1602
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
1603
+ format!("invalid value for `extract_metadata`: {}", e),
1604
+ )
1605
+ })?,
1606
+ None => true,
1607
+ },
1519
1608
  })
1520
1609
  }
1521
1610
 
@@ -1566,9 +1655,13 @@ impl ContentConfig {
1566
1655
  fn include_document_structure(&self) -> bool {
1567
1656
  self.include_document_structure
1568
1657
  }
1658
+
1659
+ fn extract_metadata(&self) -> bool {
1660
+ self.extract_metadata
1661
+ }
1569
1662
  }
1570
1663
 
1571
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
1664
+ #[derive(Clone, serde::Serialize, serde::Deserialize)]
1572
1665
  #[serde(default)]
1573
1666
  #[magnus::wrap(class = "Crawlberg::CookieInfo")]
1574
1667
  pub struct CookieInfo {
@@ -1605,6 +1698,16 @@ impl magnus::TryConvert for CookieInfo {
1605
1698
  }
1606
1699
 
1607
1700
  unsafe impl TryConvertOwned for CookieInfo {}
1701
+ impl std::fmt::Debug for CookieInfo {
1702
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1703
+ let mut debug = f.debug_struct("CookieInfo");
1704
+ debug.field("name", &self.name);
1705
+ debug.field("value", &"<redacted>");
1706
+ debug.field("domain", &self.domain);
1707
+ debug.field("path", &self.path);
1708
+ debug.finish()
1709
+ }
1710
+ }
1608
1711
 
1609
1712
  impl Default for CookieInfo {
1610
1713
  fn default() -> Self {
@@ -1675,7 +1778,7 @@ impl CookieInfo {
1675
1778
  }
1676
1779
  }
1677
1780
 
1678
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
1781
+ #[derive(Clone, serde::Serialize, serde::Deserialize)]
1679
1782
  #[serde(default)]
1680
1783
  #[magnus::wrap(class = "Crawlberg::CrawlConfig")]
1681
1784
  pub struct CrawlConfig {
@@ -1694,6 +1797,11 @@ pub struct CrawlConfig {
1694
1797
  allow_subdomains: bool,
1695
1798
  include_paths: Vec<String>,
1696
1799
  exclude_paths: Vec<String>,
1800
+ path_patterns_match_query: bool,
1801
+ path_patterns_match_url: bool,
1802
+ dedup_include_query: bool,
1803
+ strip_tracking_params: bool,
1804
+ tracking_params: Vec<String>,
1697
1805
  custom_headers: HashMap<String, String>,
1698
1806
  #[serde(default = "default_timeout")]
1699
1807
  request_timeout: u64,
@@ -1701,6 +1809,9 @@ pub struct CrawlConfig {
1701
1809
  max_redirects: usize,
1702
1810
  retry_count: usize,
1703
1811
  retry_codes: Vec<u16>,
1812
+ retry_initial_delay_ms: u64,
1813
+ retry_max_delay_ms: u64,
1814
+ rate_limit_jitter_ratio: f64,
1704
1815
  cookies_enabled: bool,
1705
1816
  auth: Option<AuthConfig>,
1706
1817
  max_body_size: Option<usize>,
@@ -1756,6 +1867,67 @@ impl magnus::TryConvert for CrawlConfig {
1756
1867
  }
1757
1868
 
1758
1869
  unsafe impl TryConvertOwned for CrawlConfig {}
1870
+ impl std::fmt::Debug for CrawlConfig {
1871
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1872
+ let mut debug = f.debug_struct("CrawlConfig");
1873
+ debug.field("max_depth", &self.max_depth);
1874
+ debug.field("max_pages", &self.max_pages);
1875
+ debug.field("max_links_per_page", &self.max_links_per_page);
1876
+ debug.field("max_concurrent", &self.max_concurrent);
1877
+ debug.field("crawl_strategy", &self.crawl_strategy);
1878
+ debug.field("content_filter", &self.content_filter);
1879
+ debug.field("bm25_query", &self.bm25_query);
1880
+ debug.field("bm25_threshold", &self.bm25_threshold);
1881
+ debug.field("respect_robots_txt", &self.respect_robots_txt);
1882
+ debug.field("soft_http_errors", &self.soft_http_errors);
1883
+ debug.field("user_agent", &self.user_agent);
1884
+ debug.field("stay_on_domain", &self.stay_on_domain);
1885
+ debug.field("allow_subdomains", &self.allow_subdomains);
1886
+ debug.field("include_paths", &self.include_paths);
1887
+ debug.field("exclude_paths", &self.exclude_paths);
1888
+ debug.field("path_patterns_match_query", &self.path_patterns_match_query);
1889
+ debug.field("path_patterns_match_url", &self.path_patterns_match_url);
1890
+ debug.field("dedup_include_query", &self.dedup_include_query);
1891
+ debug.field("strip_tracking_params", &self.strip_tracking_params);
1892
+ debug.field("tracking_params", &self.tracking_params);
1893
+ debug.field("custom_headers", &"<redacted>");
1894
+ debug.field("request_timeout", &self.request_timeout);
1895
+ debug.field("rate_limit_ms", &self.rate_limit_ms);
1896
+ debug.field("max_redirects", &self.max_redirects);
1897
+ debug.field("retry_count", &self.retry_count);
1898
+ debug.field("retry_codes", &self.retry_codes);
1899
+ debug.field("retry_initial_delay_ms", &self.retry_initial_delay_ms);
1900
+ debug.field("retry_max_delay_ms", &self.retry_max_delay_ms);
1901
+ debug.field("rate_limit_jitter_ratio", &self.rate_limit_jitter_ratio);
1902
+ debug.field("cookies_enabled", &self.cookies_enabled);
1903
+ debug.field("auth", &self.auth);
1904
+ debug.field("max_body_size", &self.max_body_size);
1905
+ debug.field("remove_tags", &self.remove_tags);
1906
+ debug.field("content", &self.content);
1907
+ debug.field("map_limit", &self.map_limit);
1908
+ debug.field("map_search", &self.map_search);
1909
+ debug.field("download_assets", &self.download_assets);
1910
+ debug.field("asset_types", &self.asset_types);
1911
+ debug.field("max_asset_size", &self.max_asset_size);
1912
+ debug.field("browser", &self.browser);
1913
+ debug.field("proxy", &self.proxy);
1914
+ debug.field("user_agents", &self.user_agents);
1915
+ debug.field("capture_screenshot", &self.capture_screenshot);
1916
+ debug.field("follow_document_urls", &self.follow_document_urls);
1917
+ debug.field("document_url_depth", &self.document_url_depth);
1918
+ debug.field("download_documents", &self.download_documents);
1919
+ debug.field("document_max_size", &self.document_max_size);
1920
+ debug.field("document_mime_types", &self.document_mime_types);
1921
+ debug.field("document_output_dir", &self.document_output_dir);
1922
+ debug.field("document_content_encoding", &self.document_content_encoding);
1923
+ debug.field("warc_output", &self.warc_output);
1924
+ debug.field("browser_profile", &self.browser_profile);
1925
+ debug.field("save_browser_profile", &self.save_browser_profile);
1926
+ debug.field("ssrf", &self.ssrf);
1927
+ debug.field("ssrf_deny_private_explicit", &self.ssrf_deny_private_explicit);
1928
+ debug.finish()
1929
+ }
1930
+ }
1759
1931
 
1760
1932
  impl Default for CrawlConfig {
1761
1933
  fn default() -> Self {
@@ -1905,6 +2077,56 @@ impl CrawlConfig {
1905
2077
  })?,
1906
2078
  None => Default::default(),
1907
2079
  },
2080
+ path_patterns_match_query: match kwargs.get(ruby.to_symbol("path_patterns_match_query")) {
2081
+ Some(v) => bool::try_convert(v).map_err(|e| {
2082
+ magnus::Error::new(
2083
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2084
+ format!("invalid value for `path_patterns_match_query`: {}", e),
2085
+ )
2086
+ })?,
2087
+ None => false,
2088
+ },
2089
+ path_patterns_match_url: match kwargs.get(ruby.to_symbol("path_patterns_match_url")) {
2090
+ Some(v) => bool::try_convert(v).map_err(|e| {
2091
+ magnus::Error::new(
2092
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2093
+ format!("invalid value for `path_patterns_match_url`: {}", e),
2094
+ )
2095
+ })?,
2096
+ None => false,
2097
+ },
2098
+ dedup_include_query: match kwargs.get(ruby.to_symbol("dedup_include_query")) {
2099
+ Some(v) => bool::try_convert(v).map_err(|e| {
2100
+ magnus::Error::new(
2101
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2102
+ format!("invalid value for `dedup_include_query`: {}", e),
2103
+ )
2104
+ })?,
2105
+ None => false,
2106
+ },
2107
+ strip_tracking_params: match kwargs.get(ruby.to_symbol("strip_tracking_params")) {
2108
+ Some(v) => bool::try_convert(v).map_err(|e| {
2109
+ magnus::Error::new(
2110
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2111
+ format!("invalid value for `strip_tracking_params`: {}", e),
2112
+ )
2113
+ })?,
2114
+ None => false,
2115
+ },
2116
+ tracking_params: match kwargs.get(ruby.to_symbol("tracking_params")) {
2117
+ Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
2118
+ magnus::Error::new(
2119
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2120
+ format!("invalid value for `tracking_params`: {}", e),
2121
+ )
2122
+ })?,
2123
+ None => vec![
2124
+ "utm_*".to_string(),
2125
+ "fbclid".to_string(),
2126
+ "gclid".to_string(),
2127
+ "ref".to_string(),
2128
+ ],
2129
+ },
1908
2130
  custom_headers: match kwargs.get(ruby.to_symbol("custom_headers")) {
1909
2131
  Some(v) => <HashMap<String, String>>::try_convert(v).map_err(|e| {
1910
2132
  magnus::Error::new(
@@ -1959,6 +2181,33 @@ impl CrawlConfig {
1959
2181
  })?,
1960
2182
  None => Default::default(),
1961
2183
  },
2184
+ retry_initial_delay_ms: match kwargs.get(ruby.to_symbol("retry_initial_delay_ms")) {
2185
+ Some(v) => u64::try_convert(v).map_err(|e| {
2186
+ magnus::Error::new(
2187
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2188
+ format!("invalid value for `retry_initial_delay_ms`: {}", e),
2189
+ )
2190
+ })?,
2191
+ None => 100,
2192
+ },
2193
+ retry_max_delay_ms: match kwargs.get(ruby.to_symbol("retry_max_delay_ms")) {
2194
+ Some(v) => u64::try_convert(v).map_err(|e| {
2195
+ magnus::Error::new(
2196
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2197
+ format!("invalid value for `retry_max_delay_ms`: {}", e),
2198
+ )
2199
+ })?,
2200
+ None => 60000,
2201
+ },
2202
+ rate_limit_jitter_ratio: match kwargs.get(ruby.to_symbol("rate_limit_jitter_ratio")) {
2203
+ Some(v) => f64::try_convert(v).map_err(|e| {
2204
+ magnus::Error::new(
2205
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
2206
+ format!("invalid value for `rate_limit_jitter_ratio`: {}", e),
2207
+ )
2208
+ })?,
2209
+ None => 0.0,
2210
+ },
1962
2211
  cookies_enabled: match kwargs.get(ruby.to_symbol("cookies_enabled")) {
1963
2212
  Some(v) => bool::try_convert(v).map_err(|e| {
1964
2213
  magnus::Error::new(
@@ -2265,6 +2514,26 @@ impl CrawlConfig {
2265
2514
  self.exclude_paths.clone()
2266
2515
  }
2267
2516
 
2517
+ fn path_patterns_match_query(&self) -> bool {
2518
+ self.path_patterns_match_query
2519
+ }
2520
+
2521
+ fn path_patterns_match_url(&self) -> bool {
2522
+ self.path_patterns_match_url
2523
+ }
2524
+
2525
+ fn dedup_include_query(&self) -> bool {
2526
+ self.dedup_include_query
2527
+ }
2528
+
2529
+ fn strip_tracking_params(&self) -> bool {
2530
+ self.strip_tracking_params
2531
+ }
2532
+
2533
+ fn tracking_params(&self) -> Vec<String> {
2534
+ self.tracking_params.clone()
2535
+ }
2536
+
2268
2537
  fn custom_headers(&self) -> HashMap<String, String> {
2269
2538
  self.custom_headers.clone()
2270
2539
  }
@@ -2289,6 +2558,18 @@ impl CrawlConfig {
2289
2558
  self.retry_codes.clone()
2290
2559
  }
2291
2560
 
2561
+ fn retry_initial_delay_ms(&self) -> u64 {
2562
+ self.retry_initial_delay_ms
2563
+ }
2564
+
2565
+ fn retry_max_delay_ms(&self) -> u64 {
2566
+ self.retry_max_delay_ms
2567
+ }
2568
+
2569
+ fn rate_limit_jitter_ratio(&self) -> f64 {
2570
+ self.rate_limit_jitter_ratio
2571
+ }
2572
+
2292
2573
  fn cookies_enabled(&self) -> bool {
2293
2574
  self.cookies_enabled
2294
2575
  }
@@ -2426,6 +2707,16 @@ impl CrawlConfig {
2426
2707
 
2427
2708
  exclude_paths: self.exclude_paths.clone(),
2428
2709
 
2710
+ path_patterns_match_query: self.path_patterns_match_query,
2711
+
2712
+ path_patterns_match_url: self.path_patterns_match_url,
2713
+
2714
+ dedup_include_query: self.dedup_include_query,
2715
+
2716
+ strip_tracking_params: self.strip_tracking_params,
2717
+
2718
+ tracking_params: self.tracking_params.clone(),
2719
+
2429
2720
  custom_headers: self
2430
2721
  .custom_headers
2431
2722
  .clone()
@@ -2443,6 +2734,12 @@ impl CrawlConfig {
2443
2734
 
2444
2735
  retry_codes: self.retry_codes.clone(),
2445
2736
 
2737
+ retry_initial_delay_ms: self.retry_initial_delay_ms,
2738
+
2739
+ retry_max_delay_ms: self.retry_max_delay_ms,
2740
+
2741
+ rate_limit_jitter_ratio: self.rate_limit_jitter_ratio,
2742
+
2446
2743
  cookies_enabled: self.cookies_enabled,
2447
2744
 
2448
2745
  auth: self.auth.clone().map(Into::into),
@@ -2619,7 +2916,7 @@ impl CrawlEngineHandle {
2619
2916
  }
2620
2917
  }
2621
2918
 
2622
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
2919
+ #[derive(Clone, Debug, serde::Serialize)]
2623
2920
  #[serde(default)]
2624
2921
  #[magnus::wrap(class = "Crawlberg::CrawlPageResult")]
2625
2922
  pub struct CrawlPageResult {
@@ -2644,6 +2941,11 @@ pub struct CrawlPageResult {
2644
2941
  extraction_meta: Option<ExtractionMeta>,
2645
2942
  downloaded_document: Option<DownloadedDocument>,
2646
2943
  browser_used: bool,
2944
+ final_url: String,
2945
+ redirect_count: usize,
2946
+ noindex_detected: bool,
2947
+ nofollow_detected: bool,
2948
+ ssrf_refused_urls: Vec<String>,
2647
2949
  }
2648
2950
 
2649
2951
  unsafe impl IntoValueFromNative for CrawlPageResult {}
@@ -2673,6 +2975,14 @@ impl magnus::TryConvert for CrawlPageResult {
2673
2975
  }
2674
2976
 
2675
2977
  unsafe impl TryConvertOwned for CrawlPageResult {}
2978
+ impl<'de> serde::Deserialize<'de> for CrawlPageResult {
2979
+ fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
2980
+ where
2981
+ D: serde::Deserializer<'de>,
2982
+ {
2983
+ <crawlberg::CrawlPageResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
2984
+ }
2985
+ }
2676
2986
 
2677
2987
  impl Default for CrawlPageResult {
2678
2988
  fn default() -> Self {
@@ -2879,6 +3189,51 @@ impl CrawlPageResult {
2879
3189
  })?,
2880
3190
  None => Default::default(),
2881
3191
  },
3192
+ final_url: match kwargs.get(ruby.to_symbol("final_url")) {
3193
+ Some(v) => String::try_convert(v).map_err(|e| {
3194
+ magnus::Error::new(
3195
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
3196
+ format!("invalid value for `final_url`: {}", e),
3197
+ )
3198
+ })?,
3199
+ None => Default::default(),
3200
+ },
3201
+ redirect_count: match kwargs.get(ruby.to_symbol("redirect_count")) {
3202
+ Some(v) => usize::try_convert(v).map_err(|e| {
3203
+ magnus::Error::new(
3204
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
3205
+ format!("invalid value for `redirect_count`: {}", e),
3206
+ )
3207
+ })?,
3208
+ None => Default::default(),
3209
+ },
3210
+ noindex_detected: match kwargs.get(ruby.to_symbol("noindex_detected")) {
3211
+ Some(v) => bool::try_convert(v).map_err(|e| {
3212
+ magnus::Error::new(
3213
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
3214
+ format!("invalid value for `noindex_detected`: {}", e),
3215
+ )
3216
+ })?,
3217
+ None => Default::default(),
3218
+ },
3219
+ nofollow_detected: match kwargs.get(ruby.to_symbol("nofollow_detected")) {
3220
+ Some(v) => bool::try_convert(v).map_err(|e| {
3221
+ magnus::Error::new(
3222
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
3223
+ format!("invalid value for `nofollow_detected`: {}", e),
3224
+ )
3225
+ })?,
3226
+ None => Default::default(),
3227
+ },
3228
+ ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
3229
+ Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
3230
+ magnus::Error::new(
3231
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
3232
+ format!("invalid value for `ssrf_refused_urls`: {}", e),
3233
+ )
3234
+ })?,
3235
+ None => Default::default(),
3236
+ },
2882
3237
  })
2883
3238
  }
2884
3239
 
@@ -2965,6 +3320,26 @@ impl CrawlPageResult {
2965
3320
  fn browser_used(&self) -> bool {
2966
3321
  self.browser_used
2967
3322
  }
3323
+
3324
+ fn final_url(&self) -> String {
3325
+ self.final_url.clone()
3326
+ }
3327
+
3328
+ fn redirect_count(&self) -> usize {
3329
+ self.redirect_count
3330
+ }
3331
+
3332
+ fn noindex_detected(&self) -> bool {
3333
+ self.noindex_detected
3334
+ }
3335
+
3336
+ fn nofollow_detected(&self) -> bool {
3337
+ self.nofollow_detected
3338
+ }
3339
+
3340
+ fn ssrf_refused_urls(&self) -> Vec<String> {
3341
+ self.ssrf_refused_urls.clone()
3342
+ }
2968
3343
  }
2969
3344
 
2970
3345
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -3360,7 +3735,7 @@ impl DownloadedAsset {
3360
3735
  }
3361
3736
  }
3362
3737
 
3363
- #[derive(Clone, Debug, serde::Serialize)]
3738
+ #[derive(Clone, serde::Serialize)]
3364
3739
  #[serde(default)]
3365
3740
  #[magnus::wrap(class = "Crawlberg::DownloadedDocument")]
3366
3741
  pub struct DownloadedDocument {
@@ -3402,6 +3777,21 @@ impl magnus::TryConvert for DownloadedDocument {
3402
3777
  }
3403
3778
 
3404
3779
  unsafe impl TryConvertOwned for DownloadedDocument {}
3780
+ impl std::fmt::Debug for DownloadedDocument {
3781
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3782
+ let mut debug = f.debug_struct("DownloadedDocument");
3783
+ debug.field("url", &self.url);
3784
+ debug.field("mime_type", &self.mime_type);
3785
+ debug.field("size", &self.size);
3786
+ debug.field("filename", &self.filename);
3787
+ debug.field("content_hash", &self.content_hash);
3788
+ debug.field("headers", &"<redacted>");
3789
+ debug.field("truncated", &self.truncated);
3790
+ debug.field("content_path", &self.content_path);
3791
+ debug.field("content_base64", &self.content_base64);
3792
+ debug.finish()
3793
+ }
3794
+ }
3405
3795
  impl<'de> serde::Deserialize<'de> for DownloadedDocument {
3406
3796
  fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
3407
3797
  where
@@ -4145,7 +4535,7 @@ impl ImageInfo {
4145
4535
  }
4146
4536
  }
4147
4537
 
4148
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
4538
+ #[derive(Clone, Debug, serde::Serialize)]
4149
4539
  #[serde(default)]
4150
4540
  #[magnus::wrap(class = "Crawlberg::InteractionResult")]
4151
4541
  pub struct InteractionResult {
@@ -4153,6 +4543,7 @@ pub struct InteractionResult {
4153
4543
  final_html: String,
4154
4544
  final_url: String,
4155
4545
  screenshot_base64: Option<String>,
4546
+ ssrf_refused_urls: Vec<String>,
4156
4547
  }
4157
4548
 
4158
4549
  unsafe impl IntoValueFromNative for InteractionResult {}
@@ -4182,6 +4573,14 @@ impl magnus::TryConvert for InteractionResult {
4182
4573
  }
4183
4574
 
4184
4575
  unsafe impl TryConvertOwned for InteractionResult {}
4576
+ impl<'de> serde::Deserialize<'de> for InteractionResult {
4577
+ fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
4578
+ where
4579
+ D: serde::Deserializer<'de>,
4580
+ {
4581
+ <crawlberg::InteractionResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
4582
+ }
4583
+ }
4185
4584
 
4186
4585
  impl Default for InteractionResult {
4187
4586
  fn default() -> Self {
@@ -4232,6 +4631,15 @@ impl InteractionResult {
4232
4631
  })?),
4233
4632
  None => None,
4234
4633
  },
4634
+ ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
4635
+ Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
4636
+ magnus::Error::new(
4637
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
4638
+ format!("invalid value for `ssrf_refused_urls`: {}", e),
4639
+ )
4640
+ })?,
4641
+ None => Default::default(),
4642
+ },
4235
4643
  })
4236
4644
  }
4237
4645
 
@@ -4250,6 +4658,10 @@ impl InteractionResult {
4250
4658
  fn screenshot_base64(&self) -> Option<String> {
4251
4659
  self.screenshot_base64.clone()
4252
4660
  }
4661
+
4662
+ fn ssrf_refused_urls(&self) -> Vec<String> {
4663
+ self.ssrf_refused_urls.clone()
4664
+ }
4253
4665
  }
4254
4666
 
4255
4667
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -5330,7 +5742,7 @@ impl PageMetadata {
5330
5742
  }
5331
5743
  }
5332
5744
 
5333
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
5745
+ #[derive(Clone, serde::Serialize, serde::Deserialize)]
5334
5746
  #[serde(default)]
5335
5747
  #[magnus::wrap(class = "Crawlberg::ProxyConfig")]
5336
5748
  pub struct ProxyConfig {
@@ -5366,6 +5778,15 @@ impl magnus::TryConvert for ProxyConfig {
5366
5778
  }
5367
5779
 
5368
5780
  unsafe impl TryConvertOwned for ProxyConfig {}
5781
+ impl std::fmt::Debug for ProxyConfig {
5782
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5783
+ let mut debug = f.debug_struct("ProxyConfig");
5784
+ debug.field("url", &"<redacted>");
5785
+ debug.field("username", &self.username);
5786
+ debug.field("password", &"<redacted>");
5787
+ debug.finish()
5788
+ }
5789
+ }
5369
5790
 
5370
5791
  impl Default for ProxyConfig {
5371
5792
  fn default() -> Self {
@@ -5572,7 +5993,7 @@ impl ResponseMeta {
5572
5993
  }
5573
5994
  }
5574
5995
 
5575
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
5996
+ #[derive(Clone, Debug, serde::Serialize)]
5576
5997
  #[serde(default)]
5577
5998
  #[magnus::wrap(class = "Crawlberg::ScrapeResult")]
5578
5999
  pub struct ScrapeResult {
@@ -5605,6 +6026,7 @@ pub struct ScrapeResult {
5605
6026
  screenshot_base64: Option<String>,
5606
6027
  downloaded_document: Option<DownloadedDocument>,
5607
6028
  browser: Option<BrowserExtras>,
6029
+ ssrf_refused_urls: Vec<String>,
5608
6030
  }
5609
6031
 
5610
6032
  unsafe impl IntoValueFromNative for ScrapeResult {}
@@ -5634,6 +6056,14 @@ impl magnus::TryConvert for ScrapeResult {
5634
6056
  }
5635
6057
 
5636
6058
  unsafe impl TryConvertOwned for ScrapeResult {}
6059
+ impl<'de> serde::Deserialize<'de> for ScrapeResult {
6060
+ fn deserialize<D>(deserializer: D) -> ::core::result::Result<Self, D::Error>
6061
+ where
6062
+ D: serde::Deserializer<'de>,
6063
+ {
6064
+ <crawlberg::ScrapeResult as serde::Deserialize>::deserialize(deserializer).map(Into::into)
6065
+ }
6066
+ }
5637
6067
 
5638
6068
  impl Default for ScrapeResult {
5639
6069
  fn default() -> Self {
@@ -5912,6 +6342,15 @@ impl ScrapeResult {
5912
6342
  })?),
5913
6343
  None => None,
5914
6344
  },
6345
+ ssrf_refused_urls: match kwargs.get(ruby.to_symbol("ssrf_refused_urls")) {
6346
+ Some(v) => <Vec<String>>::try_convert(v).map_err(|e| {
6347
+ magnus::Error::new(
6348
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
6349
+ format!("invalid value for `ssrf_refused_urls`: {}", e),
6350
+ )
6351
+ })?,
6352
+ None => Default::default(),
6353
+ },
5915
6354
  })
5916
6355
  }
5917
6356
 
@@ -6030,6 +6469,10 @@ impl ScrapeResult {
6030
6469
  fn browser(&self) -> Option<BrowserExtras> {
6031
6470
  self.browser.clone()
6032
6471
  }
6472
+
6473
+ fn ssrf_refused_urls(&self) -> Vec<String> {
6474
+ self.ssrf_refused_urls.clone()
6475
+ }
6033
6476
  }
6034
6477
 
6035
6478
  #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
@@ -6145,6 +6588,7 @@ impl SitemapUrl {
6145
6588
  pub struct SsrfPolicy {
6146
6589
  deny_private: bool,
6147
6590
  allowlist: Vec<HostMatcher>,
6591
+ denylist: Vec<HostMatcher>,
6148
6592
  max_redirects: u8,
6149
6593
  scheme_allowlist: Vec<String>,
6150
6594
  }
@@ -6216,6 +6660,15 @@ impl SsrfPolicy {
6216
6660
  })?,
6217
6661
  None => Default::default(),
6218
6662
  },
6663
+ denylist: match kwargs.get(ruby.to_symbol("denylist")) {
6664
+ Some(v) => <Vec<HostMatcher>>::try_convert(v).map_err(|e| {
6665
+ magnus::Error::new(
6666
+ unsafe { magnus::Ruby::get_unchecked() }.exception_type_error(),
6667
+ format!("invalid value for `denylist`: {}", e),
6668
+ )
6669
+ })?,
6670
+ None => Default::default(),
6671
+ },
6219
6672
  max_redirects: match kwargs.get(ruby.to_symbol("max_redirects")) {
6220
6673
  Some(v) => u8::try_convert(v).map_err(|e| {
6221
6674
  magnus::Error::new(
@@ -6245,6 +6698,10 @@ impl SsrfPolicy {
6245
6698
  self.allowlist.clone()
6246
6699
  }
6247
6700
 
6701
+ fn denylist(&self) -> Vec<HostMatcher> {
6702
+ self.denylist.clone()
6703
+ }
6704
+
6248
6705
  fn max_redirects(&self) -> u8 {
6249
6706
  self.max_redirects
6250
6707
  }
@@ -6328,7 +6785,7 @@ impl magnus::TryConvert for AssetCategory {
6328
6785
  unsafe impl IntoValueFromNative for AssetCategory {}
6329
6786
  unsafe impl TryConvertOwned for AssetCategory {}
6330
6787
 
6331
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
6788
+ #[derive(Clone, serde::Serialize, serde::Deserialize)]
6332
6789
  #[serde(tag = "type")]
6333
6790
  pub enum AuthConfig {
6334
6791
  #[serde(rename = "basic")]
@@ -6394,6 +6851,11 @@ unsafe impl IntoValueFromNative for AuthConfig {}
6394
6851
  unsafe impl TryConvertOwned for AuthConfig {}
6395
6852
 
6396
6853
  impl AuthConfig {}
6854
+ impl std::fmt::Debug for AuthConfig {
6855
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6856
+ f.write_str("AuthConfig(<redacted>)")
6857
+ }
6858
+ }
6397
6859
 
6398
6860
  #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
6399
6861
  #[serde(rename_all = "snake_case")]
@@ -6991,7 +7453,7 @@ impl magnus::TryConvert for LinkType {
6991
7453
  unsafe impl IntoValueFromNative for LinkType {}
6992
7454
  unsafe impl TryConvertOwned for LinkType {}
6993
7455
 
6994
- #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
7456
+ #[derive(Clone, serde::Serialize, serde::Deserialize)]
6995
7457
  #[serde(tag = "type")]
6996
7458
  #[serde(rename_all = "camelCase")]
6997
7459
  pub enum PageAction {
@@ -7077,6 +7539,11 @@ unsafe impl IntoValueFromNative for PageAction {}
7077
7539
  unsafe impl TryConvertOwned for PageAction {}
7078
7540
 
7079
7541
  impl PageAction {}
7542
+ impl std::fmt::Debug for PageAction {
7543
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7544
+ f.write_str("PageAction(<redacted>)")
7545
+ }
7546
+ }
7080
7547
 
7081
7548
  #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
7082
7549
  #[serde(rename_all = "camelCase")]
@@ -7522,6 +7989,8 @@ impl From<BrowserConfig> for crawlberg::BrowserConfig {
7522
7989
  backend: val.backend.into(),
7523
7990
  endpoint: val.endpoint,
7524
7991
  timeout: std::time::Duration::from_millis(val.timeout),
7992
+ overall_timeout: std::time::Duration::from_millis(val.overall_timeout),
7993
+ shutdown_timeout: std::time::Duration::from_millis(val.shutdown_timeout),
7525
7994
  wait: val.wait.into(),
7526
7995
  wait_selector: val.wait_selector,
7527
7996
  extra_wait: val.extra_wait.map(std::time::Duration::from_millis),
@@ -7531,6 +8000,8 @@ impl From<BrowserConfig> for crawlberg::BrowserConfig {
7531
8000
  robots_user_agent: val.robots_user_agent,
7532
8001
  capture_network_events: val.capture_network_events,
7533
8002
  session_affinity: val.session_affinity,
8003
+ chrome_path: val.chrome_path.map(Into::into),
8004
+ chrome_args: val.chrome_args.into_iter().collect(),
7534
8005
  ..Default::default()
7535
8006
  }
7536
8007
  }
@@ -7544,6 +8015,8 @@ impl From<crawlberg::BrowserConfig> for BrowserConfig {
7544
8015
  backend: val.backend.into(),
7545
8016
  endpoint: val.endpoint.map(|v| v.to_string()),
7546
8017
  timeout: val.timeout.as_millis() as u64,
8018
+ overall_timeout: val.overall_timeout.as_millis() as u64,
8019
+ shutdown_timeout: val.shutdown_timeout.as_millis() as u64,
7547
8020
  wait: val.wait.into(),
7548
8021
  wait_selector: val.wait_selector.map(|v| v.to_string()),
7549
8022
  extra_wait: val.extra_wait.map(|d| d.as_millis() as u64),
@@ -7553,6 +8026,8 @@ impl From<crawlberg::BrowserConfig> for BrowserConfig {
7553
8026
  robots_user_agent: val.robots_user_agent.map(|v| v.to_string()),
7554
8027
  capture_network_events: val.capture_network_events,
7555
8028
  session_affinity: val.session_affinity,
8029
+ chrome_path: val.chrome_path.map(|p| p.to_string_lossy().to_string()),
8030
+ chrome_args: val.chrome_args.into_iter().collect(),
7556
8031
  }
7557
8032
  }
7558
8033
  }
@@ -7641,6 +8116,7 @@ impl From<ContentConfig> for crawlberg::ContentConfig {
7641
8116
  wrap: val.wrap,
7642
8117
  wrap_width: val.wrap_width,
7643
8118
  include_document_structure: val.include_document_structure,
8119
+ extract_metadata: val.extract_metadata,
7644
8120
  ..Default::default()
7645
8121
  }
7646
8122
  }
@@ -7661,6 +8137,7 @@ impl From<crawlberg::ContentConfig> for ContentConfig {
7661
8137
  wrap: val.wrap,
7662
8138
  wrap_width: val.wrap_width,
7663
8139
  include_document_structure: val.include_document_structure,
8140
+ extract_metadata: val.extract_metadata,
7664
8141
  }
7665
8142
  }
7666
8143
  }
@@ -7710,6 +8187,11 @@ impl From<CrawlConfig> for crawlberg::CrawlConfig {
7710
8187
  allow_subdomains: val.allow_subdomains,
7711
8188
  include_paths: val.include_paths.into_iter().collect(),
7712
8189
  exclude_paths: val.exclude_paths.into_iter().collect(),
8190
+ path_patterns_match_query: val.path_patterns_match_query,
8191
+ path_patterns_match_url: val.path_patterns_match_url,
8192
+ dedup_include_query: val.dedup_include_query,
8193
+ strip_tracking_params: val.strip_tracking_params,
8194
+ tracking_params: val.tracking_params.into_iter().collect(),
7713
8195
  custom_headers: val
7714
8196
  .custom_headers
7715
8197
  .into_iter()
@@ -7720,6 +8202,9 @@ impl From<CrawlConfig> for crawlberg::CrawlConfig {
7720
8202
  max_redirects: val.max_redirects,
7721
8203
  retry_count: val.retry_count,
7722
8204
  retry_codes: val.retry_codes.into_iter().collect(),
8205
+ retry_initial_delay_ms: val.retry_initial_delay_ms,
8206
+ retry_max_delay_ms: val.retry_max_delay_ms,
8207
+ rate_limit_jitter_ratio: val.rate_limit_jitter_ratio,
7723
8208
  cookies_enabled: val.cookies_enabled,
7724
8209
  auth: val.auth.map(Into::into),
7725
8210
  max_body_size: val.max_body_size,
@@ -7770,6 +8255,11 @@ impl From<crawlberg::CrawlConfig> for CrawlConfig {
7770
8255
  allow_subdomains: val.allow_subdomains,
7771
8256
  include_paths: val.include_paths.into_iter().collect(),
7772
8257
  exclude_paths: val.exclude_paths.into_iter().collect(),
8258
+ path_patterns_match_query: val.path_patterns_match_query,
8259
+ path_patterns_match_url: val.path_patterns_match_url,
8260
+ dedup_include_query: val.dedup_include_query,
8261
+ strip_tracking_params: val.strip_tracking_params,
8262
+ tracking_params: val.tracking_params.into_iter().collect(),
7773
8263
  custom_headers: val
7774
8264
  .custom_headers
7775
8265
  .into_iter()
@@ -7780,6 +8270,9 @@ impl From<crawlberg::CrawlConfig> for CrawlConfig {
7780
8270
  max_redirects: val.max_redirects,
7781
8271
  retry_count: val.retry_count,
7782
8272
  retry_codes: val.retry_codes.into_iter().collect(),
8273
+ retry_initial_delay_ms: val.retry_initial_delay_ms,
8274
+ retry_max_delay_ms: val.retry_max_delay_ms,
8275
+ rate_limit_jitter_ratio: val.rate_limit_jitter_ratio,
7783
8276
  cookies_enabled: val.cookies_enabled,
7784
8277
  auth: val.auth.map(Into::into),
7785
8278
  max_body_size: val.max_body_size,
@@ -7836,6 +8329,11 @@ impl From<CrawlPageResult> for crawlberg::CrawlPageResult {
7836
8329
  extraction_meta: val.extraction_meta.map(Into::into),
7837
8330
  downloaded_document: val.downloaded_document.map(Into::into),
7838
8331
  browser_used: val.browser_used,
8332
+ final_url: val.final_url,
8333
+ redirect_count: val.redirect_count,
8334
+ noindex_detected: val.noindex_detected,
8335
+ nofollow_detected: val.nofollow_detected,
8336
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
7839
8337
  ..Default::default()
7840
8338
  }
7841
8339
  }
@@ -7866,6 +8364,11 @@ impl From<crawlberg::CrawlPageResult> for CrawlPageResult {
7866
8364
  extraction_meta: val.extraction_meta.map(Into::into),
7867
8365
  downloaded_document: val.downloaded_document.map(Into::into),
7868
8366
  browser_used: val.browser_used,
8367
+ final_url: val.final_url.to_string(),
8368
+ redirect_count: val.redirect_count,
8369
+ noindex_detected: val.noindex_detected,
8370
+ nofollow_detected: val.nofollow_detected,
8371
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
7869
8372
  }
7870
8373
  }
7871
8374
  }
@@ -8143,6 +8646,7 @@ impl From<InteractionResult> for crawlberg::InteractionResult {
8143
8646
  final_html: val.final_html,
8144
8647
  final_url: val.final_url,
8145
8648
  screenshot_base64: val.screenshot_base64,
8649
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
8146
8650
  ..Default::default()
8147
8651
  }
8148
8652
  }
@@ -8156,6 +8660,7 @@ impl From<crawlberg::InteractionResult> for InteractionResult {
8156
8660
  final_html: val.final_html.to_string(),
8157
8661
  final_url: val.final_url.to_string(),
8158
8662
  screenshot_base64: val.screenshot_base64.map(|v| v.to_string()),
8663
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
8159
8664
  }
8160
8665
  }
8161
8666
  }
@@ -8460,6 +8965,7 @@ impl From<ScrapeResult> for crawlberg::ScrapeResult {
8460
8965
  screenshot_base64: val.screenshot_base64,
8461
8966
  downloaded_document: val.downloaded_document.map(Into::into),
8462
8967
  browser: val.browser.map(Into::into),
8968
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
8463
8969
  ..Default::default()
8464
8970
  }
8465
8971
  }
@@ -8498,6 +9004,7 @@ impl From<crawlberg::ScrapeResult> for ScrapeResult {
8498
9004
  screenshot_base64: val.screenshot_base64.map(|v| v.to_string()),
8499
9005
  downloaded_document: val.downloaded_document.map(Into::into),
8500
9006
  browser: val.browser.map(Into::into),
9007
+ ssrf_refused_urls: val.ssrf_refused_urls.into_iter().collect(),
8501
9008
  }
8502
9009
  }
8503
9010
  }
@@ -8534,6 +9041,7 @@ impl From<SsrfPolicy> for crawlberg::SsrfPolicy {
8534
9041
  Self {
8535
9042
  deny_private: val.deny_private,
8536
9043
  allowlist: val.allowlist.into_iter().map(Into::into).collect(),
9044
+ denylist: val.denylist.into_iter().map(Into::into).collect(),
8537
9045
  max_redirects: val.max_redirects,
8538
9046
  scheme_allowlist: val.scheme_allowlist.into_iter().collect(),
8539
9047
  ..Default::default()
@@ -8547,6 +9055,7 @@ impl From<crawlberg::SsrfPolicy> for SsrfPolicy {
8547
9055
  Self {
8548
9056
  deny_private: val.deny_private,
8549
9057
  allowlist: val.allowlist.into_iter().map(Into::into).collect(),
9058
+ denylist: val.denylist.into_iter().map(Into::into).collect(),
8550
9059
  max_redirects: val.max_redirects,
8551
9060
  scheme_allowlist: val.scheme_allowlist.into_iter().collect(),
8552
9061
  }
@@ -9186,6 +9695,10 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9186
9695
 
9187
9696
  class.define_method("timeout", method!(BrowserConfig::timeout, 0))?;
9188
9697
 
9698
+ class.define_method("overall_timeout", method!(BrowserConfig::overall_timeout, 0))?;
9699
+
9700
+ class.define_method("shutdown_timeout", method!(BrowserConfig::shutdown_timeout, 0))?;
9701
+
9189
9702
  class.define_method("wait", method!(BrowserConfig::wait, 0))?;
9190
9703
 
9191
9704
  class.define_method("wait_selector", method!(BrowserConfig::wait_selector, 0))?;
@@ -9207,6 +9720,10 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9207
9720
 
9208
9721
  class.define_method("session_affinity", method!(BrowserConfig::session_affinity, 0))?;
9209
9722
 
9723
+ class.define_method("chrome_path", method!(BrowserConfig::chrome_path, 0))?;
9724
+
9725
+ class.define_method("chrome_args", method!(BrowserConfig::chrome_args, 0))?;
9726
+
9210
9727
  let class = module.define_class("BrowserExtras", ruby.class_object())?;
9211
9728
 
9212
9729
  class.define_singleton_method("new", function!(BrowserExtras::new, -1))?;
@@ -9268,6 +9785,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9268
9785
  method!(ContentConfig::include_document_structure, 0),
9269
9786
  )?;
9270
9787
 
9788
+ class.define_method("extract_metadata", method!(ContentConfig::extract_metadata, 0))?;
9789
+
9271
9790
  let class = module.define_class("CookieInfo", ruby.class_object())?;
9272
9791
 
9273
9792
  class.define_singleton_method("new", function!(CookieInfo::new, -1))?;
@@ -9314,6 +9833,22 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9314
9833
 
9315
9834
  class.define_method("exclude_paths", method!(CrawlConfig::exclude_paths, 0))?;
9316
9835
 
9836
+ class.define_method(
9837
+ "path_patterns_match_query",
9838
+ method!(CrawlConfig::path_patterns_match_query, 0),
9839
+ )?;
9840
+
9841
+ class.define_method(
9842
+ "path_patterns_match_url",
9843
+ method!(CrawlConfig::path_patterns_match_url, 0),
9844
+ )?;
9845
+
9846
+ class.define_method("dedup_include_query", method!(CrawlConfig::dedup_include_query, 0))?;
9847
+
9848
+ class.define_method("strip_tracking_params", method!(CrawlConfig::strip_tracking_params, 0))?;
9849
+
9850
+ class.define_method("tracking_params", method!(CrawlConfig::tracking_params, 0))?;
9851
+
9317
9852
  class.define_method("custom_headers", method!(CrawlConfig::custom_headers, 0))?;
9318
9853
 
9319
9854
  class.define_method("request_timeout", method!(CrawlConfig::request_timeout, 0))?;
@@ -9326,6 +9861,18 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9326
9861
 
9327
9862
  class.define_method("retry_codes", method!(CrawlConfig::retry_codes, 0))?;
9328
9863
 
9864
+ class.define_method(
9865
+ "retry_initial_delay_ms",
9866
+ method!(CrawlConfig::retry_initial_delay_ms, 0),
9867
+ )?;
9868
+
9869
+ class.define_method("retry_max_delay_ms", method!(CrawlConfig::retry_max_delay_ms, 0))?;
9870
+
9871
+ class.define_method(
9872
+ "rate_limit_jitter_ratio",
9873
+ method!(CrawlConfig::rate_limit_jitter_ratio, 0),
9874
+ )?;
9875
+
9329
9876
  class.define_method("cookies_enabled", method!(CrawlConfig::cookies_enabled, 0))?;
9330
9877
 
9331
9878
  class.define_method("auth", method!(CrawlConfig::auth, 0))?;
@@ -9437,6 +9984,16 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9437
9984
 
9438
9985
  class.define_method("browser_used", method!(CrawlPageResult::browser_used, 0))?;
9439
9986
 
9987
+ class.define_method("final_url", method!(CrawlPageResult::final_url, 0))?;
9988
+
9989
+ class.define_method("redirect_count", method!(CrawlPageResult::redirect_count, 0))?;
9990
+
9991
+ class.define_method("noindex_detected", method!(CrawlPageResult::noindex_detected, 0))?;
9992
+
9993
+ class.define_method("nofollow_detected", method!(CrawlPageResult::nofollow_detected, 0))?;
9994
+
9995
+ class.define_method("ssrf_refused_urls", method!(CrawlPageResult::ssrf_refused_urls, 0))?;
9996
+
9440
9997
  let class = module.define_class("CrawlResult", ruby.class_object())?;
9441
9998
 
9442
9999
  class.define_singleton_method("new", function!(CrawlResult::new, -1))?;
@@ -9586,6 +10143,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9586
10143
 
9587
10144
  class.define_method("screenshot_base64", method!(InteractionResult::screenshot_base64, 0))?;
9588
10145
 
10146
+ class.define_method("ssrf_refused_urls", method!(InteractionResult::ssrf_refused_urls, 0))?;
10147
+
9589
10148
  let class = module.define_class("JsonLdEntry", ruby.class_object())?;
9590
10149
 
9591
10150
  class.define_singleton_method("new", function!(JsonLdEntry::new, -1))?;
@@ -9814,6 +10373,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9814
10373
 
9815
10374
  class.define_method("browser", method!(ScrapeResult::browser, 0))?;
9816
10375
 
10376
+ class.define_method("ssrf_refused_urls", method!(ScrapeResult::ssrf_refused_urls, 0))?;
10377
+
9817
10378
  let class = module.define_class("SitemapUrl", ruby.class_object())?;
9818
10379
 
9819
10380
  class.define_singleton_method("new", function!(SitemapUrl::new, -1))?;
@@ -9834,6 +10395,8 @@ fn ruby_init(ruby: &Ruby) -> Result<(), Error> {
9834
10395
 
9835
10396
  class.define_method("allowlist", method!(SsrfPolicy::allowlist, 0))?;
9836
10397
 
10398
+ class.define_method("denylist", method!(SsrfPolicy::denylist, 0))?;
10399
+
9837
10400
  class.define_method("max_redirects", method!(SsrfPolicy::max_redirects, 0))?;
9838
10401
 
9839
10402
  class.define_method("scheme_allowlist", method!(SsrfPolicy::scheme_allowlist, 0))?;