dioxus_cloudflare/bindings.rs
1//! Typed binding shorthands for common Cloudflare Worker resources.
2//!
3//! These combine [`crate::context::env()`] + binding lookup + error conversion
4//! into a single call with contextual error messages.
5
6use crate::context::env;
7use crate::error::CfError;
8
9/// Access a D1 database binding by name.
10///
11/// Shorthand for `cf::env().d1(name).cf()?`.
12///
13/// # Errors
14///
15/// Returns [`CfError`] if the binding is missing or not a D1 database.
16///
17/// # Example
18///
19/// ```rust,ignore
20/// use dioxus_cloudflare::prelude::*;
21///
22/// #[server]
23/// pub async fn get_user(id: String) -> Result<User, ServerFnError> {
24/// let db = cf::d1("DB")?;
25/// // ...
26/// }
27/// ```
28pub fn d1(name: &str) -> Result<worker::D1Database, CfError> {
29 env()
30 .d1(name)
31 .map_err(|e| CfError(worker::Error::RustError(format!("D1 binding `{name}`: {e}"))))
32}
33
34/// Access a Workers KV namespace binding by name.
35///
36/// Shorthand for `cf::env().kv(name).cf()?`.
37///
38/// # Errors
39///
40/// Returns [`CfError`] if the binding is missing or not a KV namespace.
41///
42/// # Example
43///
44/// ```rust,ignore
45/// use dioxus_cloudflare::prelude::*;
46///
47/// #[server]
48/// pub async fn get_value(key: String) -> Result<String, ServerFnError> {
49/// let kv = cf::kv("KV")?;
50/// let val = kv.get(&key).text().await.cf()?.unwrap_or_default();
51/// Ok(val)
52/// }
53/// ```
54pub fn kv(name: &str) -> Result<worker::kv::KvStore, CfError> {
55 env()
56 .kv(name)
57 .map_err(|e| CfError(worker::Error::RustError(format!("KV binding `{name}`: {e}"))))
58}
59
60/// Access an R2 bucket binding by name.
61///
62/// Shorthand for `cf::env().bucket(name).cf()?`.
63///
64/// # Errors
65///
66/// Returns [`CfError`] if the binding is missing or not an R2 bucket.
67///
68/// # Example
69///
70/// ```rust,ignore
71/// use dioxus_cloudflare::prelude::*;
72///
73/// #[server]
74/// pub async fn upload(key: String, data: Vec<u8>) -> Result<(), ServerFnError> {
75/// let bucket = cf::r2("BUCKET")?;
76/// bucket.put(&key, data).execute().await.cf()?;
77/// Ok(())
78/// }
79/// ```
80pub fn r2(name: &str) -> Result<worker::Bucket, CfError> {
81 env()
82 .bucket(name)
83 .map_err(|e| CfError(worker::Error::RustError(format!("R2 binding `{name}`: {e}"))))
84}
85
86/// Access a Durable Object namespace binding by name.
87///
88/// Shorthand for `cf::env().durable_object(name).cf()?`.
89///
90/// # Errors
91///
92/// Returns [`CfError`] if the binding is missing or not a Durable Object namespace.
93///
94/// # Example
95///
96/// ```rust,ignore
97/// use dioxus_cloudflare::prelude::*;
98///
99/// #[server]
100/// pub async fn get_counter(name: String) -> Result<String, ServerFnError> {
101/// let ns = cf::durable_object("COUNTER")?;
102/// let stub = ns.id_from_name(&name)?.get_stub()?;
103/// // ...
104/// }
105/// ```
106pub fn durable_object(name: &str) -> Result<worker::durable::ObjectNamespace, CfError> {
107 env()
108 .durable_object(name)
109 .map_err(|e| CfError(worker::Error::RustError(format!("Durable Object binding `{name}`: {e}"))))
110}
111
112/// Access a secret environment variable by name.
113///
114/// Shorthand for `cf::env().secret(name).cf()?`. Secrets are set via
115/// `wrangler secret put` or the Cloudflare dashboard — they are encrypted
116/// at rest and never appear in `wrangler.toml`.
117///
118/// The returned [`Secret`](worker::Secret) implements `Display` / `ToString`
119/// to retrieve the plaintext value.
120///
121/// # Errors
122///
123/// Returns [`CfError`] if the binding is missing or not a secret.
124///
125/// # Example
126///
127/// ```rust,ignore
128/// use dioxus_cloudflare::prelude::*;
129///
130/// #[server]
131/// pub async fn verify_token(token: String) -> Result<bool, ServerFnError> {
132/// let expected = cf::secret("API_TOKEN")?.to_string();
133/// Ok(token == expected)
134/// }
135/// ```
136pub fn secret(name: &str) -> Result<worker::Secret, CfError> {
137 env()
138 .secret(name)
139 .map_err(|e| CfError(worker::Error::RustError(format!("Secret binding `{name}`: {e}"))))
140}
141
142/// Access a plaintext environment variable by name.
143///
144/// Shorthand for `cf::env().var(name).cf()?`. Variables are set in the
145/// `[vars]` section of `wrangler.toml` — they are **not** encrypted.
146///
147/// The returned value implements `Display` / `ToString`.
148///
149/// # Errors
150///
151/// Returns [`CfError`] if the variable is missing.
152///
153/// # Example
154///
155/// ```rust,ignore
156/// use dioxus_cloudflare::prelude::*;
157///
158/// #[server]
159/// pub async fn get_env() -> Result<String, ServerFnError> {
160/// let env = cf::var("ENVIRONMENT")?.to_string();
161/// Ok(env)
162/// }
163/// ```
164pub fn var(name: &str) -> Result<worker::Var, CfError> {
165 env()
166 .var(name)
167 .map_err(|e| CfError(worker::Error::RustError(format!("Var binding `{name}`: {e}"))))
168}
169
170/// Access a Workers AI binding by name.
171///
172/// Shorthand for `cf::env().ai(name).cf()?`.
173///
174/// # Errors
175///
176/// Returns [`CfError`] if the binding is missing or not an AI binding.
177///
178/// # Example
179///
180/// ```rust,ignore
181/// use dioxus_cloudflare::prelude::*;
182/// use serde::{Deserialize, Serialize};
183///
184/// #[derive(Serialize)]
185/// struct AiInput { messages: Vec<AiMessage> }
186/// #[derive(Serialize)]
187/// struct AiMessage { role: String, content: String }
188/// #[derive(Deserialize)]
189/// struct AiOutput { response: Option<String> }
190///
191/// #[server]
192/// pub async fn generate(prompt: String) -> Result<String, ServerFnError> {
193/// let ai = cf::ai("AI")?;
194/// let resp: AiOutput = ai.run("@cf/meta/llama-3.1-8b-instruct", AiInput {
195/// messages: vec![AiMessage { role: "user".into(), content: prompt }],
196/// }).await.cf()?;
197/// Ok(resp.response.unwrap_or_default())
198/// }
199/// ```
200pub fn ai(name: &str) -> Result<worker::Ai, CfError> {
201 env()
202 .ai(name)
203 .map_err(|e| CfError(worker::Error::RustError(format!("AI binding `{name}`: {e}"))))
204}
205
206/// Access a Service binding by name.
207///
208/// Shorthand for `cf::env().service(name).cf()?`. Returns a [`Fetcher`](worker::Fetcher)
209/// that can call other Workers via `fetch()` or `fetch_request()`.
210///
211/// # Errors
212///
213/// Returns [`CfError`] if the binding is missing or not a Service binding.
214///
215/// # Example
216///
217/// ```rust,ignore
218/// use dioxus_cloudflare::prelude::*;
219///
220/// #[server]
221/// pub async fn call_auth_worker(token: String) -> Result<String, ServerFnError> {
222/// let auth = cf::service("AUTH")?;
223/// let resp = auth.fetch("https://fake-host/verify", None).await.cf()?;
224/// Ok(resp.text().await.cf()?)
225/// }
226/// ```
227pub fn service(name: &str) -> Result<worker::Fetcher, CfError> {
228 env()
229 .service(name)
230 .map_err(|e| CfError(worker::Error::RustError(format!("Service binding `{name}`: {e}"))))
231}
232
233/// Access a Queue producer binding by name. Requires the `queue` feature.
234///
235/// Shorthand for `cf::env().queue(name).cf()?`.
236///
237/// # Errors
238///
239/// Returns [`CfError`] if the binding is missing or not a Queue.
240///
241/// # Example
242///
243/// ```rust,ignore
244/// use dioxus_cloudflare::prelude::*;
245///
246/// #[server]
247/// pub async fn enqueue_job(payload: String) -> Result<(), ServerFnError> {
248/// let queue = cf::queue("JOBS")?;
249/// queue.send(payload).await.cf()?;
250/// Ok(())
251/// }
252/// ```
253#[cfg(feature = "queue")]
254pub fn queue(name: &str) -> Result<worker::Queue, CfError> {
255 env()
256 .queue(name)
257 .map_err(|e| CfError(worker::Error::RustError(format!("Queue binding `{name}`: {e}"))))
258}