1use std::fmt::Display;
2
3use crate::analytics_engine::AnalyticsEngineDataset;
4#[cfg(feature = "d1")]
5use crate::d1::D1Database;
6#[cfg(feature = "queue")]
7use crate::Queue;
8use crate::{durable::ObjectNamespace, Bucket, DynamicDispatcher, Fetcher, Result, SecretStore};
9use crate::{error::Error, hyperdrive::Hyperdrive};
10
11use crate::Ai;
12
13use js_sys::Object;
14use serde::de::DeserializeOwned;
15use wasm_bindgen::{prelude::*, JsCast, JsValue};
16use worker_kv::KvStore;
17
18#[wasm_bindgen]
19extern "C" {
20 #[derive(Debug, Clone)]
22 pub type Env;
23}
24
25unsafe impl Send for Env {}
26unsafe impl Sync for Env {}
27
28impl Env {
29 pub fn get_binding<T: EnvBinding>(&self, name: &str) -> Result<T> {
32 let binding = js_sys::Reflect::get(self, &JsValue::from(name))
33 .map_err(|_| Error::JsError(format!("Env does not contain binding `{name}`")))?;
34 if binding.is_undefined() {
35 Err(format!("Binding `{name}` is undefined.").into())
36 } else {
37 T::get(binding)
40 }
41 }
42
43 pub fn ai(&self, binding: &str) -> Result<Ai> {
44 self.get_binding::<Ai>(binding)
45 }
46
47 pub fn analytics_engine(&self, binding: &str) -> Result<AnalyticsEngineDataset> {
48 self.get_binding::<AnalyticsEngineDataset>(binding)
49 }
50
51 pub fn secret(&self, binding: &str) -> Result<Secret> {
54 self.get_binding::<Secret>(binding)
55 }
56
57 pub fn var(&self, binding: &str) -> Result<Var> {
62 self.get_binding::<Var>(binding)
63 }
64
65 pub fn object_var<T: DeserializeOwned>(&self, binding: &str) -> Result<T> {
70 Ok(serde_wasm_bindgen::from_value(
71 self.get_binding::<JsValueWrapper>(binding)?.0,
72 )?)
73 }
74
75 pub fn kv(&self, binding: &str) -> Result<KvStore> {
77 KvStore::from_this(self, binding).map_err(From::from)
78 }
79
80 pub fn durable_object(&self, binding: &str) -> Result<ObjectNamespace> {
82 self.get_binding(binding)
83 }
84
85 pub fn dynamic_dispatcher(&self, binding: &str) -> Result<DynamicDispatcher> {
87 self.get_binding(binding)
88 }
89
90 pub fn service(&self, binding: &str) -> Result<Fetcher> {
93 self.get_binding(binding)
94 }
95
96 #[cfg(feature = "queue")]
97 pub fn queue(&self, binding: &str) -> Result<Queue> {
99 self.get_binding(binding)
100 }
101
102 pub fn bucket(&self, binding: &str) -> Result<Bucket> {
104 self.get_binding(binding)
105 }
106
107 #[cfg(feature = "d1")]
109 pub fn d1(&self, binding: &str) -> Result<D1Database> {
110 self.get_binding(binding)
111 }
112
113 pub fn assets(&self, binding: &str) -> Result<Fetcher> {
115 self.get_binding(binding)
116 }
117
118 pub fn hyperdrive(&self, binding: &str) -> Result<Hyperdrive> {
119 self.get_binding(binding)
120 }
121
122 pub fn secret_store(&self, binding: &str) -> Result<SecretStore> {
124 self.get_binding(binding)
125 }
126}
127
128pub trait EnvBinding: Sized + JsCast {
129 const TYPE_NAME: &'static str;
130
131 fn get(val: JsValue) -> Result<Self> {
132 let obj = Object::from(val);
133 if obj.constructor().name() == Self::TYPE_NAME {
134 Ok(obj.unchecked_into())
135 } else {
136 Err(format!(
137 "Binding cannot be cast to the type {} from {}",
138 Self::TYPE_NAME,
139 obj.constructor().name()
140 )
141 .into())
142 }