1use std::fmt::Display;
2
3use crate::analytics_engine::AnalyticsEngineDataset;
4use crate::browser_rendering::BrowserRendering;
5#[cfg(feature = "d1")]
6use crate::d1::D1Database;
7use crate::kv::KvStore;
8use crate::mtls_certificate::MtlsCertificate;
9use crate::rate_limit::RateLimiter;
10use crate::Ai;
11use crate::DynamicWorkerLoader;
12use crate::SendEmail;
13use crate::ImagesBinding;
14use crate::VectorizeIndex;
15use crate::WorkflowBinding;
16use crate::WorkerVersionMetadata;
17#[cfg(feature = "queue")]
18use crate::Queue;
19use crate::{durable::ObjectNamespace, Bucket, DynamicDispatcher, Fetcher, Result, SecretStore};
20use crate::{error::Error, hyperdrive::Hyperdrive};
21
22use js_sys::Object;
23use serde::de::DeserializeOwned;
24use wasm_bindgen::{prelude::*, JsCast, JsValue};
25
26#[wasm_bindgen]
27extern "C" {
28 #[derive(Debug, Clone)]
30 pub type Env;
31}
32
33unsafe impl Send for Env {}
34unsafe impl Sync for Env {}
35
36impl Env {
37 pub fn get_binding<T: EnvBinding>(&self, name: &str) -> Result<T> {
40 let binding = js_sys::Reflect::get(self, &JsValue::from(name))
41 .map_err(|_| Error::JsError(format!("Env does not contain binding `{name}`")))?;
42 if binding.is_undefined() {
43 Err(format!("Binding `{name}` is undefined.").into())
44 } else {
45 T::get(binding)
48 }
49 }
50
51 pub fn ai(&self, binding: &str) -> Result<Ai> {
52 self.get_binding::<Ai>(binding)
53 }
54
55 pub fn analytics_engine(&self, binding: &str) -> Result<AnalyticsEngineDataset> {
56 self.get_binding::<AnalyticsEngineDataset>(binding)
57 }
58
59 pub fn browser_rendering(&self, binding: &str) -> Result<BrowserRendering> {
61 self.get_binding::<BrowserRendering>(binding)
62 }
63
64 pub fn secret(&self, binding: &str) -> Result<Secret> {
67 self.get_binding::<Secret>(binding)
68 }
69
70 pub fn var(&self, binding: &str) -> Result<Var> {
75 self.get_binding::<Var>(binding)
76 }
77
78 pub fn object_var<T: DeserializeOwned>(&self, binding: &str) -> Result<T> {
83 Ok(serde_wasm_bindgen::from_value(
84 self.get_binding::<JsValueWrapper>(binding)?.0,
85 )?)
86 }
87
88 pub fn kv(&self, binding: &str) -> Result<KvStore> {
90 KvStore::from_this(self, binding).map_err(From::from)
91 }
92
93 pub fn durable_object(&self, binding: &str) -> Result<ObjectNamespace> {
95 self.get_binding(binding)
96 }
97
98 pub fn dynamic_dispatcher(&self, binding: &str) -> Result<DynamicDispatcher> {
100 self.get_binding(binding)
101 }
102
103 pub fn dynamic_worker_loader(&self, binding: &str) -> Result<DynamicWorkerLoader> {
105 self.get_binding(binding)
106 }
107
108 pub fn service(&self, binding: &str) -> Result<Fetcher> {
111 self.get_binding(binding)
112 }
113
114 #[cfg(feature = "queue")]
115 pub fn queue(&self, binding: &str) -> Result<Queue> {
117 self.get_binding(binding)
118 }
119
120 pub fn bucket(&self, binding: &str) -> Result<Bucket> {
122 self.get_binding(binding)
123 }
124
125 #[cfg(feature = "d1")]
127 pub fn d1(&self, binding: &str) -> Result<D1Database> {
128 self.get_binding(binding)
129 }
130
131 pub fn assets(&self, binding: &str) -> Result<Fetcher> {
133 self.get_binding(binding)
134 }
135
136 pub fn images(&self, binding: &str) -> Result<ImagesBinding> {
138 self.get_binding(binding)
139 }
140
141 pub fn hyperdrive(&self, binding: &str) -> Result<Hyperdrive> {
142 self.get_binding(binding)
143 }
144
145 pub fn mtls_certificate(&self, binding: &str) -> Result<MtlsCertificate> {
147 self.get_binding(binding)
148 }
149
150 pub fn secret_store(&self, binding: &str) -> Result<SecretStore> {
152 self.get_binding(binding)
153 }
154
155 pub fn rate_limiter(&self, binding: &str) -> Result<RateLimiter> {
157 self.get_binding(binding)
158 }
159
160 pub fn vectorize(&self, binding: &str) -> Result<VectorizeIndex> {
162 self.get_binding(binding)
163 }
164
165 pub fn workflows(&self, binding: &str) -> Result<WorkflowBinding> {
167 self.get_binding(binding)
168 }
169
170 pub fn send_email(&self, binding: &str) -> Result<SendEmail> {
172 self.get_binding(binding)
173 }
174
175 pub fn version_metadata(&self, binding: &str) -> Result<WorkerVersionMetadata> {
177 self.get_binding(binding)
178 }
179}
180
181pub trait EnvBinding: Sized + JsCast {
182 const TYPE_NAME: &'static str;
183
184 fn get(val: JsValue) -> Result<Self> {
185 let obj = Object::from(val);
186 if obj.constructor().name() == Self::TYPE_NAME {
187 Ok(obj.unchecked_into())
188 } else {
189 Err(format!(
190 "Binding cannot be cast to the type {} from {}",
191 Self::TYPE_NAME,
192 obj.constructor().name()
193 )
194 .into())
195 }
196 }
197}
198
199#[repr(transparent)]
200#[derive(Debug)]
201pub struct StringBinding(JsValue);
202
203impl EnvBinding for StringBinding {
204 const TYPE_NAME: &'static str = "String";
205}
206
207impl JsCast for StringBinding {
208 fn instanceof(val: &JsValue) -> bool {
209 val.is_string()
210 }
211
212 fn unchecked_from_js(val: JsValue) -> Self {
213 StringBinding(val)
214 }
215
216 fn unchecked_from_js_ref(val: &JsValue) -> &Self {
217 unsafe { &*(val as *const JsValue as *const Self) }
219 }
220}
221
222impl AsRef<JsValue> for StringBinding {
223 fn as_ref(&self) -> &wasm_bindgen::JsValue {
224 unsafe { &*(&self.0 as *const JsValue) }
225 }
226}
227
228impl From<JsValue> for StringBinding {
229 fn from(val: JsValue) -> Self {
230 StringBinding(val)
231 }
232}
233
234impl From<StringBinding> for JsValue {
235 fn from(sec: StringBinding) -> Self {
236 sec.0
237 }
238}
239
240impl Display for StringBinding {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
242 write!(f, "{}", self.0.as_string().unwrap_or_default())
243 }
244}
245
246#[repr(transparent)]
247struct JsValueWrapper(JsValue);
248
249impl EnvBinding for JsValueWrapper {
250 const TYPE_NAME: &'static str = "Object";
251}
252
253impl JsCast for JsValueWrapper {
254 fn instanceof(_: &JsValue) -> bool {
255 true
256 }
257
258 fn unchecked_from_js(val: JsValue) -> Self {
259 Self(val)
260 }
261
262 fn unchecked_from_js_ref(val: &JsValue) -> &Self {
263 unsafe { &*(val as *const JsValue as *const Self) }
265 }
266}
267
268impl From<JsValueWrapper> for wasm_bindgen::JsValue {
269 fn from(value: JsValueWrapper) -> Self {
270 value.0
271 }
272}
273
274impl AsRef<JsValue> for JsValueWrapper {
275 fn as_ref(&self) -> &JsValue {
276 &self.0
277 }
278}
279
280#[doc(inline)]
282pub use StringBinding as Secret;
283pub type Var = StringBinding;