فهرست منبع

add extension

lescuer97 1 روز پیش
والد
کامیت
588edcfd49

+ 2 - 0
Cargo.lock

@@ -1209,6 +1209,7 @@ dependencies = [
  "cbor-diag",
  "cdk-common",
  "cdk-fake-wallet",
+ "cdk-http-client",
  "cdk-npubcash",
  "cdk-prometheus",
  "cdk-signatory",
@@ -1280,6 +1281,7 @@ dependencies = [
  "bitcoin 0.32.8",
  "cdk",
  "cdk-common",
+ "cdk-http-client",
  "cdk-redb",
  "cdk-sqlite",
  "clap",

+ 1 - 0
crates/cdk-cli/Cargo.toml

@@ -26,6 +26,7 @@ cdk = { workspace = true, default-features = false, features = ["wallet", "nostr
 cdk-redb = { workspace = true, features = ["wallet"], optional = true }
 cdk-sqlite = { workspace = true, features = ["wallet"] }
 cdk-common = { workspace = true, features = ["wallet", "http"] }
+cdk-http-client = { workspace = true }
 clap.workspace = true
 serde.workspace = true
 serde_json.workspace = true

+ 1 - 0
crates/cdk-cli/src/sub_commands/cat_device_login.rs

@@ -6,6 +6,7 @@ use cdk::mint_url::MintUrl;
 use cdk::nuts::MintInfo;
 use cdk::wallet::WalletRepository;
 use cdk::OidcClient;
+use cdk_http_client::RequestBuilderExt;
 use clap::Args;
 use serde::{Deserialize, Serialize};
 use tokio::time::sleep;

+ 1 - 0
crates/cdk-cli/src/sub_commands/mint_blind_auth.rs

@@ -5,6 +5,7 @@ use cdk::mint_url::MintUrl;
 use cdk::nuts::{CurrencyUnit, MintInfo};
 use cdk::wallet::WalletRepository;
 use cdk::{Amount, OidcClient};
+use cdk_http_client::RequestBuilderExt;
 use clap::Args;
 use serde::{Deserialize, Serialize};
 

+ 10 - 7
crates/cdk-http-client/Cargo.toml

@@ -10,19 +10,22 @@ rust-version.workspace = true
 license.workspace = true
 readme = "README.md"
 
+[features]
+default = ["bitreq"]
+reqwest = ["dep:reqwest"]
+bitreq = ["dep:bitreq", "dep:serde_urlencoded", "dep:regex"]
+
 [dependencies]
 serde.workspace = true
 serde_json.workspace = true
 thiserror.workspace = true
 url.workspace = true
 
-[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-bitreq = { version = "0.3.1", features = ["async", "async-https-rustls", "json-using-serde", "proxy"] }
-serde_urlencoded = "0.7"
-regex = { workspace = true }
-
-[target.'cfg(target_arch = "wasm32")'.dependencies]
-reqwest = { version = "0.12", default-features = false, features = ["json"] }
+# Optional dependencies
+reqwest = { version = "0.12", default-features = false, features = ["json"], optional = true }
+bitreq = { version = "0.3.1", features = ["async", "async-https-rustls", "json-using-serde", "proxy"], optional = true }
+serde_urlencoded = { version = "0.7", optional = true }
+regex = { workspace = true, optional = true }
 
 [dev-dependencies]
 tokio = { workspace = true, features = ["rt", "macros"] }

+ 81 - 0
crates/cdk-http-client/src/backends/bitreq_backend.rs

@@ -0,0 +1,81 @@
+//! bitreq-based RequestBuilder implementation
+
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+
+use crate::error::HttpError;
+use crate::request_builder_ext::RequestBuilderExt;
+use crate::response::{RawResponse, Response};
+
+/// bitreq-based RequestBuilder wrapper
+#[derive(Debug)]
+pub struct BitreqRequestBuilder {
+    inner: bitreq::Request,
+    error: Option<HttpError>,
+}
+
+impl BitreqRequestBuilder {
+    /// Create a new BitreqRequestBuilder from a bitreq::Request
+    pub(crate) fn new(inner: bitreq::Request) -> Self {
+        Self {
+            inner,
+            error: None,
+        }
+    }
+}
+
+impl RequestBuilderExt for BitreqRequestBuilder {
+    fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
+        Self {
+            inner: self.inner.with_header(key.as_ref(), value.as_ref()),
+            error: None,
+        }
+    }
+
+    fn json<T: Serialize>(mut self, body: &T) -> Self {
+        match self.inner.clone().with_json(body) {
+            Ok(req) => {
+                self.inner = req;
+                self.error = None;
+            }
+            Err(e) => self.error = Some(HttpError::from(e)),
+        }
+        self
+    }
+
+    fn form<T: Serialize>(mut self, body: &T) -> Self {
+        match serde_urlencoded::to_string(body) {
+            Ok(form_str) => {
+                self.inner = self.inner.with_body(form_str.into_bytes());
+            }
+            Err(e) => self.error = Some(HttpError::Serialization(e.to_string())),
+        }
+        self
+    }
+
+    async fn send(self) -> Response<RawResponse> {
+        if let Some(err) = self.error {
+            return Err(err);
+        }
+        let response = self.inner.send_async().await.map_err(HttpError::from)?;
+        Ok(RawResponse::new(response))
+    }
+
+    async fn send_json<R: DeserializeOwned>(self) -> Response<R> {
+        if let Some(err) = self.error {
+            return Err(err);
+        }
+        let response = self.inner.send_async().await.map_err(HttpError::from)?;
+        let status = response.status_code;
+
+        if !(200..300).contains(&status) {
+            let message = response.as_str().unwrap_or("").to_string();
+            return Err(HttpError::Status {
+                status: status as u16,
+                message,
+            });
+        }
+
+        response.json().map_err(HttpError::from)
+    }
+}

+ 13 - 0
crates/cdk-http-client/src/backends/mod.rs

@@ -0,0 +1,13 @@
+//! HTTP request builder backends
+
+#[cfg(feature = "bitreq")]
+pub mod bitreq_backend;
+
+#[cfg(feature = "reqwest")]
+pub mod reqwest_backend;
+
+#[cfg(feature = "bitreq")]
+pub use bitreq_backend::BitreqRequestBuilder;
+
+#[cfg(feature = "reqwest")]
+pub use reqwest_backend::ReqwestRequestBuilder;

+ 61 - 0
crates/cdk-http-client/src/backends/reqwest_backend.rs

@@ -0,0 +1,61 @@
+//! reqwest-based RequestBuilder implementation
+
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+
+use crate::error::HttpError;
+use crate::request_builder_ext::RequestBuilderExt;
+use crate::response::{RawResponse, Response};
+
+/// reqwest-based RequestBuilder wrapper
+#[derive(Debug)]
+pub struct ReqwestRequestBuilder {
+    inner: reqwest::RequestBuilder,
+}
+
+impl ReqwestRequestBuilder {
+    /// Create a new ReqwestRequestBuilder from a reqwest::RequestBuilder
+    pub(crate) fn new(inner: reqwest::RequestBuilder) -> Self {
+        Self { inner }
+    }
+}
+
+impl RequestBuilderExt for ReqwestRequestBuilder {
+    fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
+        Self {
+            inner: self.inner.header(key.as_ref(), value.as_ref()),
+        }
+    }
+
+    fn json<T: Serialize>(self, body: &T) -> Self {
+        Self {
+            inner: self.inner.json(body),
+        }
+    }
+
+    fn form<T: Serialize>(self, body: &T) -> Self {
+        Self {
+            inner: self.inner.form(body),
+        }
+    }
+
+    async fn send(self) -> Response<RawResponse> {
+        let response = self.inner.send().await.map_err(HttpError::from)?;
+        Ok(RawResponse::new(response))
+    }
+
+    async fn send_json<R: DeserializeOwned>(self) -> Response<R> {
+        let response = self.inner.send().await.map_err(HttpError::from)?;
+        let status = response.status();
+
+        if !status.is_success() {
+            let message = response.text().await.unwrap_or_default();
+            return Err(HttpError::Status {
+                status: status.as_u16(),
+                message,
+            });
+        }
+
+        response.json().await.map_err(HttpError::from)
+    }
+}

+ 27 - 34
crates/cdk-http-client/src/client.rs

@@ -3,7 +3,7 @@
 use serde::de::DeserializeOwned;
 use serde::Serialize;
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(feature = "bitreq")]
 use bitreq::RequestExt;
 
 use crate::error::HttpError;
@@ -13,11 +13,11 @@ use crate::response::{RawResponse, Response};
 /// HTTP client wrapper
 #[derive(Clone)]
 pub struct HttpClient {
-    #[cfg(target_arch = "wasm32")]
+    #[cfg(feature = "reqwest")]
     inner: reqwest::Client,
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(feature = "bitreq")]
     inner: bitreq::Client,
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(feature = "bitreq")]
     proxy_config: Option<ProxyConfig>,
 }
 
