pub struct JmapClient { /* private fields */ }Expand description
Auth-agnostic JMAP base HTTP client.
Construct with JmapClient::new or JmapClient::new_plain.
Extension-specific clients (jmap-chat-client, jmap-mail-client) depend
on this crate and add their method implementations via impl JmapClient.
Implementations§
Source§impl JmapClient
impl JmapClient
Sourcepub async fn upload_blob(
&self,
upload_url_template: &str,
account_id: &str,
data: Bytes,
content_type: &str,
) -> Result<BlobUploadResponse, ClientError>
pub async fn upload_blob( &self, upload_url_template: &str, account_id: &str, data: Bytes, content_type: &str, ) -> Result<BlobUploadResponse, ClientError>
Upload raw bytes to the JMAP blob store (RFC 8620 §6.1).
upload_url_template is from Session.upload_url; {accountId} is
substituted before the request. content_type is sent as the
Content-Type header. If the server returns a sha256 field
(JMAP-CID capability), it is verified against the locally-computed
digest and ClientError::BlobIntegrityMismatch is returned on mismatch.
Sourcepub async fn download_blob(
&self,
params: DownloadBlobParams<'_>,
) -> Result<Bytes, ClientError>
pub async fn download_blob( &self, params: DownloadBlobParams<'_>, ) -> Result<Bytes, ClientError>
Download a blob by ID (RFC 8620 §6.2).
Template variables {accountId}, {blobId}, {name}, and {type} are
substituted from the corresponding fields of params before the GET
request. {type} expands to an empty string when params.accept_type
is None; templates that include ?accept={type} produce ?accept=.
If the server does not tolerate an empty ?accept= parameter, omit
{type} from the download_url template in the Session document.
If params.expected_sha256 is Some, the downloaded bytes are verified
against the hex digest and ClientError::BlobIntegrityMismatch is
returned on mismatch.
Source§impl JmapClient
impl JmapClient
Sourcepub fn new(
transport: impl TransportConfig,
auth: impl AuthProvider + 'static,
base_url: &str,
config: ClientConfig,
) -> Result<Self, ClientError>
pub fn new( transport: impl TransportConfig, auth: impl AuthProvider + 'static, base_url: &str, config: ClientConfig, ) -> Result<Self, ClientError>
Create a new client.
transport configures the underlying HTTP client (TLS trust roots,
client certificates, timeouts). auth injects per-request credentials
(Bearer token, Basic credentials, or none). The two are independent so
any transport can be paired with any credential scheme — for example,
CustomCaTransport with BearerAuth. base_url must be the server
origin (scheme, host, optional port) with no path, query, or fragment
— e.g. "https://100.64.1.1:8008". Trailing slashes are normalized
away by the URL parser and are therefore accepted.
Sourcepub fn new_plain(
auth: impl AuthProvider + 'static,
base_url: &str,
config: ClientConfig,
) -> Result<Self, ClientError>
pub fn new_plain( auth: impl AuthProvider + 'static, base_url: &str, config: ClientConfig, ) -> Result<Self, ClientError>
Convenience constructor for servers with publicly-trusted TLS.
Equivalent to JmapClient::new(DefaultTransport, auth, base_url, config).
Use JmapClient::new when you need a custom transport (e.g.
CustomCaTransport for a private-CA server).
Sourcepub async fn fetch_session(&self) -> Result<Session, ClientError>
pub async fn fetch_session(&self) -> Result<Session, ClientError>
Fetch the JMAP Session object from {base_url}/.well-known/jmap (RFC 8620 §2).
The response body is capped at 1 MiB. Returns ClientError::ResponseTooLarge
if the server sends more. Session URL fields (apiUrl, uploadUrl,
downloadUrl, eventSourceUrl) are validated to have http/https scheme;
a non-http scheme returns ClientError::InvalidSession.
Returns ClientError::AuthFailed on HTTP 401 or 403.
Sourcepub async fn call(
&self,
api_url: &str,
req: &JmapRequest,
) -> Result<JmapResponse, ClientError>
pub async fn call( &self, api_url: &str, req: &JmapRequest, ) -> Result<JmapResponse, ClientError>
POST a jmap_types::JmapRequest to api_url and return the parsed jmap_types::JmapResponse
(RFC 8620 §3.3).
api_url is taken as an explicit parameter (not from self) because the
caller holds a Session and selects the correct URL from it.
The response body is capped at 8 MiB. Returns ClientError::ResponseTooLarge
if the server sends more.
Returns ClientError::AuthFailed on HTTP 401 or 403.
Sourcepub async fn subscribe_events(
&self,
event_source_url: &str,
last_event_id: Option<&str>,
) -> Result<BoxStream<'static, Result<SseFrame, ClientError>>, ClientError>
pub async fn subscribe_events( &self, event_source_url: &str, last_event_id: Option<&str>, ) -> Result<BoxStream<'static, Result<SseFrame, ClientError>>, ClientError>
Open an SSE connection to event_source_url and return an async stream
of parsed SseFrames (RFC 8620 §7.3).
§URI template expansion
Session.event_source_url is a URI template (RFC 6570 Level-1) with
variables types, closeafter, and ping. You must expand it
before passing it to this function, or the server will receive the
literal text {types} in the URL and return an error. Use
expand_url_template:
let url = jmap_base_client::expand_url_template(
&session.event_source_url,
&[("types", "*"), ("closeafter", "no"), ("ping", "0")],
)?;
let stream = client.subscribe_events(&url, None).await?;If last_event_id is Some, sends a Last-Event-ID header so the
server can resume from where the previous stream left off.
Buffer growth is capped at ClientConfig::max_sse_frame bytes per
frame (default: 1 MiB). If a single SSE frame exceeds this limit the
stream yields ClientError::SseFrameTooLarge and terminates.
No timeout is applied to this call or to the resulting stream. The
connect timeout (10 s, TCP only) is the only deadline enforced. If the
server stalls before sending HTTP response headers, or later goes silent
on the open connection, this call or the stream will hang indefinitely.
Wrap the entire call and/or stream iteration in tokio::time::timeout
if you need to bound either phase.
Returns ClientError::AuthFailed on HTTP 401 or 403 before the stream
starts.
Sourcepub async fn connect_ws_session(
&self,
ws_url: &str,
auth_header: Option<(&str, &str)>,
) -> Result<WsSession, ClientError>
pub async fn connect_ws_session( &self, ws_url: &str, auth_header: Option<(&str, &str)>, ) -> Result<WsSession, ClientError>
Open a WebSocket connection to ws_url using this client’s
configured max_ws_message byte cap.
Convenience wrapper around crate::ws::connect_ws_with_limit that
passes ClientConfig::max_ws_message as the per-message /
per-frame byte cap. Mirrors the Self::subscribe_events
pattern of “the JmapClient method uses ClientConfig; the free
function takes an explicit value”.
ws_url must come from the session document’s WebSocket capability
URL. auth_header is an optional (name, value) pair for the
upgrade request; the auth provider on this client is NOT used here
because some servers attach WebSocket auth via cookie or session
header rather than the same scheme as HTTP requests.
§Security
The auth_header value is a credential and must not be logged or
echoed back to other systems. Treat it with the same care as a
crate::auth::BearerAuth token. Transport errors raised by this
method are constructed without the original credential bytes, but
downstream code that inspects ClientError should still avoid
printing or storing the auth_header itself.
Returns ClientError::InvalidArgument for non-ws:///wss:// URLs.
See crate::ws::connect_ws_with_limit for full error semantics.
Trait Implementations§
Source§impl Clone for JmapClient
impl Clone for JmapClient
Source§fn clone(&self) -> JmapClient
fn clone(&self) -> JmapClient
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more