@smbcloud / cli / commits / 72c2237

feat(email): add transactional email SDK (Rust crate + Ruby gem)

Reference SDK for the smbCloud transactional email API. crates/smbcloud-email-sdk (Rust, mirrors smbcloud-gresiq-sdk): - EmailClient: send / get_message / list_messages over reqwest, with Authorization: Bearer <smb_mail_ key> - SendEmail builder (html/text, cc/bcc/reply_to, attachments, headers, tags, idempotency_key); EmailMessage/EmailEvent; EmailStatus via serde_repr to match the server enum - EmailCredentials + base_url(Environment); EmailError - doctests + fmt + clippy clean sdk/gems/email (Ruby native gem, mirrors sdk/gems/auth): - Magnus extension wrapping smbcloud-email-sdk (__send/__get_message/ __list_messages), build.rs macOS install-name fix - SmbCloud::Email::Client#send/#get_message/#list_messages, error normalization, version/gemspec/Rakefile/sig/rubocop - builds against the in-repo crate via [patch.crates-io]; release tooling publishes smbcloud-email-sdk first, after which the version dep resolves from crates.io Verified: crate builds + doctests pass; gem compiles under Ruby 3.4.2 and the full Ruby -> Magnus -> Rust -> HTTP path works end to end. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

keypair34 committed Jun 30, 2026 at 00:32 UTC 72c22370c7919b5add1d871090c8f65c2c12cddc
30 files changed +3388
Cargo.lock
+15
@@ -2546,6 +2546,21 @@ dependencies = [
2546 "url-builder",
2547 ]
2548
2549 +[[package]]
2550 +name = "smbcloud-email-sdk"
2551 +version = "0.4.7"
2552 +dependencies = [
2553 + "anyhow",
2554 + "log",
2555 + "reqwest",
2556 + "serde",
2557 + "serde_json",
2558 + "serde_repr",
2559 + "smbcloud-network",
2560 + "thiserror 2.0.18",
2561 + "tokio",
2562 +]
2563 +
2564 [[package]]
2565 name = "smbcloud-gresiq"
2566 version = "0.4.7"
Cargo.toml
+1
@@ -28,6 +28,7 @@ serde_json = "1.0.82"
28 serde_repr = "0.1"
29 smbcloud-auth = { version = "0.4.7", path = "crates/smbcloud-auth" }
30 smbcloud-auth-sdk = { version = "0.4.7", path = "crates/smbcloud-auth-sdk" }
31 +smbcloud-email-sdk = { version = "0.4.7", path = "crates/smbcloud-email-sdk" }
32 smbcloud-gresiq-sdk = { version = "0.4.7", path = "crates/smbcloud-gresiq-sdk" }
33 smbcloud-mail = { version = "0.4.7", path = "crates/smbcloud-mail" }
34 smbcloud-model = { version = "0.4.7", path = "crates/smbcloud-model" }
crates/smbcloud-email-sdk/Cargo.toml new
+30
@@ -0,0 +1,30 @@
1 +[package]
2 +name = "smbcloud-email-sdk"
3 +version = "0.4.7"
4 +edition = "2021"
5 +description = "Rust client for the smbCloud transactional email API — send email from a verified domain and read delivery status."
6 +license = "Apache-2.0"
7 +authors = ["Seto Elkahfi <hej@setoelkahfi.se>"]
8 +repository = "https://github.com/smbcloudXYZ/smbcloud-cli"
9 +homepage = "https://smbcloud.xyz"
10 +documentation = "https://docs.rs/smbcloud-email-sdk"
11 +readme = "README.md"
12 +keywords = ["smbcloud", "email", "transactional", "api", "mail"]
13 +categories = ["api-bindings", "network-programming", "web-programming::http-client"]
14 +
15 +[lib]
16 +path = "src/smbcloud_email_sdk.rs"
17 +
18 +[dependencies]
19 +log = { workspace = true }
20 +reqwest = { workspace = true, features = ["json", "rustls-tls"] }
21 +serde = { workspace = true, features = ["derive"] }
22 +serde_json = { workspace = true }
23 +serde_repr = { workspace = true }
24 +smbcloud-network = { workspace = true }
25 +thiserror = { workspace = true }
26 +tokio = { workspace = true, features = ["rt"] }
27 +
28 +[dev-dependencies]
29 +anyhow = { workspace = true }
30 +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
crates/smbcloud-email-sdk/README.md new
+81
@@ -0,0 +1,81 @@
1 +# smbcloud-email-sdk
2 +
3 +Rust client for the **smbCloud transactional email API**. Send transactional
4 +email from a verified domain and read each message's delivery status.
5 +
6 +The crate handles the HTTP transport and the `Authorization: Bearer <api_key>`
7 +header. You build the message and own the content.
8 +
9 +## Install
10 +
11 +```toml
12 +[dependencies]
13 +smbcloud-email-sdk = "0.4"
14 +tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
15 +```
16 +
17 +## Authentication
18 +
19 +Mint a `smb_mail_…` API key for your Mail app in the smbCloud console. Sending is
20 +scoped to that app's verified domain; reading messages needs a read-scope key.
21 +
22 +## Send
23 +
24 +```rust,no_run
25 +use smbcloud_email_sdk::{EmailClient, EmailCredentials, Environment, SendEmail};
26 +
27 +#[tokio::main]
28 +async fn main() -> anyhow::Result<()> {
29 + let client = EmailClient::from_credentials(
30 + Environment::Production,
31 + EmailCredentials { api_key: "smb_mail_your_key" },
32 + );
33 +
34 + let message = SendEmail::new("billing@example.com", ["customer@acme.com"])
35 + .subject("Your receipt")
36 + .html("<h1>Thanks!</h1>")
37 + .text("Thanks!")
38 + .idempotency_key("receipt-2026-0001");
39 +
40 + let sent = client.send(&message).await?;
41 + println!("sent {} ({:?})", sent.id, sent.status);
42 + Ok(())
43 +}
44 +```
45 +
46 +## Attachments, cc/bcc, headers, tags
47 +
48 +```rust,no_run
49 +# use smbcloud_email_sdk::{Attachment, SendEmail};
50 +let message = SendEmail::new("billing@example.com", ["customer@acme.com"])
51 + .subject("Invoice")
52 + .html("<p>See attached.</p>")
53 + .cc(["accounts@acme.com"])
54 + .reply_to(["support@example.com"])
55 + .attachment(Attachment {
56 + filename: "invoice.pdf".into(),
57 + content_base64: "JVBERi0xLjQ...".into(),
58 + })
59 + .header("X-Entity-Ref-ID", "inv_123")
60 + .tag("category", "invoice");
61 +```
62 +
63 +## Read delivery status
64 +
65 +```rust,no_run
66 +# async fn run(client: smbcloud_email_sdk::EmailClient) -> anyhow::Result<()> {
67 +let message = client.get_message("eml_…").await?;
68 +println!("status: {:?}", message.status);
69 +for event in &message.events {
70 + println!(" {} at {}", event.event_type, event.occurred_at);
71 +}
72 +
73 +let recent = client.list_messages(Some("bounced"), Some(20)).await?;
74 +println!("{} bounced", recent.len());
75 +# Ok(())
76 +# }
77 +```
78 +
79 +## License
80 +
81 +Apache-2.0
crates/smbcloud-email-sdk/src/client.rs new
+111
@@ -0,0 +1,111 @@
1 +use crate::client_credentials::EmailCredentials;
2 +use crate::error::EmailError;
3 +use crate::message::{EmailMessage, SendEmail};
4 +use smbcloud_network::environment::Environment;
5 +
6 +/// Talks to the smbCloud transactional email API.
7 +///
8 +/// Cheap to clone — the inner `reqwest::Client` is `Arc`-backed. Build one at
9 +/// startup and clone it wherever you need it.
10 +///
11 +/// # Authentication
12 +///
13 +/// Every request carries `Authorization: Bearer <api_key>` from the
14 +/// [`EmailCredentials`]. Mint a key for your Mail app in the smbCloud console;
15 +/// sending is scoped to that app's verified domain. Reading messages
16 +/// (`get_message`, `list_messages`) needs a key with read scope.
17 +#[derive(Debug, Clone)]
18 +pub struct EmailClient {
19 + base_url: String,
20 + api_key: String,
21 + http: reqwest::Client,
22 +}
23 +
24 +impl EmailClient {
25 + /// Build a client from an environment and credentials.
26 + ///
27 + /// The base URL is resolved from the environment:
28 + /// - `Environment::Dev` → `http://localhost:8088`
29 + /// - `Environment::Production` → `https://api.smbcloud.xyz`
30 + pub fn from_credentials(environment: Environment, credentials: EmailCredentials<'_>) -> Self {
31 + EmailClient {
32 + base_url: crate::client_credentials::base_url(&environment),
33 + api_key: credentials.api_key.to_string(),
34 + http: reqwest::Client::new(),
35 + }
36 + }
37 +
38 + /// Send a transactional email: `POST /v1/email/messages`.
39 + ///
40 + /// Returns the created [`EmailMessage`] (status `Sent`). If the message
41 + /// carried an `idempotency_key` that was already used, the original message
42 + /// is returned and nothing is sent again.
43 + pub async fn send(&self, message: &SendEmail) -> Result<EmailMessage, EmailError> {
44 + let url = format!("{}/v1/email/messages", self.base_url);
45 + let response = self
46 + .authed(self.http.post(&url))
47 + .json(message)
48 + .send()
49 + .await?;
50 +
51 + if response.status().is_success() {
52 + return Ok(response.json().await?);
53 + }
54 + Err(self.api_error(response).await)
55 + }
56 +
57 + /// Fetch one message by id with its delivery-event timeline:
58 + /// `GET /v1/email/messages/:id`. Requires a read-scope key.
59 + pub async fn get_message(&self, id: &str) -> Result<EmailMessage, EmailError> {
60 + let url = format!("{}/v1/email/messages/{}", self.base_url, id);
61 + let response = self.authed(self.http.get(&url)).send().await?;
62 +
63 + if response.status().is_success() {
64 + return Ok(response.json().await?);
65 + }
66 + Err(self.api_error(response).await)
67 + }
68 +
69 + /// List recent messages: `GET /v1/email/messages`. Requires a read-scope
70 + /// key. `status` filters by delivery status name (e.g. `"delivered"`);
71 + /// `limit` is clamped server-side to `1..=100`.
72 + pub async fn list_messages(
73 + &self,
74 + status: Option<&str>,
75 + limit: Option<u32>,
76 + ) -> Result<Vec<EmailMessage>, EmailError> {
77 + let url = format!("{}/v1/email/messages", self.base_url);
78 +
79 + let mut params: Vec<(&str, String)> = Vec::new();
80 + if let Some(status) = status {
81 + params.push(("status", status.to_string()));
82 + }
83 + if let Some(limit) = limit {
84 + params.push(("limit", limit.to_string()));
85 + }
86 +
87 + let response = self
88 + .authed(self.http.get(&url))
89 + .query(&params)
90 + .send()
91 + .await?;
92 +
93 + if response.status().is_success() {
94 + return Ok(response.json().await?);
95 + }
96 + Err(self.api_error(response).await)
97 + }
98 +
99 + fn authed(&self, builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
100 + builder.header("Authorization", format!("Bearer {}", self.api_key))
101 + }
102 +
103 + async fn api_error(&self, response: reqwest::Response) -> EmailError {
104 + let status = response.status().as_u16();
105 + let message = response
106 + .text()
107 + .await
108 + .unwrap_or_else(|_| "unreadable response body".to_string());
109 + EmailError::Api { status, message }
110 + }
111 +}
crates/smbcloud-email-sdk/src/client_credentials.rs new
+23
@@ -0,0 +1,23 @@
1 +use smbcloud_network::environment::Environment;
2 +
3 +/// API credential for the smbCloud transactional email API.
4 +///
5 +/// `api_key` is a `smb_mail_…` key minted for a Mail app in the smbCloud
6 +/// console. It is sent as `Authorization: Bearer <api_key>` and scopes sending
7 +/// to that app's verified domain.
8 +#[derive(Clone, Copy)]
9 +pub struct EmailCredentials<'a> {
10 + pub api_key: &'a str,
11 +}
12 +
13 +/// Resolve the email API base URL for the given environment.
14 +///
15 +/// - **Dev** → `http://localhost:8088`
16 +/// - **Production** → `https://api.smbcloud.xyz`
17 +pub fn base_url(environment: &Environment) -> String {
18 + format!(
19 + "{}://{}",
20 + environment.api_protocol(),
21 + environment.api_host()
22 + )
23 +}
crates/smbcloud-email-sdk/src/error.rs new
+15
@@ -0,0 +1,15 @@
1 +use thiserror::Error;
2 +
3 +#[derive(Debug, Error)]
4 +pub enum EmailError {
5 + /// The HTTP layer failed before we got a response — network down, DNS
6 + /// failure, TLS handshake, that sort of thing.
7 + #[error("request failed: {0}")]
8 + Http(#[from] reqwest::Error),
9 +
10 + /// The API replied with a non-2xx status. `message` is whatever the server
11 + /// put in the response body (typically `{ "message": "..." }`), or the HTTP
12 + /// reason phrase if the body wasn't readable.
13 + #[error("email API error {status}: {message}")]
14 + Api { status: u16, message: String },
15 +}
crates/smbcloud-email-sdk/src/message.rs new
+150
@@ -0,0 +1,150 @@
1 +use serde::{Deserialize, Serialize};
2 +use serde_repr::{Deserialize_repr, Serialize_repr};
3 +
4 +/// Delivery status of a transactional email, mirroring the server-side
5 +/// integer-backed enum. Deserialized with `serde_repr` from the plain integer
6 +/// the API returns.
7 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr)]
8 +#[repr(u8)]
9 +pub enum EmailStatus {
10 + Queued = 0,
11 + Sent = 1,
12 + Delivered = 2,
13 + Bounced = 3,
14 + Complained = 4,
15 + Failed = 5,
16 +}
17 +
18 +/// One attachment on an outbound email. `content_base64` is the file content
19 +/// encoded as standard base64; the server reassembles it into the MIME message.
20 +#[derive(Debug, Clone, Serialize, Deserialize)]
21 +pub struct Attachment {
22 + pub filename: String,
23 + pub content_base64: String,
24 +}
25 +
26 +/// An outbound transactional email.
27 +///
28 +/// Build one with [`SendEmail::new`] and the builder helpers, then hand it to
29 +/// [`crate::EmailClient::send`]. At least one of `html` or `text` is required;
30 +/// `from` must be on the API key's verified domain.
31 +#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32 +#[serde(default)]
33 +pub struct SendEmail {
34 + pub from: String,
35 + pub to: Vec<String>,
36 + #[serde(skip_serializing_if = "Vec::is_empty")]
37 + pub cc: Vec<String>,
38 + #[serde(skip_serializing_if = "Vec::is_empty")]
39 + pub bcc: Vec<String>,
40 + #[serde(skip_serializing_if = "Vec::is_empty")]
41 + pub reply_to: Vec<String>,
42 + #[serde(skip_serializing_if = "Option::is_none")]
43 + pub subject: Option<String>,
44 + #[serde(skip_serializing_if = "Option::is_none")]
45 + pub html: Option<String>,
46 + #[serde(skip_serializing_if = "Option::is_none")]
47 + pub text: Option<String>,
48 + #[serde(skip_serializing_if = "Vec::is_empty")]
49 + pub attachments: Vec<Attachment>,
50 + #[serde(skip_serializing_if = "std::collections::HashMap::is_empty")]
51 + pub headers: std::collections::HashMap<String, String>,
52 + #[serde(skip_serializing_if = "std::collections::HashMap::is_empty")]
53 + pub tags: std::collections::HashMap<String, String>,
54 + #[serde(skip_serializing_if = "Option::is_none")]
55 + pub idempotency_key: Option<String>,
56 +}
57 +
58 +impl SendEmail {
59 + /// Start a message from a sender address and one or more recipients.
60 + pub fn new(from: impl Into<String>, to: impl IntoIterator<Item = impl Into<String>>) -> Self {
61 + SendEmail {
62 + from: from.into(),
63 + to: to.into_iter().map(Into::into).collect(),
64 + ..Default::default()
65 + }
66 + }
67 +
68 + pub fn subject(mut self, subject: impl Into<String>) -> Self {
69 + self.subject = Some(subject.into());
70 + self
71 + }
72 +
73 + pub fn html(mut self, html: impl Into<String>) -> Self {
74 + self.html = Some(html.into());
75 + self
76 + }
77 +
78 + pub fn text(mut self, text: impl Into<String>) -> Self {
79 + self.text = Some(text.into());
80 + self
81 + }
82 +
83 + pub fn cc(mut self, cc: impl IntoIterator<Item = impl Into<String>>) -> Self {
84 + self.cc = cc.into_iter().map(Into::into).collect();
85 + self
86 + }
87 +
88 + pub fn bcc(mut self, bcc: impl IntoIterator<Item = impl Into<String>>) -> Self {
89 + self.bcc = bcc.into_iter().map(Into::into).collect();
90 + self
91 + }
92 +
93 + pub fn reply_to(mut self, reply_to: impl IntoIterator<Item = impl Into<String>>) -> Self {
94 + self.reply_to = reply_to.into_iter().map(Into::into).collect();
95 + self
96 + }
97 +
98 + pub fn attachment(mut self, attachment: Attachment) -> Self {
99 + self.attachments.push(attachment);
100 + self
101 + }
102 +
103 + pub fn header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
104 + self.headers.insert(key.into(), value.into());
105 + self
106 + }
107 +
108 + pub fn tag(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
109 + self.tags.insert(key.into(), value.into());
110 + self
111 + }
112 +
113 + /// Make a retried send safe: the same key returns the original message
114 + /// instead of sending again.
115 + pub fn idempotency_key(mut self, key: impl Into<String>) -> Self {
116 + self.idempotency_key = Some(key.into());
117 + self
118 + }
119 +}
120 +
121 +/// One delivery event in a message's timeline (delivered, bounced, opened, …).
122 +/// Present on [`EmailMessage`] only when fetched via
123 +/// [`crate::EmailClient::get_message`].
124 +#[derive(Debug, Clone, Serialize, Deserialize)]
125 +pub struct EmailEvent {
126 + pub id: String,
127 + pub event_type: u8,
128 + #[serde(default)]
129 + pub payload: serde_json::Value,
130 + pub occurred_at: String,
131 +}
132 +
133 +/// A transactional email as returned by the API: the send result and, when
134 +/// fetched by id, its delivery status and event timeline.
135 +#[derive(Debug, Clone, Serialize, Deserialize)]
136 +pub struct EmailMessage {
137 + pub id: String,
138 + pub status: EmailStatus,
139 + pub provider_message_id: Option<String>,
140 + pub idempotency_key: Option<String>,
141 + pub from_email: String,
142 + #[serde(default)]
143 + pub to_emails: Vec<String>,
144 + pub subject: Option<String>,
145 + pub sent_at: Option<String>,
146 + pub created_at: Option<String>,
147 + /// Populated by `get_message`; empty for the bare send response.
148 + #[serde(default)]
149 + pub events: Vec<EmailEvent>,
150 +}
crates/smbcloud-email-sdk/src/smbcloud_email_sdk.rs new
+42
@@ -0,0 +1,42 @@
1 +//! Rust client for the smbCloud transactional email API.
2 +//!
3 +//! Send transactional email from your verified domain and read each message's
4 +//! delivery status. This crate handles the HTTP transport and the
5 +//! `Authorization: Bearer <api_key>` header; you build the message and own the
6 +//! content.
7 +//!
8 +//! # Quick start
9 +//!
10 +//! ```no_run
11 +//! use smbcloud_email_sdk::{EmailClient, EmailCredentials, Environment, SendEmail};
12 +//!
13 +//! #[tokio::main]
14 +//! async fn main() -> anyhow::Result<()> {
15 +//! let client = EmailClient::from_credentials(
16 +//! Environment::Production,
17 +//! EmailCredentials { api_key: "smb_mail_your_key" },
18 +//! );
19 +//!
20 +//! let message = SendEmail::new("billing@example.com", ["customer@acme.com"])
21 +//! .subject("Your receipt")
22 +//! .html("<h1>Thanks!</h1>")
23 +//! .text("Thanks!")
24 +//! .idempotency_key("receipt-2026-0001");
25 +//!
26 +//! let sent = client.send(&message).await?;
27 +//! println!("sent {} ({:?})", sent.id, sent.status);
28 +//!
29 +//! Ok(())
30 +//! }
31 +//! ```
32 +
33 +mod client;
34 +mod client_credentials;
35 +mod error;
36 +mod message;
37 +
38 +pub use client::EmailClient;
39 +pub use client_credentials::{base_url, EmailCredentials};
40 +pub use error::EmailError;
41 +pub use message::{Attachment, EmailEvent, EmailMessage, EmailStatus, SendEmail};
42 +pub use smbcloud_network::environment::Environment;
sdk/gems/email/.gitignore new
+14
@@ -0,0 +1,14 @@
1 +/.bundle/
2 +/.yardoc
3 +/_yardoc/
4 +/coverage/
5 +/doc/
6 +/pkg/
7 +/spec/reports/
8 +/tmp/
9 +*.bundle
10 +*.so
11 +*.o
12 +*.a
13 +mkmf.log
14 +target/
sdk/gems/email/.rubocop.yml new
+19
@@ -0,0 +1,19 @@
1 +AllCops:
2 + TargetRubyVersion: 3.1
3 + NewCops: enable
4 + Exclude:
5 + - "vendor/**/*"
6 + - "tmp/**/*"
7 + - "target/**/*"
8 + - "pkg/**/*"
9 +
10 +# Native extension wrapper gems use a bare `module Email; end` stub at the
11 +# top level so Magnus can register the native methods into the right namespace.
12 +# Having both that stub and the real `SmbCloud::Email` implementation in one
13 +# file is intentional — splitting them would break the require chain.
14 +Style/OneClassPerFile:
15 + Enabled: false
16 +
17 +# Yard / CHANGELOG serve as the documentation source for this gem.
18 +Style/Documentation:
19 + Enabled: false
sdk/gems/email/.ruby-version new
+1
@@ -0,0 +1 @@
1 +3.4.2
sdk/gems/email/CHANGELOG.md new
+8
@@ -0,0 +1,8 @@
1 +# Changelog
2 +
3 +## [0.4.7] - 2026-06-30
4 +
5 +- Initial release. Ruby bindings for the smbCloud transactional email API:
6 + `SmbCloud::Email::Client#send`, `#get_message`, and `#list_messages`,
7 + powered by the shared Rust SDK (`smbcloud-email-sdk`) via a native Magnus
8 + extension.
sdk/gems/email/Cargo.lock new
+2408
@@ -0,0 +1,2408 @@
1 +# This file is automatically @generated by Cargo.
2 +# It is not intended for manual editing.
3 +version = 4
4 +
5 +[[package]]
6 +name = "aho-corasick"
7 +version = "1.1.4"
8 +source = "registry+https://github.com/rust-lang/crates.io-index"
9 +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
10 +dependencies = [
11 + "memchr",
12 +]
13 +
14 +[[package]]
15 +name = "android_system_properties"
16 +version = "0.1.5"
17 +source = "registry+https://github.com/rust-lang/crates.io-index"
18 +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
19 +dependencies = [
20 + "libc",
21 +]
22 +
23 +[[package]]
24 +name = "ansi_term"
25 +version = "0.12.1"
26 +source = "registry+https://github.com/rust-lang/crates.io-index"
27 +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
28 +dependencies = [
29 + "winapi",
30 +]
31 +
32 +[[package]]
33 +name = "anstream"
34 +version = "1.0.0"
35 +source = "registry+https://github.com/rust-lang/crates.io-index"
36 +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
37 +dependencies = [
38 + "anstyle",
39 + "anstyle-parse",
40 + "anstyle-query",
41 + "anstyle-wincon",
42 + "colorchoice",
43 + "is_terminal_polyfill",
44 + "utf8parse",
45 +]
46 +
47 +[[package]]
48 +name = "anstyle"
49 +version = "1.0.14"
50 +source = "registry+https://github.com/rust-lang/crates.io-index"
51 +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
52 +
53 +[[package]]
54 +name = "anstyle-parse"
55 +version = "1.0.0"
56 +source = "registry+https://github.com/rust-lang/crates.io-index"
57 +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
58 +dependencies = [
59 + "utf8parse",
60 +]
61 +
62 +[[package]]
63 +name = "anstyle-query"
64 +version = "1.1.5"
65 +source = "registry+https://github.com/rust-lang/crates.io-index"
66 +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
67 +dependencies = [
68 + "windows-sys 0.61.2",
69 +]
70 +
71 +[[package]]
72 +name = "anstyle-wincon"
73 +version = "3.0.11"
74 +source = "registry+https://github.com/rust-lang/crates.io-index"
75 +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
76 +dependencies = [
77 + "anstyle",
78 + "once_cell_polyfill",
79 + "windows-sys 0.61.2",
80 +]
81 +
82 +[[package]]
83 +name = "atomic-waker"
84 +version = "1.1.2"
85 +source = "registry+https://github.com/rust-lang/crates.io-index"
86 +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
87 +
88 +[[package]]
89 +name = "atty"
90 +version = "0.2.14"
91 +source = "registry+https://github.com/rust-lang/crates.io-index"
92 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
93 +dependencies = [
94 + "hermit-abi",
95 + "libc",
96 + "winapi",
97 +]
98 +
99 +[[package]]
100 +name = "autocfg"
101 +version = "1.5.1"
102 +source = "registry+https://github.com/rust-lang/crates.io-index"
103 +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
104 +
105 +[[package]]
106 +name = "base64"
107 +version = "0.22.1"
108 +source = "registry+https://github.com/rust-lang/crates.io-index"
109 +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
110 +
111 +[[package]]
112 +name = "bindgen"
113 +version = "0.72.1"
114 +source = "registry+https://github.com/rust-lang/crates.io-index"
115 +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
116 +dependencies = [
117 + "bitflags 2.13.0",
118 + "cexpr",
119 + "clang-sys",
120 + "itertools",
121 + "proc-macro2",
122 + "quote",
123 + "regex",
124 + "rustc-hash",
125 + "shlex 1.3.0",
126 + "syn 2.0.118",
127 +]
128 +
129 +[[package]]
130 +name = "bitflags"
131 +version = "1.3.2"
132 +source = "registry+https://github.com/rust-lang/crates.io-index"
133 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
134 +
135 +[[package]]
136 +name = "bitflags"
137 +version = "2.13.0"
138 +source = "registry+https://github.com/rust-lang/crates.io-index"
139 +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
140 +
141 +[[package]]
142 +name = "bumpalo"
143 +version = "3.20.3"
144 +source = "registry+https://github.com/rust-lang/crates.io-index"
145 +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
146 +
147 +[[package]]
148 +name = "bytes"
149 +version = "1.12.0"
150 +source = "registry+https://github.com/rust-lang/crates.io-index"
151 +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
152 +
153 +[[package]]
154 +name = "cc"
155 +version = "1.2.65"
156 +source = "registry+https://github.com/rust-lang/crates.io-index"
157 +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
158 +dependencies = [
159 + "find-msvc-tools",
160 + "shlex 2.0.1",
161 +]
162 +
163 +[[package]]
164 +name = "cexpr"
165 +version = "0.6.0"
166 +source = "registry+https://github.com/rust-lang/crates.io-index"
167 +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
168 +dependencies = [
169 + "nom",
170 +]
171 +
172 +[[package]]
173 +name = "cfg-if"
174 +version = "1.0.4"
175 +source = "registry+https://github.com/rust-lang/crates.io-index"
176 +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
177 +
178 +[[package]]
179 +name = "cfg_aliases"
180 +version = "0.2.1"
181 +source = "registry+https://github.com/rust-lang/crates.io-index"
182 +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
183 +
184 +[[package]]
185 +name = "chrono"
186 +version = "0.4.45"
187 +source = "registry+https://github.com/rust-lang/crates.io-index"
188 +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
189 +dependencies = [
190 + "iana-time-zone",
191 + "js-sys",
192 + "num-traits",
193 + "serde",
194 + "wasm-bindgen",
195 + "windows-link",
196 +]
197 +
198 +[[package]]
199 +name = "clang-sys"
200 +version = "1.8.1"
201 +source = "registry+https://github.com/rust-lang/crates.io-index"
202 +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
203 +dependencies = [
204 + "glob",
205 + "libc",
206 + "libloading",
207 +]
208 +
209 +[[package]]
210 +name = "clap"
211 +version = "2.34.0"
212 +source = "registry+https://github.com/rust-lang/crates.io-index"
213 +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
214 +dependencies = [
215 + "ansi_term",
216 + "atty",
217 + "bitflags 1.3.2",
218 + "strsim 0.8.0",
219 + "textwrap",
220 + "unicode-width",
221 + "vec_map",
222 +]
223 +
224 +[[package]]
225 +name = "clap"
226 +version = "4.6.1"
227 +source = "registry+https://github.com/rust-lang/crates.io-index"
228 +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
229 +dependencies = [
230 + "clap_builder",
231 + "clap_derive",
232 +]
233 +
234 +[[package]]
235 +name = "clap_builder"
236 +version = "4.6.0"
237 +source = "registry+https://github.com/rust-lang/crates.io-index"
238 +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
239 +dependencies = [
240 + "anstream",
241 + "anstyle",
242 + "clap_lex",
243 + "strsim 0.11.1",
244 +]
245 +
246 +[[package]]
247 +name = "clap_derive"
248 +version = "4.6.1"
249 +source = "registry+https://github.com/rust-lang/crates.io-index"
250 +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
251 +dependencies = [
252 + "heck 0.5.0",
253 + "proc-macro2",
254 + "quote",
255 + "syn 2.0.118",
256 +]
257 +
258 +[[package]]
259 +name = "clap_lex"
260 +version = "1.1.0"
261 +source = "registry+https://github.com/rust-lang/crates.io-index"
262 +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
263 +
264 +[[package]]
265 +name = "colorchoice"
266 +version = "1.0.5"
267 +source = "registry+https://github.com/rust-lang/crates.io-index"
268 +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
269 +
270 +[[package]]
271 +name = "convert_case"
272 +version = "0.6.0"
273 +source = "registry+https://github.com/rust-lang/crates.io-index"
274 +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
275 +dependencies = [
276 + "unicode-segmentation",
277 +]
278 +
279 +[[package]]
280 +name = "core-foundation"
281 +version = "0.10.1"
282 +source = "registry+https://github.com/rust-lang/crates.io-index"
283 +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
284 +dependencies = [
285 + "core-foundation-sys",
286 + "libc",
287 +]
288 +
289 +[[package]]
290 +name = "core-foundation-sys"
291 +version = "0.8.7"
292 +source = "registry+https://github.com/rust-lang/crates.io-index"
293 +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
294 +
295 +[[package]]
296 +name = "displaydoc"
297 +version = "0.2.6"
298 +source = "registry+https://github.com/rust-lang/crates.io-index"
299 +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
300 +dependencies = [
301 + "proc-macro2",
302 + "quote",
303 + "syn 2.0.118",
304 +]
305 +
306 +[[package]]
307 +name = "either"
308 +version = "1.16.0"
309 +source = "registry+https://github.com/rust-lang/crates.io-index"
310 +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
311 +
312 +[[package]]
313 +name = "email"
314 +version = "0.4.7"
315 +dependencies = [
316 + "magnus",
317 + "serde_json",
318 + "smbcloud-email-sdk",
319 + "tokio",
320 +]
321 +
322 +[[package]]
323 +name = "find-msvc-tools"
324 +version = "0.1.9"
325 +source = "registry+https://github.com/rust-lang/crates.io-index"
326 +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
327 +
328 +[[package]]
329 +name = "form_urlencoded"
330 +version = "1.2.2"
331 +source = "registry+https://github.com/rust-lang/crates.io-index"
332 +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
333 +dependencies = [
334 + "percent-encoding",
335 +]
336 +
337 +[[package]]
338 +name = "futures-channel"
339 +version = "0.3.32"
340 +source = "registry+https://github.com/rust-lang/crates.io-index"
341 +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
342 +dependencies = [
343 + "futures-core",
344 +]
345 +
346 +[[package]]
347 +name = "futures-core"
348 +version = "0.3.32"
349 +source = "registry+https://github.com/rust-lang/crates.io-index"
350 +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
351 +
352 +[[package]]
353 +name = "futures-task"
354 +version = "0.3.32"
355 +source = "registry+https://github.com/rust-lang/crates.io-index"
356 +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
357 +
358 +[[package]]
359 +name = "futures-util"
360 +version = "0.3.32"
361 +source = "registry+https://github.com/rust-lang/crates.io-index"
362 +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
363 +dependencies = [
364 + "futures-core",
365 + "futures-task",
366 + "pin-project-lite",
367 + "slab",
368 +]
369 +
370 +[[package]]
371 +name = "generator"
372 +version = "0.7.5"
373 +source = "registry+https://github.com/rust-lang/crates.io-index"
374 +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
375 +dependencies = [
376 + "cc",
377 + "libc",
378 + "log",
379 + "rustversion",
380 + "windows",
381 +]
382 +
383 +[[package]]
384 +name = "getrandom"
385 +version = "0.2.17"
386 +source = "registry+https://github.com/rust-lang/crates.io-index"
387 +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
388 +dependencies = [
389 + "cfg-if",
390 + "js-sys",
391 + "libc",
392 + "wasi",
393 + "wasm-bindgen",
394 +]
395 +
396 +[[package]]
397 +name = "getrandom"
398 +version = "0.3.4"
399 +source = "registry+https://github.com/rust-lang/crates.io-index"
400 +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
401 +dependencies = [
402 + "cfg-if",
403 + "js-sys",
404 + "libc",
405 + "r-efi",
406 + "wasip2",
407 + "wasm-bindgen",
408 +]
409 +
410 +[[package]]
411 +name = "glob"
412 +version = "0.3.3"
413 +source = "registry+https://github.com/rust-lang/crates.io-index"
414 +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
415 +
416 +[[package]]
417 +name = "heck"
418 +version = "0.3.3"
419 +source = "registry+https://github.com/rust-lang/crates.io-index"
420 +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
421 +dependencies = [
422 + "unicode-segmentation",
423 +]
424 +
425 +[[package]]
426 +name = "heck"
427 +version = "0.4.1"
428 +source = "registry+https://github.com/rust-lang/crates.io-index"
429 +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
430 +
431 +[[package]]
432 +name = "heck"
433 +version = "0.5.0"
434 +source = "registry+https://github.com/rust-lang/crates.io-index"
435 +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
436 +
437 +[[package]]
438 +name = "hermit-abi"
439 +version = "0.1.19"
440 +source = "registry+https://github.com/rust-lang/crates.io-index"
441 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
442 +dependencies = [
443 + "libc",
444 +]
445 +
446 +[[package]]
447 +name = "http"
448 +version = "1.4.2"
449 +source = "registry+https://github.com/rust-lang/crates.io-index"
450 +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
451 +dependencies = [
452 + "bytes",
453 + "itoa",
454 +]
455 +
456 +[[package]]
457 +name = "http-body"
458 +version = "1.0.1"
459 +source = "registry+https://github.com/rust-lang/crates.io-index"
460 +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
461 +dependencies = [
462 + "bytes",
463 + "http",
464 +]
465 +
466 +[[package]]
467 +name = "http-body-util"
468 +version = "0.1.3"
469 +source = "registry+https://github.com/rust-lang/crates.io-index"
470 +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
471 +dependencies = [
472 + "bytes",
473 + "futures-core",
474 + "http",
475 + "http-body",
476 + "pin-project-lite",
477 +]
478 +
479 +[[package]]
480 +name = "httparse"
481 +version = "1.10.1"
482 +source = "registry+https://github.com/rust-lang/crates.io-index"
483 +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
484 +
485 +[[package]]
486 +name = "hyper"
487 +version = "1.10.1"
488 +source = "registry+https://github.com/rust-lang/crates.io-index"
489 +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498"
490 +dependencies = [
491 + "atomic-waker",
492 + "bytes",
493 + "futures-channel",
494 + "futures-core",
495 + "http",
496 + "http-body",
497 + "httparse",
498 + "itoa",
499 + "pin-project-lite",
500 + "smallvec",
501 + "tokio",
502 + "want",
503 +]
504 +
505 +[[package]]
506 +name = "hyper-rustls"
507 +version = "0.27.9"
508 +source = "registry+https://github.com/rust-lang/crates.io-index"
509 +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
510 +dependencies = [
511 + "http",
512 + "hyper",
513 + "hyper-util",
514 + "rustls",
515 + "rustls-native-certs",
516 + "tokio",
517 + "tokio-rustls",
518 + "tower-service",
519 + "webpki-roots",
520 +]
521 +
522 +[[package]]
523 +name = "hyper-util"
524 +version = "0.1.20"
525 +source = "registry+https://github.com/rust-lang/crates.io-index"
526 +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
527 +dependencies = [
528 + "base64",
529 + "bytes",
530 + "futures-channel",
531 + "futures-util",
532 + "http",
533 + "http-body",
534 + "hyper",
535 + "ipnet",
536 + "libc",
537 + "percent-encoding",
538 + "pin-project-lite",
539 + "socket2",
540 + "tokio",
541 + "tower-service",
542 + "tracing",
543 +]
544 +
545 +[[package]]
546 +name = "iana-time-zone"
547 +version = "0.1.65"
548 +source = "registry+https://github.com/rust-lang/crates.io-index"
549 +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
550 +dependencies = [
551 + "android_system_properties",
552 + "core-foundation-sys",
553 + "iana-time-zone-haiku",
554 + "js-sys",
555 + "log",
556 + "wasm-bindgen",
557 + "windows-core",
558 +]
559 +
560 +[[package]]
561 +name = "iana-time-zone-haiku"
562 +version = "0.1.2"
563 +source = "registry+https://github.com/rust-lang/crates.io-index"
564 +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
565 +dependencies = [
566 + "cc",
567 +]
568 +
569 +[[package]]
570 +name = "icu_collections"
571 +version = "2.2.0"
572 +source = "registry+https://github.com/rust-lang/crates.io-index"
573 +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
574 +dependencies = [
575 + "displaydoc",
576 + "potential_utf",
577 + "utf8_iter",
578 + "yoke",
579 + "zerofrom",
580 + "zerovec",
581 +]
582 +
583 +[[package]]
584 +name = "icu_locale_core"
585 +version = "2.2.0"
586 +source = "registry+https://github.com/rust-lang/crates.io-index"
587 +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
588 +dependencies = [
589 + "displaydoc",
590 + "litemap",
591 + "tinystr",
592 + "writeable",
593 + "zerovec",
594 +]
595 +
596 +[[package]]
597 +name = "icu_normalizer"
598 +version = "2.2.0"
599 +source = "registry+https://github.com/rust-lang/crates.io-index"
600 +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
601 +dependencies = [
602 + "icu_collections",
603 + "icu_normalizer_data",
604 + "icu_properties",
605 + "icu_provider",
606 + "smallvec",
607 + "zerovec",
608 +]
609 +
610 +[[package]]
611 +name = "icu_normalizer_data"
612 +version = "2.2.0"
613 +source = "registry+https://github.com/rust-lang/crates.io-index"
614 +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
615 +
616 +[[package]]
617 +name = "icu_properties"
618 +version = "2.2.0"
619 +source = "registry+https://github.com/rust-lang/crates.io-index"
620 +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
621 +dependencies = [
622 + "icu_collections",
623 + "icu_locale_core",
624 + "icu_properties_data",
625 + "icu_provider",
626 + "zerotrie",
627 + "zerovec",
628 +]
629 +
630 +[[package]]
631 +name = "icu_properties_data"
632 +version = "2.2.0"
633 +source = "registry+https://github.com/rust-lang/crates.io-index"
634 +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
635 +
636 +[[package]]
637 +name = "icu_provider"
638 +version = "2.2.0"
639 +source = "registry+https://github.com/rust-lang/crates.io-index"
640 +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
641 +dependencies = [
642 + "displaydoc",
643 + "icu_locale_core",
644 + "writeable",
645 + "yoke",
646 + "zerofrom",
647 + "zerotrie",
648 + "zerovec",
649 +]
650 +
651 +[[package]]
652 +name = "idna"
653 +version = "1.1.0"
654 +source = "registry+https://github.com/rust-lang/crates.io-index"
655 +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
656 +dependencies = [
657 + "idna_adapter",
658 + "smallvec",
659 + "utf8_iter",
660 +]
661 +
662 +[[package]]
663 +name = "idna_adapter"
664 +version = "1.2.2"
665 +source = "registry+https://github.com/rust-lang/crates.io-index"
666 +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
667 +dependencies = [
668 + "icu_normalizer",
669 + "icu_properties",
670 +]
671 +
672 +[[package]]
673 +name = "ipnet"
674 +version = "2.12.0"
675 +source = "registry+https://github.com/rust-lang/crates.io-index"
676 +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
677 +
678 +[[package]]
679 +name = "is_terminal_polyfill"
680 +version = "1.70.2"
681 +source = "registry+https://github.com/rust-lang/crates.io-index"
682 +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
683 +
684 +[[package]]
685 +name = "itertools"
686 +version = "0.13.0"
687 +source = "registry+https://github.com/rust-lang/crates.io-index"
688 +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
689 +dependencies = [
690 + "either",
691 +]
692 +
693 +[[package]]
694 +name = "itoa"
695 +version = "1.0.18"
696 +source = "registry+https://github.com/rust-lang/crates.io-index"
697 +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
698 +
699 +[[package]]
700 +name = "js-sys"
701 +version = "0.3.103"
702 +source = "registry+https://github.com/rust-lang/crates.io-index"
703 +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
704 +dependencies = [
705 + "cfg-if",
706 + "futures-util",
707 + "wasm-bindgen",
708 +]
709 +
710 +[[package]]
711 +name = "lazy_static"
712 +version = "1.5.0"
713 +source = "registry+https://github.com/rust-lang/crates.io-index"
714 +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
715 +
716 +[[package]]
717 +name = "libc"
718 +version = "0.2.186"
719 +source = "registry+https://github.com/rust-lang/crates.io-index"
720 +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
721 +
722 +[[package]]
723 +name = "libloading"
724 +version = "0.8.9"
725 +source = "registry+https://github.com/rust-lang/crates.io-index"
726 +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
727 +dependencies = [
728 + "cfg-if",
729 + "windows-link",
730 +]
731 +
732 +[[package]]
733 +name = "litemap"
734 +version = "0.8.2"
735 +source = "registry+https://github.com/rust-lang/crates.io-index"
736 +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
737 +
738 +[[package]]
739 +name = "log"
740 +version = "0.4.33"
741 +source = "registry+https://github.com/rust-lang/crates.io-index"
742 +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
743 +
744 +[[package]]
745 +name = "loom"
746 +version = "0.5.6"
747 +source = "registry+https://github.com/rust-lang/crates.io-index"
748 +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
749 +dependencies = [
750 + "cfg-if",
751 + "generator",
752 + "scoped-tls",
753 + "serde",
754 + "serde_json",
755 + "tracing",
756 + "tracing-subscriber",
757 +]
758 +
759 +[[package]]
760 +name = "lru-slab"
761 +version = "0.1.2"
762 +source = "registry+https://github.com/rust-lang/crates.io-index"
763 +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
764 +
765 +[[package]]
766 +name = "magnus"
767 +version = "0.7.1"
768 +source = "registry+https://github.com/rust-lang/crates.io-index"
769 +checksum = "3d87ae53030f3a22e83879e666cb94e58a7bdf31706878a0ba48752994146dab"
770 +dependencies = [
771 + "magnus-macros",
772 + "rb-sys",
773 + "rb-sys-env",
774 + "seq-macro",
775 +]
776 +
777 +[[package]]
778 +name = "magnus-macros"
779 +version = "0.6.0"
780 +source = "registry+https://github.com/rust-lang/crates.io-index"
781 +checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3"
782 +dependencies = [
783 + "proc-macro2",
784 + "quote",
785 + "syn 2.0.118",
786 +]
787 +
788 +[[package]]
789 +name = "maplit"
790 +version = "1.0.2"
791 +source = "registry+https://github.com/rust-lang/crates.io-index"
792 +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
793 +
794 +[[package]]
795 +name = "matchers"
796 +version = "0.2.0"
797 +source = "registry+https://github.com/rust-lang/crates.io-index"
798 +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
799 +dependencies = [
800 + "regex-automata",
801 +]
802 +
803 +[[package]]
804 +name = "memchr"
805 +version = "2.8.2"
806 +source = "registry+https://github.com/rust-lang/crates.io-index"
807 +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
808 +
809 +[[package]]
810 +name = "minimal-lexical"
811 +version = "0.2.1"
812 +source = "registry+https://github.com/rust-lang/crates.io-index"
813 +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
814 +
815 +[[package]]
816 +name = "mio"
817 +version = "1.2.1"
818 +source = "registry+https://github.com/rust-lang/crates.io-index"
819 +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
820 +dependencies = [
821 + "libc",
822 + "wasi",
823 + "windows-sys 0.61.2",
824 +]
825 +
826 +[[package]]
827 +name = "nom"
828 +version = "7.1.3"
829 +source = "registry+https://github.com/rust-lang/crates.io-index"
830 +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
831 +dependencies = [
832 + "memchr",
833 + "minimal-lexical",
834 +]
835 +
836 +[[package]]
837 +name = "nu-ansi-term"
838 +version = "0.50.3"
839 +source = "registry+https://github.com/rust-lang/crates.io-index"
840 +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
841 +dependencies = [
842 + "windows-sys 0.61.2",
843 +]
844 +
845 +[[package]]
846 +name = "num-traits"
847 +version = "0.2.19"
848 +source = "registry+https://github.com/rust-lang/crates.io-index"
849 +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
850 +dependencies = [
851 + "autocfg",
852 +]
853 +
854 +[[package]]
855 +name = "once_cell"
856 +version = "1.21.4"
857 +source = "registry+https://github.com/rust-lang/crates.io-index"
858 +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
859 +
860 +[[package]]
861 +name = "once_cell_polyfill"
862 +version = "1.70.2"
863 +source = "registry+https://github.com/rust-lang/crates.io-index"
864 +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
865 +
866 +[[package]]
867 +name = "openssl-probe"
868 +version = "0.2.1"
869 +source = "registry+https://github.com/rust-lang/crates.io-index"
870 +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
871 +
872 +[[package]]
873 +name = "percent-encoding"
874 +version = "2.3.2"
875 +source = "registry+https://github.com/rust-lang/crates.io-index"
876 +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
877 +
878 +[[package]]
879 +name = "pin-project-lite"
880 +version = "0.2.17"
881 +source = "registry+https://github.com/rust-lang/crates.io-index"
882 +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
883 +
884 +[[package]]
885 +name = "potential_utf"
886 +version = "0.1.5"
887 +source = "registry+https://github.com/rust-lang/crates.io-index"
888 +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
889 +dependencies = [
890 + "zerovec",
891 +]
892 +
893 +[[package]]
894 +name = "ppv-lite86"
895 +version = "0.2.21"
896 +source = "registry+https://github.com/rust-lang/crates.io-index"
897 +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
898 +dependencies = [
899 + "zerocopy",
900 +]
901 +
902 +[[package]]
903 +name = "proc-macro-error"
904 +version = "1.0.4"
905 +source = "registry+https://github.com/rust-lang/crates.io-index"
906 +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
907 +dependencies = [
908 + "proc-macro-error-attr",
909 + "proc-macro2",
910 + "quote",
911 + "syn 1.0.109",
912 + "version_check",
913 +]
914 +
915 +[[package]]
916 +name = "proc-macro-error-attr"
917 +version = "1.0.4"
918 +source = "registry+https://github.com/rust-lang/crates.io-index"
919 +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
920 +dependencies = [
921 + "proc-macro2",
922 + "quote",
923 + "version_check",
924 +]
925 +
926 +[[package]]
927 +name = "proc-macro2"
928 +version = "1.0.106"
929 +source = "registry+https://github.com/rust-lang/crates.io-index"
930 +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
931 +dependencies = [
932 + "unicode-ident",
933 +]
934 +
935 +[[package]]
936 +name = "quinn"
937 +version = "0.11.11"
938 +source = "registry+https://github.com/rust-lang/crates.io-index"
939 +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8"
940 +dependencies = [
941 + "bytes",
942 + "cfg_aliases",
943 + "pin-project-lite",
944 + "quinn-proto",
945 + "quinn-udp",
946 + "rustc-hash",
947 + "rustls",
948 + "socket2",
949 + "thiserror",
950 + "tokio",
951 + "tracing",
952 + "web-time",
953 +]
954 +
955 +[[package]]
956 +name = "quinn-proto"
957 +version = "0.11.15"
958 +source = "registry+https://github.com/rust-lang/crates.io-index"
959 +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
960 +dependencies = [
961 + "bytes",
962 + "getrandom 0.3.4",
963 + "lru-slab",
964 + "rand",
965 + "ring",
966 + "rustc-hash",
967 + "rustls",
968 + "rustls-pki-types",
969 + "slab",
970 + "thiserror",
971 + "tinyvec",
972 + "tracing",
973 + "web-time",
974 +]
975 +
976 +[[package]]
977 +name = "quinn-udp"
978 +version = "0.5.14"
979 +source = "registry+https://github.com/rust-lang/crates.io-index"
980 +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
981 +dependencies = [
982 + "cfg_aliases",
983 + "libc",
984 + "once_cell",
985 + "socket2",
986 + "tracing",
987 + "windows-sys 0.60.2",
988 +]
989 +
990 +[[package]]
991 +name = "quote"
992 +version = "1.0.46"
993 +source = "registry+https://github.com/rust-lang/crates.io-index"
994 +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
995 +dependencies = [
996 + "proc-macro2",
997 +]
998 +
999 +[[package]]
1000 +name = "r-efi"
1001 +version = "5.3.0"
1002 +source = "registry+https://github.com/rust-lang/crates.io-index"
1003 +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
1004 +
1005 +[[package]]
1006 +name = "rand"
1007 +version = "0.9.4"
1008 +source = "registry+https://github.com/rust-lang/crates.io-index"
1009 +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
1010 +dependencies = [
1011 + "rand_chacha",
1012 + "rand_core",
1013 +]
1014 +
1015 +[[package]]
1016 +name = "rand_chacha"
1017 +version = "0.9.0"
1018 +source = "registry+https://github.com/rust-lang/crates.io-index"
1019 +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
1020 +dependencies = [
1021 + "ppv-lite86",
1022 + "rand_core",
1023 +]
1024 +
1025 +[[package]]
1026 +name = "rand_core"
1027 +version = "0.9.5"
1028 +source = "registry+https://github.com/rust-lang/crates.io-index"
1029 +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
1030 +dependencies = [
1031 + "getrandom 0.3.4",
1032 +]
1033 +
1034 +[[package]]
1035 +name = "rb-sys"
1036 +version = "0.9.128"
1037 +source = "registry+https://github.com/rust-lang/crates.io-index"
1038 +checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
1039 +dependencies = [
1040 + "rb-sys-build",
1041 +]
1042 +
1043 +[[package]]
1044 +name = "rb-sys-build"
1045 +version = "0.9.128"
1046 +source = "registry+https://github.com/rust-lang/crates.io-index"
1047 +checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
1048 +dependencies = [
1049 + "bindgen",
1050 + "lazy_static",
1051 + "proc-macro2",
1052 + "quote",
1053 + "regex",
1054 + "shell-words",
1055 + "syn 2.0.118",
1056 +]
1057 +
1058 +[[package]]
1059 +name = "rb-sys-env"
1060 +version = "0.1.2"
1061 +source = "registry+https://github.com/rust-lang/crates.io-index"
1062 +checksum = "a35802679f07360454b418a5d1735c89716bde01d35b1560fc953c1415a0b3bb"
1063 +
1064 +[[package]]
1065 +name = "regex"
1066 +version = "1.12.4"
1067 +source = "registry+https://github.com/rust-lang/crates.io-index"
1068 +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
1069 +dependencies = [
1070 + "aho-corasick",
1071 + "memchr",
1072 + "regex-automata",
1073 + "regex-syntax",
1074 +]
1075 +
1076 +[[package]]
1077 +name = "regex-automata"
1078 +version = "0.4.14"
1079 +source = "registry+https://github.com/rust-lang/crates.io-index"
1080 +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
1081 +dependencies = [
1082 + "aho-corasick",
1083 + "memchr",
1084 + "regex-syntax",
1085 +]
1086 +
1087 +[[package]]
1088 +name = "regex-syntax"
1089 +version = "0.8.11"
1090 +source = "registry+https://github.com/rust-lang/crates.io-index"
1091 +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
1092 +
1093 +[[package]]
1094 +name = "reqwest"
1095 +version = "0.12.28"
1096 +source = "registry+https://github.com/rust-lang/crates.io-index"
1097 +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
1098 +dependencies = [
1099 + "base64",
1100 + "bytes",
1101 + "futures-core",
1102 + "http",
1103 + "http-body",
1104 + "http-body-util",
1105 + "hyper",
1106 + "hyper-rustls",
1107 + "hyper-util",
1108 + "js-sys",
1109 + "log",
1110 + "percent-encoding",
1111 + "pin-project-lite",
1112 + "quinn",
1113 + "rustls",
1114 + "rustls-native-certs",
1115 + "rustls-pki-types",
1116 + "serde",
1117 + "serde_json",
1118 + "serde_urlencoded",
1119 + "sync_wrapper",
1120 + "tokio",
1121 + "tokio-rustls",
1122 + "tower",
1123 + "tower-http",
1124 + "tower-service",
1125 + "url",
1126 + "wasm-bindgen",
1127 + "wasm-bindgen-futures",
1128 + "web-sys",
1129 + "webpki-roots",
1130 +]
1131 +
1132 +[[package]]
1133 +name = "ring"
1134 +version = "0.17.14"
1135 +source = "registry+https://github.com/rust-lang/crates.io-index"
1136 +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
1137 +dependencies = [
1138 + "cc",
1139 + "cfg-if",
1140 + "getrandom 0.2.17",
1141 + "libc",
1142 + "untrusted",
1143 + "windows-sys 0.52.0",
1144 +]
1145 +
1146 +[[package]]
1147 +name = "rustc-hash"
1148 +version = "2.1.2"
1149 +source = "registry+https://github.com/rust-lang/crates.io-index"
1150 +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
1151 +
1152 +[[package]]
1153 +name = "rustls"
1154 +version = "0.23.41"
1155 +source = "registry+https://github.com/rust-lang/crates.io-index"
1156 +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f"
1157 +dependencies = [
1158 + "once_cell",
1159 + "ring",
1160 + "rustls-pki-types",
1161 + "rustls-webpki",
1162 + "subtle",
1163 + "zeroize",
1164 +]
1165 +
1166 +[[package]]
1167 +name = "rustls-native-certs"
1168 +version = "0.8.4"
1169 +source = "registry+https://github.com/rust-lang/crates.io-index"
1170 +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
1171 +dependencies = [
1172 + "openssl-probe",
1173 + "rustls-pki-types",
1174 + "schannel",
1175 + "security-framework",
1176 +]
1177 +
1178 +[[package]]
1179 +name = "rustls-pki-types"
1180 +version = "1.14.1"
1181 +source = "registry+https://github.com/rust-lang/crates.io-index"
1182 +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
1183 +dependencies = [
1184 + "web-time",
1185 + "zeroize",
1186 +]
1187 +
1188 +[[package]]
1189 +name = "rustls-webpki"
1190 +version = "0.103.13"
1191 +source = "registry+https://github.com/rust-lang/crates.io-index"
1192 +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
1193 +dependencies = [
1194 + "ring",
1195 + "rustls-pki-types",
1196 + "untrusted",
1197 +]
1198 +
1199 +[[package]]
1200 +name = "rustversion"
1201 +version = "1.0.22"
1202 +source = "registry+https://github.com/rust-lang/crates.io-index"
1203 +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
1204 +
1205 +[[package]]
1206 +name = "ryu"
1207 +version = "1.0.23"
1208 +source = "registry+https://github.com/rust-lang/crates.io-index"
1209 +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
1210 +
1211 +[[package]]
1212 +name = "same-file"
1213 +version = "1.0.6"
1214 +source = "registry+https://github.com/rust-lang/crates.io-index"
1215 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1216 +dependencies = [
1217 + "winapi-util",
1218 +]
1219 +
1220 +[[package]]
1221 +name = "schannel"
1222 +version = "0.1.29"
1223 +source = "registry+https://github.com/rust-lang/crates.io-index"
1224 +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
1225 +dependencies = [
1226 + "windows-sys 0.61.2",
1227 +]
1228 +
1229 +[[package]]
1230 +name = "scoped-tls"
1231 +version = "1.0.1"
1232 +source = "registry+https://github.com/rust-lang/crates.io-index"
1233 +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
1234 +
1235 +[[package]]
1236 +name = "security-framework"
1237 +version = "3.7.0"
1238 +source = "registry+https://github.com/rust-lang/crates.io-index"
1239 +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
1240 +dependencies = [
1241 + "bitflags 2.13.0",
1242 + "core-foundation",
1243 + "core-foundation-sys",
1244 + "libc",
1245 + "security-framework-sys",
1246 +]
1247 +
1248 +[[package]]
1249 +name = "security-framework-sys"
1250 +version = "2.17.0"
1251 +source = "registry+https://github.com/rust-lang/crates.io-index"
1252 +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
1253 +dependencies = [
1254 + "core-foundation-sys",
1255 + "libc",
1256 +]
1257 +
1258 +[[package]]
1259 +name = "seq-macro"
1260 +version = "0.3.6"
1261 +source = "registry+https://github.com/rust-lang/crates.io-index"
1262 +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
1263 +
1264 +[[package]]
1265 +name = "serde"
1266 +version = "1.0.228"
1267 +source = "registry+https://github.com/rust-lang/crates.io-index"
1268 +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1269 +dependencies = [
1270 + "serde_core",
1271 + "serde_derive",
1272 +]
1273 +
1274 +[[package]]
1275 +name = "serde_core"
1276 +version = "1.0.228"
1277 +source = "registry+https://github.com/rust-lang/crates.io-index"
1278 +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1279 +dependencies = [
1280 + "serde_derive",
1281 +]
1282 +
1283 +[[package]]
1284 +name = "serde_derive"
1285 +version = "1.0.228"
1286 +source = "registry+https://github.com/rust-lang/crates.io-index"
1287 +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1288 +dependencies = [
1289 + "proc-macro2",
1290 + "quote",
1291 + "syn 2.0.118",
1292 +]
1293 +
1294 +[[package]]
1295 +name = "serde_json"
1296 +version = "1.0.150"
1297 +source = "registry+https://github.com/rust-lang/crates.io-index"
1298 +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
1299 +dependencies = [
1300 + "itoa",
1301 + "memchr",
1302 + "serde",
1303 + "serde_core",
1304 + "zmij",
1305 +]
1306 +
1307 +[[package]]
1308 +name = "serde_repr"
1309 +version = "0.1.20"
1310 +source = "registry+https://github.com/rust-lang/crates.io-index"
1311 +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
1312 +dependencies = [
1313 + "proc-macro2",
1314 + "quote",
1315 + "syn 2.0.118",
1316 +]
1317 +
1318 +[[package]]
1319 +name = "serde_urlencoded"
1320 +version = "0.7.1"
1321 +source = "registry+https://github.com/rust-lang/crates.io-index"
1322 +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1323 +dependencies = [
1324 + "form_urlencoded",
1325 + "itoa",
1326 + "ryu",
1327 + "serde",
1328 +]
1329 +
1330 +[[package]]
1331 +name = "sharded-slab"
1332 +version = "0.1.7"
1333 +source = "registry+https://github.com/rust-lang/crates.io-index"
1334 +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
1335 +dependencies = [
1336 + "lazy_static",
1337 +]
1338 +
1339 +[[package]]
1340 +name = "shell-words"
1341 +version = "1.1.1"
1342 +source = "registry+https://github.com/rust-lang/crates.io-index"
1343 +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77"
1344 +
1345 +[[package]]
1346 +name = "shlex"
1347 +version = "1.3.0"
1348 +source = "registry+https://github.com/rust-lang/crates.io-index"
1349 +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1350 +
1351 +[[package]]
1352 +name = "shlex"
1353 +version = "2.0.1"
1354 +source = "registry+https://github.com/rust-lang/crates.io-index"
1355 +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
1356 +
1357 +[[package]]
1358 +name = "slab"
1359 +version = "0.4.12"
1360 +source = "registry+https://github.com/rust-lang/crates.io-index"
1361 +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
1362 +
1363 +[[package]]
1364 +name = "smallvec"
1365 +version = "1.15.2"
1366 +source = "registry+https://github.com/rust-lang/crates.io-index"
1367 +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
1368 +
1369 +[[package]]
1370 +name = "smbcloud-email-sdk"
1371 +version = "0.4.7"
1372 +dependencies = [
1373 + "log",
1374 + "reqwest",
1375 + "serde",
1376 + "serde_json",
1377 + "serde_repr",
1378 + "smbcloud-network",
1379 + "thiserror",
1380 + "tokio",
1381 +]
1382 +
1383 +[[package]]
1384 +name = "smbcloud-model"
1385 +version = "0.4.7"
1386 +dependencies = [
1387 + "chrono",
1388 + "log",
1389 + "serde",
1390 + "serde_json",
1391 + "serde_repr",
1392 + "spinners",
1393 + "strum 0.27.2",
1394 + "strum_macros 0.27.2",
1395 + "thiserror",
1396 + "tsync",
1397 +]
1398 +
1399 +[[package]]
1400 +name = "smbcloud-network"
1401 +version = "0.4.7"
1402 +dependencies = [
1403 + "clap 4.6.1",
1404 + "log",
1405 + "reqwest",
1406 + "serde",
1407 + "serde_json",
1408 + "smbcloud-model",
1409 + "wasm-bindgen",
1410 +]
1411 +
1412 +[[package]]
1413 +name = "socket2"
1414 +version = "0.6.4"
1415 +source = "registry+https://github.com/rust-lang/crates.io-index"
1416 +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
1417 +dependencies = [
1418 + "libc",
1419 + "windows-sys 0.61.2",
1420 +]
1421 +
1422 +[[package]]
1423 +name = "spinners"
1424 +version = "4.2.0"
1425 +source = "registry+https://github.com/rust-lang/crates.io-index"
1426 +checksum = "071af1a9d34b78b8db3ca4424b0ea4d87052d607dbe96287aebaccd596cabc86"
1427 +dependencies = [
1428 + "lazy_static",
1429 + "maplit",
1430 + "strum 0.24.1",
1431 +]
1432 +
1433 +[[package]]
1434 +name = "stable_deref_trait"
1435 +version = "1.2.1"
1436 +source = "registry+https://github.com/rust-lang/crates.io-index"
1437 +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
1438 +
1439 +[[package]]
1440 +name = "state"
1441 +version = "0.6.0"
1442 +source = "registry+https://github.com/rust-lang/crates.io-index"
1443 +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8"
1444 +dependencies = [
1445 + "loom",
1446 +]
1447 +
1448 +[[package]]
1449 +name = "strsim"
1450 +version = "0.8.0"
1451 +source = "registry+https://github.com/rust-lang/crates.io-index"
1452 +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
1453 +
1454 +[[package]]
1455 +name = "strsim"
1456 +version = "0.11.1"
1457 +source = "registry+https://github.com/rust-lang/crates.io-index"
1458 +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1459 +
1460 +[[package]]
1461 +name = "structopt"
1462 +version = "0.3.26"
1463 +source = "registry+https://github.com/rust-lang/crates.io-index"
1464 +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
1465 +dependencies = [
1466 + "clap 2.34.0",
1467 + "lazy_static",
1468 + "structopt-derive",
1469 +]
1470 +
1471 +[[package]]
1472 +name = "structopt-derive"
1473 +version = "0.4.18"
1474 +source = "registry+https://github.com/rust-lang/crates.io-index"
1475 +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
1476 +dependencies = [
1477 + "heck 0.3.3",
1478 + "proc-macro-error",
1479 + "proc-macro2",
1480 + "quote",
1481 + "syn 1.0.109",
1482 +]
1483 +
1484 +[[package]]
1485 +name = "strum"
1486 +version = "0.24.1"
1487 +source = "registry+https://github.com/rust-lang/crates.io-index"
1488 +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
1489 +dependencies = [
1490 + "strum_macros 0.24.3",
1491 +]
1492 +
1493 +[[package]]
1494 +name = "strum"
1495 +version = "0.27.2"
1496 +source = "registry+https://github.com/rust-lang/crates.io-index"
1497 +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
1498 +
1499 +[[package]]
1500 +name = "strum_macros"
1501 +version = "0.24.3"
1502 +source = "registry+https://github.com/rust-lang/crates.io-index"
1503 +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
1504 +dependencies = [
1505 + "heck 0.4.1",
1506 + "proc-macro2",
1507 + "quote",
1508 + "rustversion",
1509 + "syn 1.0.109",
1510 +]
1511 +
1512 +[[package]]
1513 +name = "strum_macros"
1514 +version = "0.27.2"
1515 +source = "registry+https://github.com/rust-lang/crates.io-index"
1516 +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
1517 +dependencies = [
1518 + "heck 0.5.0",
1519 + "proc-macro2",
1520 + "quote",
1521 + "syn 2.0.118",
1522 +]
1523 +
1524 +[[package]]
1525 +name = "subtle"
1526 +version = "2.6.1"
1527 +source = "registry+https://github.com/rust-lang/crates.io-index"
1528 +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
1529 +
1530 +[[package]]
1531 +name = "syn"
1532 +version = "1.0.109"
1533 +source = "registry+https://github.com/rust-lang/crates.io-index"
1534 +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
1535 +dependencies = [
1536 + "proc-macro2",
1537 + "quote",
1538 + "unicode-ident",
1539 +]
1540 +
1541 +[[package]]
1542 +name = "syn"
1543 +version = "2.0.118"
1544 +source = "registry+https://github.com/rust-lang/crates.io-index"
1545 +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
1546 +dependencies = [
1547 + "proc-macro2",
1548 + "quote",
1549 + "unicode-ident",
1550 +]
1551 +
1552 +[[package]]
1553 +name = "sync_wrapper"
1554 +version = "1.0.2"
1555 +source = "registry+https://github.com/rust-lang/crates.io-index"
1556 +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
1557 +dependencies = [
1558 + "futures-core",
1559 +]
1560 +
1561 +[[package]]
1562 +name = "synstructure"
1563 +version = "0.13.2"
1564 +source = "registry+https://github.com/rust-lang/crates.io-index"
1565 +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
1566 +dependencies = [
1567 + "proc-macro2",
1568 + "quote",
1569 + "syn 2.0.118",
1570 +]
1571 +
1572 +[[package]]
1573 +name = "textwrap"
1574 +version = "0.11.0"
1575 +source = "registry+https://github.com/rust-lang/crates.io-index"
1576 +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1577 +dependencies = [
1578 + "unicode-width",
1579 +]
1580 +
1581 +[[package]]
1582 +name = "thiserror"
1583 +version = "2.0.18"
1584 +source = "registry+https://github.com/rust-lang/crates.io-index"
1585 +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
1586 +dependencies = [
1587 + "thiserror-impl",
1588 +]
1589 +
1590 +[[package]]
1591 +name = "thiserror-impl"
1592 +version = "2.0.18"
1593 +source = "registry+https://github.com/rust-lang/crates.io-index"
1594 +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
1595 +dependencies = [
1596 + "proc-macro2",
1597 + "quote",
1598 + "syn 2.0.118",
1599 +]
1600 +
1601 +[[package]]
1602 +name = "thread_local"
1603 +version = "1.1.9"
1604 +source = "registry+https://github.com/rust-lang/crates.io-index"
1605 +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
1606 +dependencies = [
1607 + "cfg-if",
1608 +]
1609 +
1610 +[[package]]
1611 +name = "tinystr"
1612 +version = "0.8.3"
1613 +source = "registry+https://github.com/rust-lang/crates.io-index"
1614 +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
1615 +dependencies = [
1616 + "displaydoc",
1617 + "zerovec",
1618 +]
1619 +
1620 +[[package]]
1621 +name = "tinyvec"
1622 +version = "1.11.0"
1623 +source = "registry+https://github.com/rust-lang/crates.io-index"
1624 +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
1625 +dependencies = [
1626 + "tinyvec_macros",
1627 +]
1628 +
1629 +[[package]]
1630 +name = "tinyvec_macros"
1631 +version = "0.1.1"
1632 +source = "registry+https://github.com/rust-lang/crates.io-index"
1633 +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
1634 +
1635 +[[package]]
1636 +name = "tokio"
1637 +version = "1.52.3"
1638 +source = "registry+https://github.com/rust-lang/crates.io-index"
1639 +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
1640 +dependencies = [
1641 + "bytes",
1642 + "libc",
1643 + "mio",
1644 + "pin-project-lite",
1645 + "socket2",
1646 + "windows-sys 0.61.2",
1647 +]
1648 +
1649 +[[package]]
1650 +name = "tokio-rustls"
1651 +version = "0.26.4"
1652 +source = "registry+https://github.com/rust-lang/crates.io-index"
1653 +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
1654 +dependencies = [
1655 + "rustls",
1656 + "tokio",
1657 +]
1658 +
1659 +[[package]]
1660 +name = "tower"
1661 +version = "0.5.3"
1662 +source = "registry+https://github.com/rust-lang/crates.io-index"
1663 +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
1664 +dependencies = [
1665 + "futures-core",
1666 + "futures-util",
1667 + "pin-project-lite",
1668 + "sync_wrapper",
1669 + "tokio",
1670 + "tower-layer",
1671 + "tower-service",
1672 +]
1673 +
1674 +[[package]]
1675 +name = "tower-http"
1676 +version = "0.6.11"
1677 +source = "registry+https://github.com/rust-lang/crates.io-index"
1678 +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
1679 +dependencies = [
1680 + "bitflags 2.13.0",
1681 + "bytes",
1682 + "futures-util",
1683 + "http",
1684 + "http-body",
1685 + "pin-project-lite",
1686 + "tower",
1687 + "tower-layer",
1688 + "tower-service",
1689 + "url",
1690 +]
1691 +
1692 +[[package]]
1693 +name = "tower-layer"
1694 +version = "0.3.3"
1695 +source = "registry+https://github.com/rust-lang/crates.io-index"
1696 +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
1697 +
1698 +[[package]]
1699 +name = "tower-service"
1700 +version = "0.3.3"
1701 +source = "registry+https://github.com/rust-lang/crates.io-index"
1702 +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
1703 +
1704 +[[package]]
1705 +name = "tracing"
1706 +version = "0.1.44"
1707 +source = "registry+https://github.com/rust-lang/crates.io-index"
1708 +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
1709 +dependencies = [
1710 + "pin-project-lite",
1711 + "tracing-attributes",
1712 + "tracing-core",
1713 +]
1714 +
1715 +[[package]]
1716 +name = "tracing-attributes"
1717 +version = "0.1.31"
1718 +source = "registry+https://github.com/rust-lang/crates.io-index"
1719 +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
1720 +dependencies = [
1721 + "proc-macro2",
1722 + "quote",
1723 + "syn 2.0.118",
1724 +]
1725 +
1726 +[[package]]
1727 +name = "tracing-core"
1728 +version = "0.1.36"
1729 +source = "registry+https://github.com/rust-lang/crates.io-index"
1730 +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
1731 +dependencies = [
1732 + "once_cell",
1733 + "valuable",
1734 +]
1735 +
1736 +[[package]]
1737 +name = "tracing-log"
1738 +version = "0.2.0"
1739 +source = "registry+https://github.com/rust-lang/crates.io-index"
1740 +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
1741 +dependencies = [
1742 + "log",
1743 + "once_cell",
1744 + "tracing-core",
1745 +]
1746 +
1747 +[[package]]
1748 +name = "tracing-subscriber"
1749 +version = "0.3.23"
1750 +source = "registry+https://github.com/rust-lang/crates.io-index"
1751 +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
1752 +dependencies = [
1753 + "matchers",
1754 + "nu-ansi-term",
1755 + "once_cell",
1756 + "regex-automata",
1757 + "sharded-slab",
1758 + "smallvec",
1759 + "thread_local",
1760 + "tracing",
1761 + "tracing-core",
1762 + "tracing-log",
1763 +]
1764 +
1765 +[[package]]
1766 +name = "try-lock"
1767 +version = "0.2.5"
1768 +source = "registry+https://github.com/rust-lang/crates.io-index"
1769 +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
1770 +
1771 +[[package]]
1772 +name = "tsync"
1773 +version = "2.2.1"
1774 +source = "registry+https://github.com/rust-lang/crates.io-index"
1775 +checksum = "4fc20a25899c5ae43735253244214f3d5eb75dd28d9cc8491732294a985adb8c"
1776 +dependencies = [
1777 + "convert_case",
1778 + "proc-macro2",
1779 + "quote",
1780 + "state",
1781 + "structopt",
1782 + "syn 2.0.118",
1783 + "tsync-macro",
1784 + "walkdir",
1785 +]
1786 +
1787 +[[package]]
1788 +name = "tsync-macro"
1789 +version = "0.1.0"
1790 +source = "registry+https://github.com/rust-lang/crates.io-index"
1791 +checksum = "8acc9e35a3072d9ea375093f321b3738ea3ac4fdebc18d2789b01581e5c2e4ae"
1792 +
1793 +[[package]]
1794 +name = "unicode-ident"
1795 +version = "1.0.24"
1796 +source = "registry+https://github.com/rust-lang/crates.io-index"
1797 +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
1798 +
1799 +[[package]]
1800 +name = "unicode-segmentation"
1801 +version = "1.13.3"
1802 +source = "registry+https://github.com/rust-lang/crates.io-index"
1803 +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
1804 +
1805 +[[package]]
1806 +name = "unicode-width"
1807 +version = "0.1.14"
1808 +source = "registry+https://github.com/rust-lang/crates.io-index"
1809 +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
1810 +
1811 +[[package]]
1812 +name = "untrusted"
1813 +version = "0.9.0"
1814 +source = "registry+https://github.com/rust-lang/crates.io-index"
1815 +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
1816 +
1817 +[[package]]
1818 +name = "url"
1819 +version = "2.5.8"
1820 +source = "registry+https://github.com/rust-lang/crates.io-index"
1821 +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
1822 +dependencies = [
1823 + "form_urlencoded",
1824 + "idna",
1825 + "percent-encoding",
1826 + "serde",
1827 +]
1828 +
1829 +[[package]]
1830 +name = "utf8_iter"
1831 +version = "1.0.4"
1832 +source = "registry+https://github.com/rust-lang/crates.io-index"
1833 +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
1834 +
1835 +[[package]]
1836 +name = "utf8parse"
1837 +version = "0.2.2"
1838 +source = "registry+https://github.com/rust-lang/crates.io-index"
1839 +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1840 +
1841 +[[package]]
1842 +name = "valuable"
1843 +version = "0.1.1"
1844 +source = "registry+https://github.com/rust-lang/crates.io-index"
1845 +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
1846 +
1847 +[[package]]
1848 +name = "vec_map"
1849 +version = "0.8.2"
1850 +source = "registry+https://github.com/rust-lang/crates.io-index"
1851 +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1852 +
1853 +[[package]]
1854 +name = "version_check"
1855 +version = "0.9.5"
1856 +source = "registry+https://github.com/rust-lang/crates.io-index"
1857 +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1858 +
1859 +[[package]]
1860 +name = "walkdir"
1861 +version = "2.5.0"
1862 +source = "registry+https://github.com/rust-lang/crates.io-index"
1863 +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
1864 +dependencies = [
1865 + "same-file",
1866 + "winapi-util",
1867 +]
1868 +
1869 +[[package]]
1870 +name = "want"
1871 +version = "0.3.1"
1872 +source = "registry+https://github.com/rust-lang/crates.io-index"
1873 +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
1874 +dependencies = [
1875 + "try-lock",
1876 +]
1877 +
1878 +[[package]]
1879 +name = "wasi"
1880 +version = "0.11.1+wasi-snapshot-preview1"
1881 +source = "registry+https://github.com/rust-lang/crates.io-index"
1882 +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
1883 +
1884 +[[package]]
1885 +name = "wasip2"
1886 +version = "1.0.4+wasi-0.2.12"
1887 +source = "registry+https://github.com/rust-lang/crates.io-index"
1888 +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
1889 +dependencies = [
1890 + "wit-bindgen",
1891 +]
1892 +
1893 +[[package]]
1894 +name = "wasm-bindgen"
1895 +version = "0.2.126"
1896 +source = "registry+https://github.com/rust-lang/crates.io-index"
1897 +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
1898 +dependencies = [
1899 + "cfg-if",
1900 + "once_cell",
1901 + "rustversion",
1902 + "wasm-bindgen-macro",
1903 + "wasm-bindgen-shared",
1904 +]
1905 +
1906 +[[package]]
1907 +name = "wasm-bindgen-futures"
1908 +version = "0.4.76"
1909 +source = "registry+https://github.com/rust-lang/crates.io-index"
1910 +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
1911 +dependencies = [
1912 + "js-sys",
1913 + "wasm-bindgen",
1914 +]
1915 +
1916 +[[package]]
1917 +name = "wasm-bindgen-macro"
1918 +version = "0.2.126"
1919 +source = "registry+https://github.com/rust-lang/crates.io-index"
1920 +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
1921 +dependencies = [
1922 + "quote",
1923 + "wasm-bindgen-macro-support",
1924 +]
1925 +
1926 +[[package]]
1927 +name = "wasm-bindgen-macro-support"
1928 +version = "0.2.126"
1929 +source = "registry+https://github.com/rust-lang/crates.io-index"
1930 +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
1931 +dependencies = [
1932 + "bumpalo",
1933 + "proc-macro2",
1934 + "quote",
1935 + "syn 2.0.118",
1936 + "wasm-bindgen-shared",
1937 +]
1938 +
1939 +[[package]]
1940 +name = "wasm-bindgen-shared"
1941 +version = "0.2.126"
1942 +source = "registry+https://github.com/rust-lang/crates.io-index"
1943 +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
1944 +dependencies = [
1945 + "unicode-ident",
1946 +]
1947 +
1948 +[[package]]
1949 +name = "web-sys"
1950 +version = "0.3.103"
1951 +source = "registry+https://github.com/rust-lang/crates.io-index"
1952 +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
1953 +dependencies = [
1954 + "js-sys",
1955 + "wasm-bindgen",
1956 +]
1957 +
1958 +[[package]]
1959 +name = "web-time"
1960 +version = "1.1.0"
1961 +source = "registry+https://github.com/rust-lang/crates.io-index"
1962 +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
1963 +dependencies = [
1964 + "js-sys",
1965 + "wasm-bindgen",
1966 +]
1967 +
1968 +[[package]]
1969 +name = "webpki-roots"
1970 +version = "1.0.8"
1971 +source = "registry+https://github.com/rust-lang/crates.io-index"
1972 +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf"
1973 +dependencies = [
1974 + "rustls-pki-types",
1975 +]
1976 +
1977 +[[package]]
1978 +name = "winapi"
1979 +version = "0.3.9"
1980 +source = "registry+https://github.com/rust-lang/crates.io-index"
1981 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1982 +dependencies = [
1983 + "winapi-i686-pc-windows-gnu",
1984 + "winapi-x86_64-pc-windows-gnu",
1985 +]
1986 +
1987 +[[package]]
1988 +name = "winapi-i686-pc-windows-gnu"
1989 +version = "0.4.0"
1990 +source = "registry+https://github.com/rust-lang/crates.io-index"
1991 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1992 +
1993 +[[package]]
1994 +name = "winapi-util"
1995 +version = "0.1.11"
1996 +source = "registry+https://github.com/rust-lang/crates.io-index"
1997 +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
1998 +dependencies = [
1999 + "windows-sys 0.61.2",
2000 +]
2001 +
2002 +[[package]]
2003 +name = "winapi-x86_64-pc-windows-gnu"
2004 +version = "0.4.0"
2005 +source = "registry+https://github.com/rust-lang/crates.io-index"
2006 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2007 +
2008 +[[package]]
2009 +name = "windows"
2010 +version = "0.48.0"
2011 +source = "registry+https://github.com/rust-lang/crates.io-index"
2012 +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
2013 +dependencies = [
2014 + "windows-targets 0.48.5",
2015 +]
2016 +
2017 +[[package]]
2018 +name = "windows-core"
2019 +version = "0.62.2"
2020 +source = "registry+https://github.com/rust-lang/crates.io-index"
2021 +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
2022 +dependencies = [
2023 + "windows-implement",
2024 + "windows-interface",
2025 + "windows-link",
2026 + "windows-result",
2027 + "windows-strings",
2028 +]
2029 +
2030 +[[package]]
2031 +name = "windows-implement"
2032 +version = "0.60.2"
2033 +source = "registry+https://github.com/rust-lang/crates.io-index"
2034 +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
2035 +dependencies = [
2036 + "proc-macro2",
2037 + "quote",
2038 + "syn 2.0.118",
2039 +]
2040 +
2041 +[[package]]
2042 +name = "windows-interface"
2043 +version = "0.59.3"
2044 +source = "registry+https://github.com/rust-lang/crates.io-index"
2045 +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
2046 +dependencies = [
2047 + "proc-macro2",
2048 + "quote",
2049 + "syn 2.0.118",
2050 +]
2051 +
2052 +[[package]]
2053 +name = "windows-link"
2054 +version = "0.2.1"
2055 +source = "registry+https://github.com/rust-lang/crates.io-index"
2056 +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
2057 +
2058 +[[package]]
2059 +name = "windows-result"
2060 +version = "0.4.1"
2061 +source = "registry+https://github.com/rust-lang/crates.io-index"
2062 +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
2063 +dependencies = [
2064 + "windows-link",
2065 +]
2066 +
2067 +[[package]]
2068 +name = "windows-strings"
2069 +version = "0.5.1"
2070 +source = "registry+https://github.com/rust-lang/crates.io-index"
2071 +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
2072 +dependencies = [
2073 + "windows-link",
2074 +]
2075 +
2076 +[[package]]
2077 +name = "windows-sys"
2078 +version = "0.52.0"
2079 +source = "registry+https://github.com/rust-lang/crates.io-index"
2080 +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
2081 +dependencies = [
2082 + "windows-targets 0.52.6",
2083 +]
2084 +
2085 +[[package]]
2086 +name = "windows-sys"
2087 +version = "0.60.2"
2088 +source = "registry+https://github.com/rust-lang/crates.io-index"
2089 +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
2090 +dependencies = [
2091 + "windows-targets 0.53.5",
2092 +]
2093 +
2094 +[[package]]
2095 +name = "windows-sys"
2096 +version = "0.61.2"
2097 +source = "registry+https://github.com/rust-lang/crates.io-index"
2098 +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
2099 +dependencies = [
2100 + "windows-link",
2101 +]
2102 +
2103 +[[package]]
2104 +name = "windows-targets"
2105 +version = "0.48.5"
2106 +source = "registry+https://github.com/rust-lang/crates.io-index"
2107 +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
2108 +dependencies = [
2109 + "windows_aarch64_gnullvm 0.48.5",
2110 + "windows_aarch64_msvc 0.48.5",
2111 + "windows_i686_gnu 0.48.5",
2112 + "windows_i686_msvc 0.48.5",
2113 + "windows_x86_64_gnu 0.48.5",
2114 + "windows_x86_64_gnullvm 0.48.5",
2115 + "windows_x86_64_msvc 0.48.5",
2116 +]
2117 +
2118 +[[package]]
2119 +name = "windows-targets"
2120 +version = "0.52.6"
2121 +source = "registry+https://github.com/rust-lang/crates.io-index"
2122 +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
2123 +dependencies = [
2124 + "windows_aarch64_gnullvm 0.52.6",
2125 + "windows_aarch64_msvc 0.52.6",
2126 + "windows_i686_gnu 0.52.6",
2127 + "windows_i686_gnullvm 0.52.6",
2128 + "windows_i686_msvc 0.52.6",
2129 + "windows_x86_64_gnu 0.52.6",
2130 + "windows_x86_64_gnullvm 0.52.6",
2131 + "windows_x86_64_msvc 0.52.6",
2132 +]
2133 +
2134 +[[package]]
2135 +name = "windows-targets"
2136 +version = "0.53.5"
2137 +source = "registry+https://github.com/rust-lang/crates.io-index"
2138 +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
2139 +dependencies = [
2140 + "windows-link",
2141 + "windows_aarch64_gnullvm 0.53.1",
2142 + "windows_aarch64_msvc 0.53.1",
2143 + "windows_i686_gnu 0.53.1",
2144 + "windows_i686_gnullvm 0.53.1",
2145 + "windows_i686_msvc 0.53.1",
2146 + "windows_x86_64_gnu 0.53.1",
2147 + "windows_x86_64_gnullvm 0.53.1",
2148 + "windows_x86_64_msvc 0.53.1",
2149 +]
2150 +
2151 +[[package]]
2152 +name = "windows_aarch64_gnullvm"
2153 +version = "0.48.5"
2154 +source = "registry+https://github.com/rust-lang/crates.io-index"
2155 +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
2156 +
2157 +[[package]]
2158 +name = "windows_aarch64_gnullvm"
2159 +version = "0.52.6"
2160 +source = "registry+https://github.com/rust-lang/crates.io-index"
2161 +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
2162 +
2163 +[[package]]
2164 +name = "windows_aarch64_gnullvm"
2165 +version = "0.53.1"
2166 +source = "registry+https://github.com/rust-lang/crates.io-index"
2167 +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
2168 +
2169 +[[package]]
2170 +name = "windows_aarch64_msvc"
2171 +version = "0.48.5"
2172 +source = "registry+https://github.com/rust-lang/crates.io-index"
2173 +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
2174 +
2175 +[[package]]
2176 +name = "windows_aarch64_msvc"
2177 +version = "0.52.6"
2178 +source = "registry+https://github.com/rust-lang/crates.io-index"
2179 +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
2180 +
2181 +[[package]]
2182 +name = "windows_aarch64_msvc"
2183 +version = "0.53.1"
2184 +source = "registry+https://github.com/rust-lang/crates.io-index"
2185 +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
2186 +
2187 +[[package]]
2188 +name = "windows_i686_gnu"
2189 +version = "0.48.5"
2190 +source = "registry+https://github.com/rust-lang/crates.io-index"
2191 +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
2192 +
2193 +[[package]]
2194 +name = "windows_i686_gnu"
2195 +version = "0.52.6"
2196 +source = "registry+https://github.com/rust-lang/crates.io-index"
2197 +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
2198 +
2199 +[[package]]
2200 +name = "windows_i686_gnu"
2201 +version = "0.53.1"
2202 +source = "registry+https://github.com/rust-lang/crates.io-index"
2203 +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
2204 +
2205 +[[package]]
2206 +name = "windows_i686_gnullvm"
2207 +version = "0.52.6"
2208 +source = "registry+https://github.com/rust-lang/crates.io-index"
2209 +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
2210 +
2211 +[[package]]
2212 +name = "windows_i686_gnullvm"
2213 +version = "0.53.1"
2214 +source = "registry+https://github.com/rust-lang/crates.io-index"
2215 +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
2216 +
2217 +[[package]]
2218 +name = "windows_i686_msvc"
2219 +version = "0.48.5"
2220 +source = "registry+https://github.com/rust-lang/crates.io-index"
2221 +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
2222 +
2223 +[[package]]
2224 +name = "windows_i686_msvc"
2225 +version = "0.52.6"
2226 +source = "registry+https://github.com/rust-lang/crates.io-index"
2227 +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
2228 +
2229 +[[package]]
2230 +name = "windows_i686_msvc"
2231 +version = "0.53.1"
2232 +source = "registry+https://github.com/rust-lang/crates.io-index"
2233 +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
2234 +
2235 +[[package]]
2236 +name = "windows_x86_64_gnu"
2237 +version = "0.48.5"
2238 +source = "registry+https://github.com/rust-lang/crates.io-index"
2239 +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
2240 +
2241 +[[package]]
2242 +name = "windows_x86_64_gnu"
2243 +version = "0.52.6"
2244 +source = "registry+https://github.com/rust-lang/crates.io-index"
2245 +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
2246 +
2247 +[[package]]
2248 +name = "windows_x86_64_gnu"
2249 +version = "0.53.1"
2250 +source = "registry+https://github.com/rust-lang/crates.io-index"
2251 +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
2252 +
2253 +[[package]]
2254 +name = "windows_x86_64_gnullvm"
2255 +version = "0.48.5"
2256 +source = "registry+https://github.com/rust-lang/crates.io-index"
2257 +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
2258 +
2259 +[[package]]
2260 +name = "windows_x86_64_gnullvm"
2261 +version = "0.52.6"
2262 +source = "registry+https://github.com/rust-lang/crates.io-index"
2263 +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
2264 +
2265 +[[package]]
2266 +name = "windows_x86_64_gnullvm"
2267 +version = "0.53.1"
2268 +source = "registry+https://github.com/rust-lang/crates.io-index"
2269 +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
2270 +
2271 +[[package]]
2272 +name = "windows_x86_64_msvc"
2273 +version = "0.48.5"
2274 +source = "registry+https://github.com/rust-lang/crates.io-index"
2275 +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
2276 +
2277 +[[package]]
2278 +name = "windows_x86_64_msvc"
2279 +version = "0.52.6"
2280 +source = "registry+https://github.com/rust-lang/crates.io-index"
2281 +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
2282 +
2283 +[[package]]
2284 +name = "windows_x86_64_msvc"
2285 +version = "0.53.1"
2286 +source = "registry+https://github.com/rust-lang/crates.io-index"
2287 +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
2288 +
2289 +[[package]]
2290 +name = "wit-bindgen"
2291 +version = "0.57.1"
2292 +source = "registry+https://github.com/rust-lang/crates.io-index"
2293 +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
2294 +
2295 +[[package]]
2296 +name = "writeable"
2297 +version = "0.6.3"
2298 +source = "registry+https://github.com/rust-lang/crates.io-index"
2299 +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
2300 +
2301 +[[package]]
2302 +name = "yoke"
2303 +version = "0.8.3"
2304 +source = "registry+https://github.com/rust-lang/crates.io-index"
2305 +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
2306 +dependencies = [
2307 + "stable_deref_trait",
2308 + "yoke-derive",
2309 + "zerofrom",
2310 +]
2311 +
2312 +[[package]]
2313 +name = "yoke-derive"
2314 +version = "0.8.2"
2315 +source = "registry+https://github.com/rust-lang/crates.io-index"
2316 +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
2317 +dependencies = [
2318 + "proc-macro2",
2319 + "quote",
2320 + "syn 2.0.118",
2321 + "synstructure",
2322 +]
2323 +
2324 +[[package]]
2325 +name = "zerocopy"
2326 +version = "0.8.52"
2327 +source = "registry+https://github.com/rust-lang/crates.io-index"
2328 +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
2329 +dependencies = [
2330 + "zerocopy-derive",
2331 +]
2332 +
2333 +[[package]]
2334 +name = "zerocopy-derive"
2335 +version = "0.8.52"
2336 +source = "registry+https://github.com/rust-lang/crates.io-index"
2337 +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
2338 +dependencies = [
2339 + "proc-macro2",
2340 + "quote",
2341 + "syn 2.0.118",
2342 +]
2343 +
2344 +[[package]]
2345 +name = "zerofrom"
2346 +version = "0.1.8"
2347 +source = "registry+https://github.com/rust-lang/crates.io-index"
2348 +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
2349 +dependencies = [
2350 + "zerofrom-derive",
2351 +]
2352 +
2353 +[[package]]
2354 +name = "zerofrom-derive"
2355 +version = "0.1.7"
2356 +source = "registry+https://github.com/rust-lang/crates.io-index"
2357 +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
2358 +dependencies = [
2359 + "proc-macro2",
2360 + "quote",
2361 + "syn 2.0.118",
2362 + "synstructure",
2363 +]
2364 +
2365 +[[package]]
2366 +name = "zeroize"
2367 +version = "1.9.0"
2368 +source = "registry+https://github.com/rust-lang/crates.io-index"
2369 +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
2370 +
2371 +[[package]]
2372 +name = "zerotrie"
2373 +version = "0.2.4"
2374 +source = "registry+https://github.com/rust-lang/crates.io-index"
2375 +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
2376 +dependencies = [
2377 + "displaydoc",
2378 + "yoke",
2379 + "zerofrom",
2380 +]
2381 +
2382 +[[package]]
2383 +name = "zerovec"
2384 +version = "0.11.6"
2385 +source = "registry+https://github.com/rust-lang/crates.io-index"
2386 +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
2387 +dependencies = [
2388 + "yoke",
2389 + "zerofrom",
2390 + "zerovec-derive",
2391 +]
2392 +
2393 +[[package]]
2394 +name = "zerovec-derive"
2395 +version = "0.11.3"
2396 +source = "registry+https://github.com/rust-lang/crates.io-index"
2397 +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
2398 +dependencies = [
2399 + "proc-macro2",
2400 + "quote",
2401 + "syn 2.0.118",
2402 +]
2403 +
2404 +[[package]]
2405 +name = "zmij"
2406 +version = "1.0.21"
2407 +source = "registry+https://github.com/rust-lang/crates.io-index"
2408 +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
sdk/gems/email/Cargo.toml new
+14
@@ -0,0 +1,14 @@
1 +# This Cargo.toml is here to let external tools (IDEs, etc.) know that this is a
2 +# Rust project. Your extension dependencies should be added to the Cargo.toml in
3 +# the ext/ directory.
4 +
5 +[workspace]
6 +members = ["./ext/email"]
7 +resolver = "2"
8 +
9 +# For local development, build the native extension against the in-repo SDK crate
10 +# rather than the published one. The release tooling publishes smbcloud-email-sdk
11 +# first, after which the version dependency in ext/email/Cargo.toml resolves from
12 +# crates.io and this patch is a no-op.
13 +[patch.crates-io]
14 +smbcloud-email-sdk = { path = "../../../crates/smbcloud-email-sdk" }
sdk/gems/email/Gemfile new
+8
@@ -0,0 +1,8 @@
1 +# frozen_string_literal: true
2 +
3 +source "https://rubygems.org"
4 +
5 +gemspec
6 +
7 +gem "rake", "~> 13.0"
8 +gem "rake-compiler", "~> 1.2"
sdk/gems/email/Gemfile.lock new
+29
@@ -0,0 +1,29 @@
1 +PATH
2 + remote: .
3 + specs:
4 + smbcloud-email (0.4.7)
5 + json
6 + rb_sys (~> 0.9.91)
7 +
8 +GEM
9 + remote: https://rubygems.org/
10 + specs:
11 + json (2.19.9)
12 + rake (13.4.2)
13 + rake-compiler (1.3.1)
14 + rake
15 + rake-compiler-dock (1.12.0)
16 + rb_sys (0.9.128)
17 + rake-compiler-dock (= 1.12.0)
18 +
19 +PLATFORMS
20 + arm64-darwin-20
21 + ruby
22 +
23 +DEPENDENCIES
24 + rake (~> 13.0)
25 + rake-compiler (~> 1.2)
26 + smbcloud-email!
27 +
28 +BUNDLED WITH
29 + 2.7.2
sdk/gems/email/README.md new
+68
@@ -0,0 +1,68 @@
1 +# smbcloud-email (Ruby)
2 +
3 +Ruby bindings for the **smbCloud transactional email API**, powered by the shared
4 +Rust SDK ([`smbcloud-email-sdk`](../../../crates/smbcloud-email-sdk)) and a native
5 +[Magnus](https://github.com/matsadler/magnus) extension.
6 +
7 +## Install
8 +
9 +```ruby
10 +gem 'smbcloud-email'
11 +```
12 +
13 +The gem ships a native extension; `bundle install` compiles it (Rust toolchain
14 +required).
15 +
16 +## Usage
17 +
18 +```ruby
19 +require 'email'
20 +
21 +client = SmbCloud::Email.client(
22 + environment: SmbCloud::Email::Environment::PRODUCTION,
23 + api_key: 'smb_mail_your_key',
24 +)
25 +
26 +# Send
27 +sent = client.send(
28 + from: 'billing@example.com',
29 + to: ['customer@acme.com'],
30 + subject: 'Your receipt',
31 + html: '<h1>Thanks!</h1>',
32 + text: 'Thanks!',
33 + idempotency_key: 'receipt-2026-0001',
34 +)
35 +sent[:id] # => "eml_…"
36 +sent[:status] # => 1 (sent)
37 +
38 +# Attachments, cc/bcc, headers, tags
39 +client.send(
40 + from: 'billing@example.com',
41 + to: ['customer@acme.com'],
42 + subject: 'Invoice',
43 + html: '<p>See attached.</p>',
44 + cc: ['accounts@acme.com'],
45 + attachments: [{ filename: 'invoice.pdf', content_base64: 'JVBERi0xLjQ...' }],
46 + headers: { 'X-Entity-Ref-ID' => 'inv_123' },
47 + tags: { 'category' => 'invoice' },
48 +)
49 +
50 +# Delivery status (needs a read-scope key)
51 +message = client.get_message('eml_…')
52 +message[:status]
53 +message[:events]
54 +
55 +client.list_messages(status: 'bounced', limit: 20)
56 +```
57 +
58 +Mint an API key for your Mail app in the smbCloud console. Sending is scoped to
59 +that app's verified domain; reading messages needs a read-scope key.
60 +
61 +## Errors
62 +
63 +Non-2xx API responses and transport failures raise `SmbCloud::Email::Error`, with
64 +the parsed response body available on `#payload`.
65 +
66 +## License
67 +
68 +MIT
sdk/gems/email/Rakefile new
+14
@@ -0,0 +1,14 @@
1 +# frozen_string_literal: true
2 +
3 +require 'bundler/gem_tasks'
4 +require 'rb_sys/extensiontask'
5 +
6 +task build: :compile
7 +
8 +GEMSPEC = Gem::Specification.load('email.gemspec')
9 +
10 +RbSys::ExtensionTask.new('email', GEMSPEC) do |ext|
11 + ext.lib_dir = 'lib/email'
12 +end
13 +
14 +task default: :compile
sdk/gems/email/bin/console new
+8
@@ -0,0 +1,8 @@
1 +#!/usr/bin/env ruby
2 +# frozen_string_literal: true
3 +
4 +require 'bundler/setup'
5 +require 'email'
6 +
7 +require 'irb'
8 +IRB.start(__FILE__)
sdk/gems/email/bin/setup new
+10
@@ -0,0 +1,10 @@
1 +#!/usr/bin/env ruby
2 +# frozen_string_literal: true
3 +
4 +ROOT = File.expand_path('..', __dir__)
5 +Dir.chdir(ROOT) do
6 + puts 'Installing dependencies...'
7 + system('bundle install')
8 + puts 'Compiling extension...'
9 + system('bundle exec rake compile')
10 +end
sdk/gems/email/email.gemspec new
+37
@@ -0,0 +1,37 @@
1 +# frozen_string_literal: true
2 +
3 +require_relative 'lib/email/version'
4 +
5 +Gem::Specification.new do |spec|
6 + spec.name = 'smbcloud-email'
7 + spec.version = Email::VERSION
8 + spec.authors = ['Seto Elkahfi']
9 + spec.email = ['hej@setoelkahfi.se']
10 +
11 + spec.summary = 'Ruby bindings for the smbCloud transactional email API.'
12 + spec.description = 'Send transactional email from a verified domain and read delivery status, powered by the shared Rust SDK and a native Magnus extension.'
13 + spec.homepage = 'https://github.com/smbcloudXYZ/smbcloud-cli/tree/main/sdk/gems/email'
14 + spec.license = 'MIT'
15 + spec.required_ruby_version = '>= 3.1.0'
16 + spec.required_rubygems_version = '>= 3.3.11'
17 +
18 + spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19 + spec.metadata['homepage_uri'] = spec.homepage
20 + spec.metadata['source_code_uri'] = 'https://github.com/smbcloudXYZ/smbcloud-cli/tree/main/sdk/gems/email'
21 + spec.metadata['changelog_uri'] = 'https://github.com/smbcloudXYZ/smbcloud-cli/tree/main/sdk/gems/email/CHANGELOG.md'
22 +
23 + gemspec = File.basename(__FILE__)
24 + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
25 + ls.readlines("\x0", chomp: true).reject do |f|
26 + (f == gemspec) ||
27 + f.start_with?(*%w[bin/ test/ spec/ features/ .git appveyor Gemfile])
28 + end
29 + end
30 + spec.bindir = 'exe'
31 + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32 + spec.require_paths = ['lib']
33 + spec.extensions = ['ext/email/extconf.rb']
34 +
35 + spec.add_dependency 'json'
36 + spec.add_dependency 'rb_sys', '~> 0.9.91'
37 +end
sdk/gems/email/ext/.keep
sdk/gems/email/ext/email/Cargo.toml new
+18
@@ -0,0 +1,18 @@
1 +[package]
2 +name = "email"
3 +version = "0.4.7"
4 +edition = "2024"
5 +authors = ["Seto Elkahfi <hej@setoelkahfi.se>"]
6 +publish = false
7 +
8 +[lib]
9 +crate-type = ["cdylib"]
10 +
11 +[dependencies]
12 +magnus = { version = "0.7.1" }
13 +serde_json = "1"
14 +tokio = { version = "1", features = ["rt-multi-thread"] }
15 +
16 +# The published transactional-email SDK. For local development this is patched
17 +# to the in-repo crate via `[patch.crates-io]` in the gem workspace Cargo.toml.
18 +smbcloud-email-sdk = { version = "0.4" }
sdk/gems/email/ext/email/build.rs new
+11
@@ -0,0 +1,11 @@
1 +fn main() {
2 + // On macOS, a Rust `cdylib` is emitted with an empty LC_ID_DYLIB install
3 + // name. The dyld in macOS 15+/Tahoe (Darwin 27) validates this strictly and
4 + // refuses to load the resulting `.bundle` with:
5 + // "load command #4 string extends beyond end of load command"
6 + // Give the dylib a valid install name at link time so the Ruby extension
7 + // loads on the stricter loader.
8 + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos") {
9 + println!("cargo:rustc-cdylib-link-arg=-Wl,-install_name,@rpath/email.bundle");
10 + }
11 +}
sdk/gems/email/ext/email/extconf.rb new
+6
@@ -0,0 +1,6 @@
1 +# frozen_string_literal: true
2 +
3 +require 'mkmf'
4 +require 'rb_sys/mkmf'
5 +
6 +create_rust_makefile('email/email')
sdk/gems/email/ext/email/src/lib.rs new
+89
@@ -0,0 +1,89 @@
1 +use magnus::{function, prelude::*, Error, Ruby};
2 +use smbcloud_email_sdk::{EmailClient, EmailCredentials, Environment, SendEmail};
3 +use tokio::runtime::Runtime;
4 +
5 +fn parse_environment(value: String) -> Result<Environment, Error> {
6 + value.parse().map_err(|_| {
7 + Error::new(
8 + magnus::exception::arg_error(),
9 + format!("invalid environment `{value}`, expected `dev` or `production`"),
10 + )
11 + })
12 +}
13 +
14 +fn with_runtime<T, F>(f: F) -> Result<T, Error>
15 +where
16 + F: FnOnce(&Runtime) -> Result<T, Error>,
17 +{
18 + let runtime = Runtime::new().map_err(|err| {
19 + Error::new(
20 + magnus::exception::runtime_error(),
21 + format!("failed to initialize tokio runtime: {err}"),
22 + )
23 + })?;
24 + f(&runtime)
25 +}
26 +
27 +fn runtime_error(message: impl std::fmt::Display) -> Error {
28 + Error::new(magnus::exception::runtime_error(), message.to_string())
29 +}
30 +
31 +fn client(environment: Environment, api_key: &str) -> EmailClient {
32 + EmailClient::from_credentials(environment, EmailCredentials { api_key })
33 +}
34 +
35 +/// `message_json` is the SendEmail payload built on the Ruby side. Returns the
36 +/// created message as JSON.
37 +fn send_json(environment: String, api_key: String, message_json: String) -> Result<String, Error> {
38 + let env = parse_environment(environment)?;
39 + let message: SendEmail = serde_json::from_str(&message_json)
40 + .map_err(|err| Error::new(magnus::exception::arg_error(), format!("invalid message: {err}")))?;
41 +
42 + with_runtime(|runtime| {
43 + match runtime.block_on(client(env, &api_key).send(&message)) {
44 + Ok(result) => serde_json::to_string(&result).map_err(runtime_error),
45 + Err(error) => Err(runtime_error(error)),
46 + }
47 + })
48 +}
49 +
50 +fn get_message_json(environment: String, api_key: String, id: String) -> Result<String, Error> {
51 + let env = parse_environment(environment)?;
52 + with_runtime(|runtime| {
53 + match runtime.block_on(client(env, &api_key).get_message(&id)) {
54 + Ok(result) => serde_json::to_string(&result).map_err(runtime_error),
55 + Err(error) => Err(runtime_error(error)),
56 + }
57 + })
58 +}
59 +
60 +/// `status` empty string means "no filter"; `limit` <= 0 means "server default".
61 +fn list_messages_json(
62 + environment: String,
63 + api_key: String,
64 + status: String,
65 + limit: i64,
66 +) -> Result<String, Error> {
67 + let env = parse_environment(environment)?;
68 + let status = if status.trim().is_empty() { None } else { Some(status) };
69 + let limit = if limit > 0 { Some(limit as u32) } else { None };
70 +
71 + with_runtime(|runtime| {
72 + match runtime.block_on(client(env, &api_key).list_messages(status.as_deref(), limit)) {
73 + Ok(result) => serde_json::to_string(&result).map_err(runtime_error),
74 + Err(error) => Err(runtime_error(error)),
75 + }
76 + })
77 +}
78 +
79 +#[magnus::init]
80 +fn init(ruby: &Ruby) -> Result<(), Error> {
81 + let smbcloud = ruby.define_module("SmbCloud")?;
82 + let email = smbcloud.define_module("Email")?;
83 +
84 + email.define_singleton_method("__send", function!(send_json, 3))?;
85 + email.define_singleton_method("__get_message", function!(get_message_json, 3))?;
86 + email.define_singleton_method("__list_messages", function!(list_messages_json, 4))?;
87 +
88 + Ok(())
89 +}
sdk/gems/email/lib/email.rb new
+125
@@ -0,0 +1,125 @@
1 +# frozen_string_literal: true
2 +
3 +require 'json'
4 +require_relative 'email/version'
5 +require_relative 'email/email'
6 +
7 +module Email
8 +end
9 +
10 +module SmbCloud
11 + # Ruby bindings for the smbCloud transactional email API, powered by the shared
12 + # Rust SDK (smbcloud-email-sdk) and a native Magnus extension.
13 + #
14 + # @example
15 + # client = SmbCloud::Email.client(environment: "production", api_key: "smb_mail_…")
16 + # sent = client.send(
17 + # from: "billing@example.com",
18 + # to: ["customer@acme.com"],
19 + # subject: "Your receipt",
20 + # html: "<h1>Thanks!</h1>",
21 + # idempotency_key: "receipt-2026-0001",
22 + # )
23 + # sent[:id] # => "eml_…"
24 + module Email
25 + class Error < StandardError
26 + attr_reader :payload
27 +
28 + def initialize(message = nil, payload: nil)
29 + super(message)
30 + @payload = payload
31 + end
32 + end
33 +
34 + module Environment
35 + DEV = 'dev'
36 + PRODUCTION = 'production'
37 + end
38 +
39 + class Client
40 + attr_reader :environment, :api_key
41 +
42 + def initialize(environment:, api_key:)
43 + @environment = environment
44 + @api_key = api_key
45 + end
46 +
47 + # Send a transactional email. `from` must be on the API key's verified
48 + # domain; provide at least one of `html`/`text`. `attachments` is an array
49 + # of { filename:, content_base64: }. Returns the created message hash.
50 + def send(from:, to:, subject: nil, html: nil, text: nil, cc: nil, bcc: nil,
51 + reply_to: nil, attachments: nil, headers: nil, tags: nil,
52 + idempotency_key: nil)
53 + message = {
54 + from: from,
55 + to: Array(to),
56 + cc: Array(cc),
57 + bcc: Array(bcc),
58 + reply_to: Array(reply_to),
59 + subject: subject,
60 + html: html,
61 + text: text,
62 + attachments: Array(attachments),
63 + headers: headers || {},
64 + tags: tags || {},
65 + idempotency_key: idempotency_key
66 + }.compact
67 +
68 + Email.send(:parse_json, Email.__send(environment, api_key, JSON.generate(message)))
69 + rescue RuntimeError => e
70 + raise Email.send(:normalize_error, e)
71 + end
72 +
73 + # Fetch one message by id, including its delivery-event timeline. Requires
74 + # a read-scope key.
75 + def get_message(id)
76 + Email.send(:parse_json, Email.__get_message(environment, api_key, id))
77 + rescue RuntimeError => e
78 + raise Email.send(:normalize_error, e)
79 + end
80 +
81 + # List recent messages. `status` filters by delivery status name; `limit`
82 + # is clamped server-side to 1..=100. Requires a read-scope key.
83 + def list_messages(status: nil, limit: nil)
84 + Email.send(:parse_json,
85 + Email.__list_messages(environment, api_key, status.to_s, limit.to_i))
86 + rescue RuntimeError => e
87 + raise Email.send(:normalize_error, e)
88 + end
89 + end
90 +
91 + class << self
92 + def client(environment:, api_key:)
93 + Client.new(environment:, api_key:)
94 + end
95 +
96 + def send_with_client(environment:, api_key:, **kwargs)
97 + client(environment:, api_key:).send(**kwargs)
98 + end
99 +
100 + def get_message_with_client(environment:, api_key:, id:)
101 + client(environment:, api_key:).get_message(id)
102 + end
103 +
104 + def list_messages_with_client(environment:, api_key:, status: nil, limit: nil)
105 + client(environment:, api_key:).list_messages(status:, limit:)
106 + end
107 +
108 + private
109 +
110 + def parse_json(payload)
111 + return payload unless payload.is_a?(String)
112 +
113 + JSON.parse(payload, symbolize_names: true)
114 + end
115 +
116 + def normalize_error(error)
117 + payload = parse_json(error.message)
118 + message = payload.is_a?(Hash) ? (payload[:message] || error.message) : error.message
119 + Error.new(message, payload: payload)
120 + rescue JSON::ParserError, NoMethodError, TypeError
121 + Error.new(error.message)
122 + end
123 + end
124 + end
125 +end
sdk/gems/email/lib/email/version.rb new
+5
@@ -0,0 +1,5 @@
1 +# frozen_string_literal: true
2 +
3 +module Email
4 + VERSION = '0.4.7'
5 +end
sdk/gems/email/sig/email.rbs new
+28
@@ -0,0 +1,28 @@
1 +module Email
2 + VERSION: String
3 +end
4 +
5 +module SmbCloud
6 + module Email
7 + class Error < StandardError
8 + attr_reader payload: untyped
9 + end
10 +
11 + module Environment
12 + DEV: String
13 + PRODUCTION: String
14 + end
15 +
16 + class Client
17 + attr_reader environment: String
18 + attr_reader api_key: String
19 +
20 + def initialize: (environment: String, api_key: String) -> void
21 + def send: (from: String, to: untyped, ?subject: String?, ?html: String?, ?text: String?, ?cc: untyped, ?bcc: untyped, ?reply_to: untyped, ?attachments: untyped, ?headers: untyped, ?tags: untyped, ?idempotency_key: String?) -> Hash[Symbol, untyped]
22 + def get_message: (String) -> Hash[Symbol, untyped]
23 + def list_messages: (?status: String?, ?limit: Integer?) -> Array[Hash[Symbol, untyped]]
24 + end
25 +
26 + def self.client: (environment: String, api_key: String) -> Client
27 + end
28 +end