Skip to main content

hot_dev/
client.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use reqwest::{Method, RequestBuilder, Response};
5use serde_json::Value;
6
7use crate::resources::{
8    BuildsResource, ContextResource, DomainsResource, EnvResource, EventsResource, FilesResource,
9    OrgResource, ProjectsResource, RunsResource, ServiceKeysResource, SessionsResource,
10    StreamsResource,
11};
12use crate::transport::{Transport, DEFAULT_BASE_URL};
13use crate::{JsonObject, Result};
14
15/// Hot API v1 client. Construct it with [`HotClient::builder`]; the resource
16/// accessors mirror the Hot API resources.
17#[derive(Clone)]
18pub struct HotClient {
19    transport: Arc<Transport>,
20}
21
22/// Builder for [`HotClient`].
23pub struct HotClientBuilder {
24    token: String,
25    base_url: String,
26    timeout: Option<Duration>,
27    client: Option<reqwest::Client>,
28}
29
30impl HotClient {
31    /// Returns a client with default configuration.
32    pub fn new(token: impl Into<String>) -> HotClient {
33        HotClient::builder(token).build()
34    }
35
36    /// Returns a builder using the given Hot API key, session token, or
37    /// service key.
38    pub fn builder(token: impl Into<String>) -> HotClientBuilder {
39        HotClientBuilder {
40            token: token.into(),
41            base_url: DEFAULT_BASE_URL.to_string(),
42            timeout: None,
43            client: None,
44        }
45    }
46
47    /// The configured base URL without the /v1 suffix.
48    pub fn base_url(&self) -> &str {
49        self.transport.base_url()
50    }
51
52    pub fn builds(&self) -> BuildsResource {
53        BuildsResource::new(self.transport.clone())
54    }
55
56    pub fn context(&self) -> ContextResource {
57        ContextResource::new(self.transport.clone())
58    }
59
60    pub fn domains(&self) -> DomainsResource {
61        DomainsResource::new(self.transport.clone())
62    }
63
64    pub fn env(&self) -> EnvResource {
65        EnvResource::new(self.transport.clone())
66    }
67
68    pub fn events(&self) -> EventsResource {
69        EventsResource::new(self.transport.clone())
70    }
71
72    pub fn files(&self) -> FilesResource {
73        FilesResource::new(self.transport.clone())
74    }
75
76    pub fn org(&self) -> OrgResource {
77        OrgResource::new(self.transport.clone())
78    }
79
80    pub fn projects(&self) -> ProjectsResource {
81        ProjectsResource::new(self.transport.clone())
82    }
83
84    pub fn runs(&self) -> RunsResource {
85        RunsResource::new(self.transport.clone())
86    }
87
88    pub fn service_keys(&self) -> ServiceKeysResource {
89        ServiceKeysResource::new(self.transport.clone())
90    }
91
92    pub fn sessions(&self) -> SessionsResource {
93        SessionsResource::new(self.transport.clone())
94    }
95
96    pub fn streams(&self) -> StreamsResource {
97        StreamsResource::new(self.transport.clone())
98    }
99
100    /// Calls a JSON API endpoint that does not yet have a resource helper.
101    /// `path` is relative to /v1 and the returned object is the response
102    /// envelope.
103    pub async fn request(
104        &self,
105        method: Method,
106        path: &str,
107        body: Option<&Value>,
108        query: &[(&str, &str)],
109    ) -> Result<JsonObject> {
110        self.transport.request_json(method, path, body, query).await
111    }
112
113    /// Returns an authorized [`RequestBuilder`] for a path relative to /v1,
114    /// for endpoints needing full control (raw bodies, custom headers).
115    /// Send it with [`HotClient::execute`] to get API error mapping.
116    pub fn request_builder(&self, method: Method, path: &str) -> RequestBuilder {
117        self.transport.request_builder(method, path)
118    }
119
120    /// Sends a request built with [`HotClient::request_builder`], mapping
121    /// non-2xx responses to [`crate::ApiError`].
122    pub async fn execute(&self, builder: RequestBuilder) -> Result<Response> {
123        self.transport.execute(builder).await
124    }
125}
126
127impl HotClientBuilder {
128    /// Overrides the base URL (default `https://api.hot.dev`). For local
129    /// development with `hot dev`, use `http://localhost:4681`.
130    pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
131        self.base_url = base_url.into();
132        self
133    }
134
135    /// Bounds each JSON request. Not applied to streaming or raw requests.
136    pub fn timeout(mut self, timeout: Duration) -> Self {
137        self.timeout = Some(timeout);
138        self
139    }
140
141    /// Overrides the underlying [`reqwest::Client`], e.g. to configure
142    /// proxies or connection pools. Do not set a client-wide timeout on a
143    /// client used for SSE subscriptions — it would sever long-lived streams.
144    pub fn http_client(mut self, client: reqwest::Client) -> Self {
145        self.client = Some(client);
146        self
147    }
148
149    pub fn build(self) -> HotClient {
150        HotClient {
151            transport: Arc::new(Transport::new(
152                self.token,
153                self.base_url,
154                self.timeout,
155                self.client,
156            )),
157        }
158    }
159}