@@ -27,14 +27,7 @@ impl std::fmt::Debug for HttpClient {
     }
 }
 
-// #[cfg(not(target_arch = "wasm32"))]
-// impl std::fmt::Debug for HttpClient {
-//     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-//         f.debug_struct("HttpClient").finish()
-//     }
-// }
-
-#[cfg(target_arch = "wasm32")]
+#[cfg(feature = "reqwest")]
 impl HttpClient {
     /// Create a new HTTP client with default settings
     pub fn new() -> Self {
@@ -55,7 +48,7 @@ impl HttpClient {
 
     /// GET request, returns JSON deserialized to R
     pub async fn fetch<R: DeserializeOwned>(&self, url: &str) -> Response<R> {
-        let response = self.inner.get(url).send().await?;
+        let response = self.inner.get(url).send().await.map_err(HttpError::from)?;
         let status = response.status();
 
         if !status.is_success() {
@@ -75,7 +68,7 @@ impl HttpClient {
         url: &str,
         body: &B,
     ) -> Response<R> {
-        let response = self.inner.post(url).json(body).send().await?;
+        let response = self.inner.post(url).json(body).send().await.map_err(HttpError::from)?;
         let status = response.status();
 
         if !status.is_success() {
@@ -95,7 +88,7 @@ impl HttpClient {
         url: &str,
         form: &F,
     ) -> Response<R> {
-        let response = self.inner.post(url).form(form).send().await?;
+        let response = self.inner.post(url).form(form).send().await.map_err(HttpError::from)?;
         let status = response.status();
 
         if !status.is_success() {
@@ -115,7 +108,7 @@ impl HttpClient {
         url: &str,
         body: &B,
     ) -> Response<R> {
-        let response = self.inner.patch(url).json(body).send().await?;
+        let response = self.inner.patch(url).json(body).send().await.map_err(HttpError::from)?;
         let status = response.status();
 
         if !status.is_success() {
@@ -131,7 +124,7 @@ impl HttpClient {
 
     /// GET request returning raw response body
     pub async fn get_raw(&self, url: &str) -> Response<RawResponse> {
-        let response = self.inner.get(url).send().await?;
+        let response = self.inner.get(url).send().await.map_err(HttpError::from)?;
         Ok(RawResponse::new(response))
     }
 
@@ -151,7 +144,7 @@ impl HttpClient {
     }
 }
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(feature = "bitreq")]
 impl HttpClient {
     /// Create a new HTTP client with default settings
     pub fn new() -> Self {
@@ -314,13 +307,13 @@ impl Default for HttpClient {
 /// HTTP client builder for configuring proxy and TLS settings
 #[derive(Debug, Default)]
 pub struct HttpClientBuilder {
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(feature = "bitreq")]
     accept_invalid_certs: bool,
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(feature = "bitreq")]
     proxy: Option<ProxyConfig>,
 }
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(feature = "bitreq")]
 #[derive(Debug, Clone)]
 struct ProxyConfig {
     url: url::Url,
@@ -328,22 +321,22 @@ struct ProxyConfig {
 }
 
 impl HttpClientBuilder {
-    /// Accept invalid TLS certificates (non-WASM only)
-    #[cfg(not(target_arch = "wasm32"))]
+    /// Accept invalid TLS certificates (bitreq only)
+    #[cfg(feature = "bitreq")]
     pub fn danger_accept_invalid_certs(mut self, accept: bool) -> Self {
         self.accept_invalid_certs = accept;
         self
     }
 
-    /// Set a proxy URL (non-WASM only)
-    #[cfg(not(target_arch = "wasm32"))]
+    /// Set a proxy URL (bitreq only)
+    #[cfg(feature = "bitreq")]
     pub fn proxy(mut self, url: url::Url) -> Self {
         self.proxy = Some(ProxyConfig { url, matcher: None });
         self
     }
 
-    /// Set a proxy URL with a host pattern matcher (non-WASM only)
-    #[cfg(not(target_arch = "wasm32"))]
+    /// Set a proxy URL with a host pattern matcher (bitreq only)
+    #[cfg(feature = "bitreq")]
     pub fn proxy_with_matcher(mut self, url: url::Url, pattern: &str) -> Response<Self> {
         let matcher = regex::Regex::new(pattern)
             .map_err(|e| HttpError::Proxy(format!("Invalid proxy pattern: {}", e)))?;
@@ -356,19 +349,19 @@ impl HttpClientBuilder {
 
     /// Build the HTTP client
     pub fn build(self) -> Response<HttpClient> {
-        #[cfg(target_arch = "wasm32")]
+        #[cfg(feature = "reqwest")]
         {
             Ok(HttpClient {
                 inner: reqwest::Client::new(),
             })
         }
 
-        #[cfg(not(target_arch = "wasm32"))]
+        #[cfg(feature = "bitreq")]
         {
-            // Return error if danger_accept_invalid_certs was set on non-wasm32
+            // Return error if danger_accept_invalid_certs was set
             if self.accept_invalid_certs {
                 return Err(HttpError::Build(
-                    "danger_accept_invalid_certs is not supported on non-WASM targets".to_string(),
+                    "danger_accept_invalid_certs is not supported".to_string(),
                 ));
             }
 
@@ -415,7 +408,7 @@ mod tests {
         assert!(result.is_ok());
     }
 
-    #[cfg(target_arch = "wasm32")]
+    #[cfg(feature = "reqwest")]
     #[test]
     fn test_from_reqwest() {
         let reqwest_client = reqwest::Client::new();
@@ -423,8 +416,8 @@ mod tests {
         let _ = format!("{:?}", client);
     }
 
-    #[cfg(not(target_arch = "wasm32"))]
-    mod non_wasm {
+    #[cfg(feature = "bitreq")]
+    mod bitreq_tests {
         use super::*;
 
         #[test]

+ 2 - 2
crates/cdk-http-client/src/error.rs

@@ -33,7 +33,7 @@ pub enum HttpError {
     Other(String),
 }
 
-#[cfg(target_arch = "wasm32")]
+#[cfg(feature = "reqwest")]
 impl From<reqwest::Error> for HttpError {
     fn from(err: reqwest::Error) -> Self {
         if err.is_timeout() {
@@ -51,7 +51,7 @@ impl From<reqwest::Error> for HttpError {
     }
 }
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(feature = "bitreq")]
 impl From<bitreq::Error> for HttpError {
     fn from(err: bitreq::Error) -> Self {
         use bitreq::Error;

+ 9 - 1
crates/cdk-http-client/src/lib.rs

@@ -20,12 +20,20 @@
 //! }
 //! ```
 
+mod backends;
 mod client;
 mod error;
 mod request;
+mod request_builder_ext;
 mod response;
 
+#[cfg(feature = "bitreq")]
+pub use backends::BitreqRequestBuilder;
+
+#[cfg(feature = "reqwest")]
+pub use backends::ReqwestRequestBuilder;
+
 pub use client::{fetch, HttpClient, HttpClientBuilder};
 pub use error::HttpError;
-pub use request::RequestBuilder;
+pub use request::{RequestBuilder, RequestBuilderExt};
 pub use response::{RawResponse, Response};

+ 9 - 135
crates/cdk-http-client/src/request.rs

@@ -1,139 +1,13 @@
 //! HTTP request builder
 
-use serde::de::DeserializeOwned;
-use serde::Serialize;
-
-use crate::error::HttpError;
-use crate::response::{RawResponse, Response};
+pub use crate::request_builder_ext::RequestBuilderExt;
 
 /// HTTP request builder for complex requests
-#[derive(Debug)]
-pub struct RequestBuilder {
-    #[cfg(target_arch = "wasm32")]
-    inner: reqwest::RequestBuilder,
-    #[cfg(not(target_arch = "wasm32"))]
-    inner: bitreq::Request,
-    #[cfg(not(target_arch = "wasm32"))]
-    error: Option<HttpError>,
-}
-
-#[cfg(target_arch = "wasm32")]
-impl RequestBuilder {
-    /// Create a new RequestBuilder from a reqwest::RequestBuilder
-    pub(crate) fn new(inner: reqwest::RequestBuilder) -> Self {
-        Self { inner }
-    }
-
-    /// Add a header to the request
-    pub fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
-        Self {
-            inner: self.inner.header(key.as_ref(), value.as_ref()),
-        }
-    }
-
-    /// Set the request body as JSON
-    pub fn json<T: Serialize>(self, body: &T) -> Self {
-        Self {
-            inner: self.inner.json(body),
-        }
-    }
-
-    /// Set the request body as form data
-    pub fn form<T: Serialize>(self, body: &T) -> Self {
-        Self {
-            inner: self.inner.form(body),
-        }
-    }
-
-    /// Send the request and return a raw response
-    pub async fn send(self) -> Response<RawResponse> {
-        let response = self.inner.send().await?;
-        Ok(RawResponse::new(response))
-    }
-
-    /// Send the request and deserialize the response as JSON
-    pub async fn send_json<R: DeserializeOwned>(self) -> Response<R> {
-        let response = self.inner.send().await?;
-        let status = response.status();
-
-        if !status.is_success() {
-            let message = response.text().await.unwrap_or_default();
-            return Err(HttpError::Status {
-                status: status.as_u16(),
-                message,
-            });
-        }
-
-        response.json().await.map_err(HttpError::from)
-    }
-}
-
-#[cfg(not(target_arch = "wasm32"))]
-impl RequestBuilder {
-    /// Create a new RequestBuilder from a bitreq::Request
-    pub(crate) fn new(inner: bitreq::Request) -> Self {
-        Self {
-            inner: inner,
-            error: None,
-        }
-    }
-
-    /// Add a header to the request
-    pub fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
-        Self {
-            inner: self.inner.with_header(key.as_ref(), value.as_ref()),
-            error: None,
-        }
-    }
-
-    /// Set the request body as JSON
-    pub fn json<T: Serialize>(mut self, body: &T) -> Self {
-        match self.inner.clone().with_json(body) {
-            Ok(req) => {
-                self.inner = req;
-                self.error = None;
-            }
-            Err(e) => self.error = Some(HttpError::from(e)),
-        }
-        self
-    }
-
-    /// Set the request body as form data
-    pub fn form<T: Serialize>(mut self, body: &T) -> Self {
-        match serde_urlencoded::to_string(body) {
-            Ok(form_str) => {
-                self.inner = self.inner.with_body(form_str.into_bytes());
-            }
-            Err(e) => self.error = Some(HttpError::Serialization(e.to_string())),
-        }
-        self
-    }
-
-    /// Send the request and return a raw response
-    pub async fn send(self) -> Response<RawResponse> {
-        if let Some(err) = self.error {
-            return Err(err);
-        }
-        let response = self.inner.send_async().await.map_err(HttpError::from)?;
-        Ok(RawResponse::new(response))
-    }
-
-    /// Send the request and deserialize the response as JSON
-    pub async fn send_json<R: DeserializeOwned>(self) -> Response<R> {
-        if let Some(err) = self.error {
-            return Err(err);
-        }
-        let response = self.inner.send_async().await.map_err(HttpError::from)?;
-        let status = response.status_code;
-
-        if !(200..300).contains(&status) {
-            let message = response.as_str().unwrap_or("").to_string();
-            return Err(HttpError::Status {
-                status: status as u16,
-                message,
-            });
-        }
-
-        response.json().map_err(HttpError::from)
-    }
-}
+///
+/// This is a type alias that resolves to either `BitreqRequestBuilder` or
+/// `ReqwestRequestBuilder` depending on the enabled feature.
+#[cfg(feature = "bitreq")]
+pub use crate::backends::BitreqRequestBuilder as RequestBuilder;
+
+#[cfg(feature = "reqwest")]
+pub use crate::backends::ReqwestRequestBuilder as RequestBuilder;

+ 49 - 0
crates/cdk-http-client/src/request_builder_ext.rs

@@ -0,0 +1,49 @@
+//! HTTP RequestBuilder extension trait
+
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+
+use crate::response::{RawResponse, Response};
+
+/// Trait for building and sending HTTP requests
+///
+/// This trait abstracts over different HTTP client backends (bitreq, reqwest)
+/// and provides a unified interface for building and sending HTTP requests.
+pub trait RequestBuilderExt: Sized + Send {
+    /// Add a header to the request
+    fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self;
+
+    /// Set the request body as JSON
+    fn json<T: Serialize>(self, body: &T) -> Self;
+
+    /// Set the request body as form data
+    fn form<T: Serialize>(self, body: &T) -> Self;
+
+    /// Send the request and return a raw response
+    async fn send(self) -> Response<RawResponse>;
+
+    /// Send the request and deserialize the response as JSON
+    async fn send_json<R: DeserializeOwned>(self) -> Response<R>;
+}
+
+impl<T: RequestBuilderExt> RequestBuilderExt for Box<T> {
+    fn header(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
+        Box::new((*self).header(key, value))
+    }
+
+    fn json<B: Serialize>(self, body: &B) -> Self {
+        Box::new((*self).json(body))
+    }
+
+    fn form<F: Serialize>(self, body: &F) -> Self {
+        Box::new((*self).form(body))
+    }
+
+    async fn send(self) -> Response<RawResponse> {
+        (*self).send().await
+    }
+
+    async fn send_json<R: DeserializeOwned>(self) -> Response<R> {
+        (*self).send_json().await
+    }
+}

+ 4 - 4
crates/cdk-http-client/src/response.rs

@@ -12,13 +12,13 @@ pub type Response<R, E = HttpError> = Result<R, E>;
 #[derive(Debug)]
 pub struct RawResponse {
     status: u16,
-    #[cfg(target_arch = "wasm32")]
+    #[cfg(feature = "reqwest")]
     inner: reqwest::Response,
-    #[cfg(not(target_arch = "wasm32"))]
+    #[cfg(feature = "bitreq")]
     inner: bitreq::Response,
 }
 
-#[cfg(target_arch = "wasm32")]
+#[cfg(feature = "reqwest")]
 impl RawResponse {
     /// Create a new RawResponse from a reqwest::Response
     pub(crate) fn new(response: reqwest::Response) -> Self {
@@ -68,7 +68,7 @@ impl RawResponse {
     }
 }
 
-#[cfg(not(target_arch = "wasm32"))]
+#[cfg(feature = "bitreq")]
 impl RawResponse {
     /// Create a new RawResponse from a bitreq::Response
     pub(crate) fn new(response: bitreq::Response) -> Self {

+ 1 - 0
crates/cdk-npubcash/src/auth.rs

@@ -6,6 +6,7 @@ use std::sync::Arc;
 use std::time::{Duration, SystemTime};
 
 use base64::Engine;
+use cdk_http_client::RequestBuilderExt;
 use nostr_sdk::{EventBuilder, Keys, Kind, Tag};
 use tokio::sync::RwLock;
 

+ 1 - 0
crates/cdk-npubcash/src/client.rs

@@ -3,6 +3,7 @@
 use std::sync::Arc;
 
 use cdk_http_client::{HttpClient, RawResponse};
+use cdk_http_client::RequestBuilderExt;
 use tracing::instrument;
 
 use crate::auth::JwtAuthProvider;

+ 1 - 0
crates/cdk/Cargo.toml

@@ -37,6 +37,7 @@ prometheus = ["dep:cdk-prometheus"]
 [dependencies]
 arc-swap = "1.7.1"
 cdk-common.workspace = true
+cdk-http-client.workspace = true
 cbor-diag.workspace = true
 async-trait.workspace = true
 anyhow.workspace = true

+ 1 - 0
crates/cdk/src/wallet/mint_connector/transport.rs

@@ -2,6 +2,7 @@
 use std::fmt::Debug;
 
 use cdk_common::{AuthToken, HttpClient, HttpClientBuilder};
+use cdk_http_client::RequestBuilderExt;
 #[cfg(all(feature = "bip353", not(target_arch = "wasm32")))]
 use hickory_resolver::config::ResolverConfig;
 #[cfg(all(feature = "bip353", not(target_arch = "wasm32")))]

+ 1 - 0
crates/cdk/src/wallet/payment_request.rs

@@ -10,6 +10,7 @@ use std::sync::Arc;
 use anyhow::Result;
 use bitcoin::hashes::sha256::Hash as Sha256Hash;
 use cdk_common::{Amount, HttpClient, PaymentRequest, PaymentRequestPayload, TransportType};
+use cdk_http_client::RequestBuilderExt;
 #[cfg(feature = "nostr")]
 use nostr_sdk::nips::nip19::Nip19Profile;
 #[cfg(feature = "nostr")]