use std::fmt::Display; use crate::analytics_engine::AnalyticsEngineDataset; #[cfg(feature = "d1")] use crate::d1::D1Database; use crate::kv::KvStore; use crate::rate_limit::RateLimiter; use crate::Ai; #[cfg(feature = "queue")] use crate::Queue; use crate::{durable::ObjectNamespace, Bucket, DynamicDispatcher, Fetcher, Result, SecretStore}; use crate::{error::Error, hyperdrive::Hyperdrive}; use js_sys::Object; use serde::de::DeserializeOwned; use wasm_bindgen::{prelude::*, JsCast, JsValue}; #[wasm_bindgen] extern "C" { /// Env contains any bindings you have associated with the Worker when you uploaded it. #[derive(Debug, Clone)] pub type Env; } unsafe impl Send for Env {} unsafe impl Sync for Env {} impl Env { /// Access a binding that does not have a wrapper in workers-rs. Useful for internal-only or /// unstable bindings. pub fn get_binding(&self, name: &str) -> Result { let binding = js_sys::Reflect::get(self, &JsValue::from(name)) .map_err(|_| Error::JsError(format!("Env does not contain binding `{name}`")))?; if binding.is_undefined() { Err(format!("Binding `{name}` is undefined.").into()) } else { // Can't just use JsCast::dyn_into here because the type name might not be in scope // resulting in a terribly annoying javascript error which can't be caught T::get(binding) } } pub fn ai(&self, binding: &str) -> Result { self.get_binding::(binding) } pub fn analytics_engine(&self, binding: &str) -> Result { self.get_binding::(binding) } /// Access Secret value bindings added to your Worker via the UI or `wrangler`: /// pub fn secret(&self, binding: &str) -> Result { self.get_binding::(binding) } /// Get an environment variable defined in the [vars] section of your wrangler.toml or a secret /// defined using `wrangler secret` as a plaintext value. /// /// See: pub fn var(&self, binding: &str) -> Result { self.get_binding::(binding) } /// Get an environment variable defined in the [vars] section of your wrangler.toml that is /// defined as an object. /// /// See: pub fn object_var(&self, binding: &str) -> Result { Ok(serde_wasm_bindgen::from_value( self.get_binding::(binding)?.0, )?) } /// Access a Workers KV namespace by the binding name configured in your wrangler.toml file. pub fn kv(&self, binding: &str) -> Result { KvStore::from_this(self, binding).map_err(From::from) } /// Access a Durable Object namespace by the binding name configured in your wrangler.toml file. pub fn durable_object(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access a Dynamic Dispatcher for dispatching events to other workers. pub fn dynamic_dispatcher(&self, binding: &str) -> Result { self.get_binding(binding) } /// Get a [Service Binding](https://developers.cloudflare.com/workers/runtime-apis/service-bindings/) /// for Worker-to-Worker communication. pub fn service(&self, binding: &str) -> Result { self.get_binding(binding) } #[cfg(feature = "queue")] /// Access a Queue by the binding name configured in your wrangler.toml file. pub fn queue(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access an R2 Bucket by the binding name configured in your wrangler.toml file. pub fn bucket(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access a D1 Database by the binding name configured in your wrangler.toml file. #[cfg(feature = "d1")] pub fn d1(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access the worker assets by the binding name configured in your wrangler.toml file. pub fn assets(&self, binding: &str) -> Result { self.get_binding(binding) } pub fn hyperdrive(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access a Secret Store by the binding name configured in your wrangler.toml file. pub fn secret_store(&self, binding: &str) -> Result { self.get_binding(binding) } /// Access a Rate Limiter by the binding name configured in your wrangler.toml file. pub fn rate_limiter(&self, binding: &str) -> Result { self.get_binding(binding) } } pub trait EnvBinding: Sized + JsCast { const TYPE_NAME: &'static str; fn get(val: JsValue) -> Result { let obj = Object::from(val); if obj.constructor().name() == Self::TYPE_NAME { Ok(obj.unchecked_into()) } else { Err(format!( "Binding cannot be cast to the type {} from {}", Self::TYPE_NAME, obj.constructor().name() ) .into()) } } } #[repr(transparent)] #[derive(Debug)] pub struct StringBinding(JsValue); impl EnvBinding for StringBinding { const TYPE_NAME: &'static str = "String"; } impl JsCast for StringBinding { fn instanceof(val: &JsValue) -> bool { val.is_string() } fn unchecked_from_js(val: JsValue) -> Self { StringBinding(val) } fn unchecked_from_js_ref(val: &JsValue) -> &Self { // Safety: Self is marked repr(transparent) unsafe { &*(val as *const JsValue as *const Self) } } } impl AsRef for StringBinding { fn as_ref(&self) -> &wasm_bindgen::JsValue { unsafe { &*(&self.0 as *const JsValue) } } } impl From for StringBinding { fn from(val: JsValue) -> Self { StringBinding(val) } } impl From for JsValue { fn from(sec: StringBinding) -> Self { sec.0 } } impl Display for StringBinding { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { write!(f, "{}", self.0.as_string().unwrap_or_default()) } } #[repr(transparent)] struct JsValueWrapper(JsValue); impl EnvBinding for JsValueWrapper { const TYPE_NAME: &'static str = "Object"; } impl JsCast for JsValueWrapper { fn instanceof(_: &JsValue) -> bool { true } fn unchecked_from_js(val: JsValue) -> Self { Self(val) } fn unchecked_from_js_ref(val: &JsValue) -> &Self { // Safety: Self is marked repr(transparent) unsafe { &*(val as *const JsValue as *const Self) } } } impl From for wasm_bindgen::JsValue { fn from(value: JsValueWrapper) -> Self { value.0 } } impl AsRef for JsValueWrapper { fn as_ref(&self) -> &JsValue { &self.0 } } /// A string value representing a binding to a secret in a Worker. #[doc(inline)] pub use StringBinding as Secret; /// A string value representing a binding to an environment variable in a Worker. pub type Var = StringBinding;