Skip to main content

worker/
durable.rs

1//! Durable Objects provide low-latency coordination and consistent storage for the Workers platform.
2//! A given namespace can support essentially unlimited Durable Objects, with each Object having
3//! access to a transactional, key-value storage API.
4//!
5//! Durable Objects consist of two components: a class that defines a template for creating Durable
6//! Objects and a Workers script that instantiates and uses those Durable Objects.
7//!
8//! The class and the Workers script are linked together with a binding.
9//!
10//! [Learn more](https://developers.cloudflare.com/workers/learning/using-durable-objects) about
11//! using Durable Objects.
12
13use std::{fmt::Display, ops::Deref, panic::AssertUnwindSafe, time::Duration};
14
15use crate::{
16    container::Container,
17    date::Date,
18    env::{Env, EnvBinding},
19    error::Error,
20    request::Request,
21    response::Response,
22    Result, WebSocket,
23};
24
25use chrono::{DateTime, Utc};
26use futures_util::Future;
27use js_sys::{Map, Number, Object};
28use serde::{de::DeserializeOwned, Serialize};
29use wasm_bindgen::{prelude::*, JsCast};
30use worker_sys::{
31    DurableObject as EdgeDurableObject, DurableObjectId,
32    DurableObjectNamespace as EdgeObjectNamespace, DurableObjectState, DurableObjectStorage,
33    DurableObjectTransaction,
34};
35// use wasm_bindgen_futures::future_to_promise;
36use wasm_bindgen_futures::{future_to_promise, JsFuture};
37
38/// A Durable Object stub is a client object used to send requests to a remote Durable Object.
39#[derive(Debug)]
40pub struct Stub {
41    inner: EdgeDurableObject,
42}
43
44unsafe impl Send for Stub {}
45unsafe impl Sync for Stub {}
46
47impl Stub {
48    /// Send an internal Request to the Durable Object to which the stub points.
49    pub async fn fetch_with_request(&self, req: Request) -> Result<Response> {
50        let promise = self.inner.fetch_with_request(req.inner())?;
51        let response = JsFuture::from(promise).await?;
52        Ok(response.dyn_into::<web_sys::Response>()?.into())
53    }
54
55    /// Construct a Request from a URL to the Durable Object to which the stub points.
56    pub async fn fetch_with_str(&self, url: &str) -> Result<Response> {
57        let promise = self.inner.fetch_with_str(url)?;
58        let response = JsFuture::from(promise).await?;
59        Ok(response.dyn_into::<web_sys::Response>()?.into())
60    }
61
62    pub fn into_rpc<T: JsCast>(self) -> T {
63        self.inner.unchecked_into()
64    }
65}
66
67/// Use an ObjectNamespace to get access to Stubs for communication with a Durable Object instance.
68/// A given namespace can support essentially unlimited Durable Objects, with each Object having
69/// access to a transactional, key-value storage API.
70#[derive(Debug, Clone)]
71pub struct ObjectNamespace {
72    inner: EdgeObjectNamespace,
73}
74
75unsafe impl Send for ObjectNamespace {}
76unsafe impl Sync for ObjectNamespace {}
77
78impl ObjectNamespace {
79    /// This method derives a unique object ID from the given name string. It will always return the
80    /// same ID when given the same name as input.
81    pub fn id_from_name(&self, name: &str) -> Result<ObjectId<'_>> {
82        self.inner
83            .id_from_name(name)
84            .map_err(Error::from)
85            .map(|id| ObjectId {
86                inner: id,
87                namespace: Some(self),
88            })
89    }
90
91    /// This method parses an ID that was previously stringified. This is useful in particular with
92    /// IDs created using `unique_id(&self)`, as these IDs need to be stored somewhere, probably as
93    // as a string.
94    ///
95    /// A stringified object ID is a 64-digit hexadecimal number. However, not all 64-digit hex
96    /// numbers are valid IDs. This method will throw if it is passed an ID that was not originally
97    /// created by newUniqueId() or idFromName(). It will also throw if the ID was originally
98    /// created for a different namespace.
99    pub fn id_from_string(&self, hex_id: &str) -> Result<ObjectId<'_>> {
100        self.inner
101            .id_from_string(hex_id)
102            .map_err(Error::from)
103            .map(|id| ObjectId {
104                inner: id,
105                namespace: Some(self),
106            })
107    }
108
109    /// Creates a new object ID randomly. This method will never return the same ID twice, and thus
110    /// it is guaranteed that the object does not yet exist and has never existed at the time the
111    /// method returns.
112    pub fn unique_id(&self) -> Result<ObjectId<'_>> {
113        self.inner
114            .new_unique_id()
115            .map_err(Error::from)
116            .map(|id| ObjectId {
117                inner: id,
118                namespace: Some(self),
119            })
120    }
121
122    /// Durable Objects can be created so that they only run and store data within a specific
123    /// jurisdiction to comply with local regulations. You must specify the jurisdiction when
124    /// generating the Durable Object's id.
125    ///
126    /// Jurisdiction constraints can only be used with ids created by `unique_id()` and are not
127    /// currently compatible with ids created by `id_from_name()`.
128    ///
129    /// See supported jurisdictions and more documentation at:
130    /// <https://developers.cloudflare.com/durable-objects/reference/data-location/#restrict-durable-objects-to-a-jurisdiction>
131    pub fn unique_id_with_jurisdiction(&self, jd: &str) -> Result<ObjectId<'_>> {
132        let options = Object::new();
133        js_sys::Reflect::set(&options, &JsValue::from("jurisdiction"), &jd.into())?;
134        self.inner
135            .new_unique_id_with_options(&options)
136            .map_err(Error::from)
137            .map(|id| ObjectId {
138                inner: id,
139                namespace: Some(self),
140            })
141    }
142
143    /// Get a Durable Object stub directly by name. This combines the functionality of
144    /// `id_from_name()` and `get_stub()` into a single method call.
145    pub fn get_by_name(&self, name: &str) -> Result<Stub> {
146        self.inner
147            .get_by_name(name)
148            .map_err(Error::from)
149            .map(|stub| Stub { inner: stub })
150    }
151
152    /// Get a Durable Object stub directly by name with options (such as location hints).
153    /// This combines the functionality of `id_from_name()` and `get_stub_with_location_hint()`
154    /// into a single method call.
155    pub fn get_by_name_with_location_hint(&self, name: &str, location_hint: &str) -> Result<Stub> {
156        let options = Object::new();
157        js_sys::Reflect::set(
158            &options,
159            &JsValue::from("locationHint"),
160            &location_hint.into(),
161        )?;
162        self.inner
163            .get_by_name_with_options(name, &options)
164            .map_err(Error::from)
165            .map(|stub| Stub { inner: stub })
166    }
167}
168
169/// An ObjectId is used to identify, locate, and access a Durable Object via interaction with its
170/// Stub.
171#[derive(Debug)]
172pub struct ObjectId<'a> {
173    inner: DurableObjectId,
174    namespace: Option<&'a ObjectNamespace>,
175}
176
177impl ObjectId<'_> {
178    /// Get a Stub for the Durable Object instance identified by this ObjectId.
179    pub fn get_stub(&self) -> Result<Stub> {
180        self.namespace
181            .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
182            .and_then(|n| {
183                Ok(Stub {
184                    inner: n.inner.get(&self.inner)?,
185                })
186            })
187            .map_err(Error::from)
188    }
189
190    pub fn get_stub_with_location_hint(&self, location_hint: &str) -> Result<Stub> {
191        let options = Object::new();
192        js_sys::Reflect::set(
193            &options,
194            &JsValue::from("locationHint"),
195            &location_hint.into(),
196        )?;
197
198        self.namespace
199            .ok_or_else(|| JsValue::from("Cannot get stub from within a Durable Object"))
200            .and_then(|n| {
201                Ok(Stub {
202                    inner: n.inner.get_with_options(&self.inner, &options)?,
203                })
204            })
205            .map_err(Error::from)
206    }
207
208    /// The name that was used to create the `ObjectId` via [`id_from_name`](https://developers.cloudflare.com/durable-objects/api/namespace/#idfromname).
209    /// `None` is returned if the `ObjectId` was constructed using [`unique_id`](https://developers.cloudflare.com/durable-objects/api/namespace/#newuniqueid).
210    /// `None` is also returned within the Durable Object constructor, as the `name` property is not accessible there (see <https://github.com/cloudflare/workerd/issues/2240>).
211    pub fn name(&self) -> Option<String> {
212        self.inner.name()
213    }
214}
215
216impl PartialEq for ObjectId<'_> {
217    /// Compare equality between two ObjectIds using [`equals`](<https://developers.cloudflare.com/durable-objects/api/id/#equals>).
218    /// <div class="warning">The equality check ignores the namespace.</div>
219    fn eq(&self, other: &Self) -> bool {
220        self.inner.equals(&other.inner)
221    }
222}
223
224impl Display for ObjectId<'_> {
225    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
226        write!(
227            f,
228            "{}",
229            self.inner.to_string().map_err(|_| { std::fmt::Error })?
230        )
231    }
232}
233
234/// Passed from the runtime to provide access to the Durable Object's storage as well as various
235/// metadata about the Object.
236#[derive(Debug)]
237pub struct State {
238    inner: DurableObjectState,
239}
240
241impl State {
242    /// The ID of this Durable Object which can be converted into a hex string using its `to_string()`
243    /// method.
244    pub fn id(&self) -> ObjectId<'_> {
245        ObjectId {
246            inner: self.inner.id().unwrap(),
247            namespace: None,
248        }
249    }
250
251    /// Contains methods for accessing persistent storage via the transactional storage API. See
252    /// [Transactional Storage API](https://developers.cloudflare.com/workers/runtime-apis/durable-objects#transactional-storage-api) for a detailed reference.
253    pub fn storage(&self) -> Storage {
254        Storage {
255            inner: self.inner.storage().unwrap(),
256        }
257    }
258
259    pub fn container(&self) -> Option<Container> {
260        self.inner.container().map(|inner| Container { inner })
261    }
262
263    pub fn wait_until<F>(&self, future: F)
264    where
265        F: Future<Output = ()> + 'static,
266    {
267        self.inner
268            .wait_until(&future_to_promise(AssertUnwindSafe(async {
269                future.await;
270                Ok(JsValue::UNDEFINED)
271            })))
272            .unwrap()
273    }
274
275    // needs to be accessed by the `#[durable_object]` macro in a conversion step
276    pub fn _inner(self) -> DurableObjectState {
277        self.inner
278    }
279
280    pub fn accept_web_socket(&self, ws: &WebSocket) {
281        self.inner.accept_websocket(ws.as_ref()).unwrap()
282    }
283
284    pub fn accept_websocket_with_tags(&self, ws: &WebSocket, tags: &[&str]) {
285        let tags = tags.iter().map(|it| (*it).into()).collect();
286
287        self.inner
288            .accept_websocket_with_tags(ws.as_ref(), tags)
289            .unwrap();
290    }
291
292    pub fn get_websockets(&self) -> Vec<WebSocket> {
293        self.inner
294            .get_websockets()
295            .unwrap()
296            .into_iter()
297            .map(Into::into)
298            .collect()
299    }
300
301    pub fn get_websockets_with_tag(&self, tag: &str) -> Vec<WebSocket> {
302        self.inner
303            .get_websockets_with_tag(tag)
304            .unwrap()
305            .into_iter()
306            .map(Into::into)
307            .collect()
308    }
309
310    /// Retrieve tags from a hibernatable websocket
311    pub fn get_tags(&self, websocket: &WebSocket) -> Vec<String> {
312        self.inner.get_tags(websocket.as_ref()).unwrap()
313    }
314
315    pub fn set_websocket_auto_response(&self, pair: &worker_sys::WebSocketRequestResponsePair) {
316        self.inner.set_websocket_auto_response(pair).unwrap();
317    }
318
319    pub fn get_websocket_auto_response(&self) -> Option<worker_sys::WebSocketRequestResponsePair> {
320        self.inner.get_websocket_auto_response().unwrap()
321    }
322}
323
324impl From<DurableObjectState> for State {
325    fn from(o: DurableObjectState) -> Self {
326        Self { inner: o }
327    }
328}
329
330/// Access a Durable Object's Storage API. Each method is implicitly wrapped inside a transaction,
331/// such that its results are atomic and isolated from all other storage operations, even when
332/// accessing multiple key-value pairs.
333pub struct Storage {
334    inner: DurableObjectStorage,
335}
336
337impl core::fmt::Debug for Storage {
338    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339        f.debug_struct("Storage").finish()
340    }
341}
342
343impl Storage {
344    /// Retrieves the value associated with the given key. The type of the returned value will be
345    /// whatever was previously written for the key.
346    ///
347    /// Returns `Ok(None)` if the key does not exist.
348    pub async fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
349        let res = match JsFuture::from(self.inner.get(key)?).await {
350            // If we successfully retrived `undefined`, that means the key doesn't exist
351            Ok(val) if val.is_undefined() => Ok(None),
352            // Otherwise deserialize whatever we successfully received
353            Ok(val) => {
354                serde_wasm_bindgen::from_value(val).map_err(|e| JsValue::from(e.to_string()))
355            }
356            // Forward any error, rewrap to make the typechecker happy
357            Err(e) => Err(e),
358        };
359
360        res.map_err(Error::from)
361    }
362
363    /// Retrieves the values associated with each of the provided keys.
364    pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
365        let keys = self.inner.get_multiple(
366            keys.into_iter()
367                .map(|key| JsValue::from(key.deref()))
368                .collect(),
369        )?;
370        let keys = JsFuture::from(keys).await?;
371        keys.dyn_into::<Map>().map_err(Error::from)
372    }
373
374    /// Stores the value and associates it with the given key.
375    pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
376        self.put_raw(key, serde_wasm_bindgen::to_value(&value)?)
377            .await
378    }
379
380    pub async fn put_raw(&self, key: &str, value: impl Into<JsValue>) -> Result<()> {
381        JsFuture::from(self.inner.put(key, value.into())?)
382            .await
383            .map_err(Error::from)
384            .map(|_| ())
385    }
386
387    /// Takes a serializable struct and stores each of its keys and values to storage.
388    pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
389        let values = serde_wasm_bindgen::to_value(&values)?;
390        if !values.is_object() {
391            return Err("Must pass in a struct type".to_string().into());
392        }
393        self.put_multiple_raw(values.dyn_into().unwrap()).await
394    }
395
396    /// Takes an object and stores each of its keys and values to storage.
397    ///
398    /// ```no_run
399    /// # use worker::Storage;
400    /// use worker::JsValue;
401    ///
402    /// # let storage: Storage = todo!();
403    ///
404    /// let obj = js_sys::Object::new();
405    /// js_sys::Reflect::set(&obj, &JsValue::from_str("foo"), JsValue::from_u64(1));
406    ///
407    /// storage.put_multiple_raw(obj);
408    /// ```
409    pub async fn put_multiple_raw(&self, values: Object) -> Result<()> {
410        JsFuture::from(self.inner.put_multiple(values.into())?)
411            .await
412            .map_err(Error::from)
413            .map(|_| ())
414    }
415
416    /// Deletes the key and associated value. Returns true if the key existed or false if it didn't.
417    pub async fn delete(&self, key: &str) -> Result<bool> {
418        let fut: JsFuture = self.inner.delete(key)?.into();
419        fut.await
420            .and_then(|jsv| {
421                jsv.as_bool()
422                    .ok_or_else(|| JsValue::from("Promise did not return bool"))
423            })
424            .map_err(Error::from)
425    }
426
427    /// Deletes the provided keys and their associated values. Returns a count of the number of
428    /// key-value pairs deleted.
429    pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
430        let fut: JsFuture = self
431            .inner
432            .delete_multiple(
433                keys.into_iter()
434                    .map(|key| JsValue::from(key.deref()))
435                    .collect(),
436            )?
437            .into();
438        fut.await
439            .and_then(|jsv| {
440                jsv.as_f64()
441                    .map(|f| f as usize)
442                    .ok_or_else(|| JsValue::from("Promise did not return number"))
443            })
444            .map_err(Error::from)
445    }
446
447    /// Deletes all keys and associated values, effectively deallocating all storage used by the
448    /// Durable Object. In the event of a failure while the operation is still in flight, it may be
449    /// that only a subset of the data is properly deleted.
450    pub async fn delete_all(&self) -> Result<()> {
451        let fut: JsFuture = self.inner.delete_all()?.into();
452        fut.await.map(|_| ()).map_err(Error::from)
453    }
454
455    /// Returns all keys and values associated with the current Durable Object in ascending
456    /// lexicographic sorted order.
457    ///
458    /// Be aware of how much data may be stored in your Durable Object before calling this version
459    /// of list without options, because it will all be loaded into the Durable Object's memory,
460    /// potentially hitting its [limit](https://developers.cloudflare.com/workers/platform/limits#durable-objects-limits).
461    /// If that is a concern, use the alternate `list_with_options()` method.
462    pub async fn list(&self) -> Result<Map> {
463        let fut: JsFuture = self.inner.list()?.into();
464        fut.await
465            .and_then(|jsv| jsv.dyn_into())
466            .map_err(Error::from)
467    }
468
469    /// Returns keys associated with the current Durable Object according to the parameters in the
470    /// provided options object.
471    pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
472        let fut: JsFuture = self
473            .inner
474            .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
475            .into();
476        fut.await
477            .and_then(|jsv| jsv.dyn_into())
478            .map_err(Error::from)
479    }
480
481    /// Retrieves the current alarm time (if set) as integer milliseconds since epoch.
482    /// The alarm is considered to be set if it has not started, or if it has failed
483    /// and any retry has not begun. If no alarm is set, `get_alarm()` returns `None`.
484    pub async fn get_alarm(&self) -> Result<Option<i64>> {
485        let fut: JsFuture = self.inner.get_alarm(JsValue::NULL.into())?.into();
486        fut.await
487            .map(|jsv| jsv.as_f64().map(|f| f as i64))
488            .map_err(Error::from)
489    }
490
491    pub async fn get_alarm_with_options(&self, options: GetAlarmOptions) -> Result<Option<i64>> {
492        let fut: JsFuture = self
493            .inner
494            .get_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
495            .into();
496        fut.await
497            .map(|jsv| jsv.as_f64().map(|f| f as i64))
498            .map_err(Error::from)
499    }
500
501    /// Sets the current alarm time to the given datetime.
502    ///
503    /// If `set_alarm()` is called with a time equal to or before Date.now(), the alarm
504    /// will be scheduled for asynchronous execution in the immediate future. If the
505    /// alarm handler is currently executing in this case, it will not be canceled.
506    /// Alarms can be set to millisecond granularity and will usually execute within
507    /// a few milliseconds after the set time, but can be delayed by up to a minute
508    /// due to maintenance or failures while failover takes place.
509    pub async fn set_alarm(&self, scheduled_time: impl Into<ScheduledTime>) -> Result<()> {
510        let fut: JsFuture = self
511            .inner
512            .set_alarm(scheduled_time.into().schedule(), JsValue::NULL.into())?
513            .into();
514        fut.await.map(|_| ()).map_err(Error::from)
515    }
516
517    pub async fn set_alarm_with_options(
518        &self,
519        scheduled_time: impl Into<ScheduledTime>,
520        options: SetAlarmOptions,
521    ) -> Result<()> {
522        let fut: JsFuture = self
523            .inner
524            .set_alarm(
525                scheduled_time.into().schedule(),
526                serde_wasm_bindgen::to_value(&options)?.into(),
527            )?
528            .into();
529        fut.await.map(|_| ()).map_err(Error::from)
530    }
531
532    /// Deletes the alarm if one exists. Does not cancel the alarm handler if it is
533    /// currently executing.
534    pub async fn delete_alarm(&self) -> Result<()> {
535        let fut: JsFuture = self.inner.delete_alarm(JsValue::NULL.into())?.into();
536        fut.await.map(|_| ()).map_err(Error::from)
537    }
538
539    pub async fn delete_alarm_with_options(&self, options: SetAlarmOptions) -> Result<()> {
540        let fut: JsFuture = self
541            .inner
542            .delete_alarm(serde_wasm_bindgen::to_value(&options)?.into())?
543            .into();
544        fut.await.map(|_| ()).map_err(Error::from)
545    }
546
547    pub async fn transaction<F, Fut>(&self, closure: F) -> Result<()>
548    where
549        F: FnOnce(Transaction) -> Fut + 'static,
550        Fut: Future<Output = Result<()>> + 'static,
551    {
552        let inner: Box<dyn FnOnce(DurableObjectTransaction) -> js_sys::Promise> =
553            Box::new(move |t: DurableObjectTransaction| -> js_sys::Promise {
554                future_to_promise(AssertUnwindSafe(async move {
555                    closure(Transaction { inner: t })
556                        .await
557                        .map_err(JsValue::from)
558                        .map(|_| JsValue::NULL)
559                }))
560            });
561        let clos = wasm_bindgen::closure::Closure::once_assert_unwind_safe(inner);
562        JsFuture::from(self.inner.transaction(&clos)?)
563            .await
564            .map_err(Error::from)
565            .map(|_| ())
566    }
567
568    // Add new method to access SQLite APIs
569    pub fn sql(&self) -> crate::sql::SqlStorage {
570        crate::sql::SqlStorage::new(self.inner.sql())
571    }
572}
573
574#[derive(Debug)]
575pub struct Transaction {
576    inner: DurableObjectTransaction,
577}
578
579impl Transaction {
580    pub async fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T> {
581        JsFuture::from(self.inner.get(key)?)
582            .await
583            .and_then(|val| {
584                if val.is_undefined() {
585                    Err(JsValue::from("No such value in storage."))
586                } else {
587                    serde_wasm_bindgen::from_value(val).map_err(std::convert::Into::into)
588                }
589            })
590            .map_err(Error::from)
591    }
592
593    pub async fn get_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<Map> {
594        let keys = self.inner.get_multiple(
595            keys.into_iter()
596                .map(|key| JsValue::from(key.deref()))
597                .collect(),
598        )?;
599        let keys = JsFuture::from(keys).await?;
600        keys.dyn_into::<Map>().map_err(Error::from)
601    }
602
603    pub async fn put<T: Serialize>(&self, key: &str, value: T) -> Result<()> {
604        JsFuture::from(self.inner.put(key, serde_wasm_bindgen::to_value(&value)?)?)
605            .await
606            .map_err(Error::from)
607            .map(|_| ())
608    }
609
610    // Each key-value pair in the serialized object will be added to the storage
611    pub async fn put_multiple<T: Serialize>(&self, values: T) -> Result<()> {
612        let values = serde_wasm_bindgen::to_value(&values)?;
613        if !values.is_object() {
614            return Err("Must pass in a struct type".to_string().into());
615        }
616        JsFuture::from(self.inner.put_multiple(values)?)
617            .await
618            .map_err(Error::from)
619            .map(|_| ())
620    }
621
622    pub async fn delete(&self, key: &str) -> Result<bool> {
623        let fut: JsFuture = self.inner.delete(key)?.into();
624        fut.await
625            .and_then(|jsv| {
626                jsv.as_bool()
627                    .ok_or_else(|| JsValue::from("Promise did not return bool"))
628            })
629            .map_err(Error::from)
630    }
631
632    pub async fn delete_multiple(&self, keys: Vec<impl Deref<Target = str>>) -> Result<usize> {
633        let fut: JsFuture = self
634            .inner
635            .delete_multiple(
636                keys.into_iter()
637                    .map(|key| JsValue::from(key.deref()))
638                    .collect(),
639            )?
640            .into();
641        fut.await
642            .and_then(|jsv| {
643                jsv.as_f64()
644                    .map(|f| f as usize)
645                    .ok_or_else(|| JsValue::from("Promise did not return number"))
646            })
647            .map_err(Error::from)
648    }
649
650    pub async fn delete_all(&self) -> Result<()> {
651        let fut: JsFuture = self.inner.delete_all()?.into();
652        fut.await.map(|_| ()).map_err(Error::from)
653    }
654
655    pub async fn list(&self) -> Result<Map> {
656        let fut: JsFuture = self.inner.list()?.into();
657        fut.await
658            .and_then(|jsv| jsv.dyn_into())
659            .map_err(Error::from)
660    }
661
662    pub async fn list_with_options(&self, opts: ListOptions<'_>) -> Result<Map> {
663        let fut: JsFuture = self
664            .inner
665            .list_with_options(serde_wasm_bindgen::to_value(&opts)?.into())?
666            .into();
667        fut.await
668            .and_then(|jsv| jsv.dyn_into())
669            .map_err(Error::from)
670    }
671
672    pub fn rollback(&self) -> Result<()> {
673        self.inner.rollback().map_err(Error::from)
674    }
675}
676
677#[derive(Default, Serialize, Debug)]
678pub struct ListOptions<'a> {
679    /// Key at which the list results should start, inclusive.
680    #[serde(skip_serializing_if = "Option::is_none")]
681    start: Option<&'a str>,
682    /// Key at which the list results should end, exclusive.
683    #[serde(skip_serializing_if = "Option::is_none")]
684    end: Option<&'a str>,
685    /// Restricts results to only include key-value pairs whose keys begin with the prefix.
686    #[serde(skip_serializing_if = "Option::is_none")]
687    prefix: Option<&'a str>,
688    /// If true, return results in descending lexicographic order instead of the default ascending
689    /// order.
690    #[serde(skip_serializing_if = "Option::is_none")]
691    reverse: Option<bool>,
692    /// Maximum number of key-value pairs to return.
693    #[serde(skip_serializing_if = "Option::is_none")]
694    limit: Option<usize>,
695}
696
697impl<'a> ListOptions<'a> {
698    /// Create a new ListOptions struct with no options set.
699    pub fn new() -> Self {
700        Default::default()
701    }
702
703    /// Key at which the list results should start, inclusive.
704    pub fn start(mut self, val: &'a str) -> Self {
705        self.start = Some(val);
706        self
707    }
708
709    /// Key at which the list results should end, exclusive.
710    pub fn end(mut self, val: &'a str) -> Self {
711        self.end = Some(val);
712        self
713    }
714
715    /// Restricts results to only include key-value pairs whose keys begin with the prefix.
716    pub fn prefix(mut self, val: &'a str) -> Self {
717        self.prefix = Some(val);
718        self
719    }
720
721    /// If true, return results in descending lexicographic order instead of the default ascending
722    /// order.
723    pub fn reverse(mut self, val: bool) -> Self {
724        self.reverse = Some(val);
725        self
726    }
727
728    /// Maximum number of key-value pairs to return.
729    pub fn limit(mut self, val: usize) -> Self {
730        self.limit = Some(val);
731        self
732    }
733}
734#[derive(Debug)]
735enum ScheduledTimeInit {
736    Date(js_sys::Date),
737    Offset(f64),
738}
739
740/// Determines when a Durable Object alarm should be ran, based on a timestamp or offset in milliseconds.
741///
742/// Implements [`From`] for:
743/// - [`Duration`], interpreted as an offset (in milliseconds).
744/// - [`i64`], interpreted as an offset (in milliseconds).
745/// - [`DateTime`], interpreted as a timestamp.
746///
747/// When an offset is used, the time at which `set_alarm()` or `set_alarm_with_options()` is called
748/// is used to compute the scheduled time. [`Date::now`] is used as the current time.
749#[derive(Debug)]
750pub struct ScheduledTime {
751    init: ScheduledTimeInit,
752}
753
754impl ScheduledTime {
755    pub fn new(date: js_sys::Date) -> Self {
756        Self {
757            init: ScheduledTimeInit::Date(date),
758        }
759    }
760
761    fn schedule(self) -> js_sys::Date {
762        match self.init {
763            ScheduledTimeInit::Date(date) => date,
764            ScheduledTimeInit::Offset(offset_ms) => {
765                let now = Date::now().as_millis() as f64;
766                js_sys::Date::new(&Number::from(now + offset_ms))
767            }
768        }
769    }
770}
771
772impl From<i64> for ScheduledTime {
773    fn from(offset_ms: i64) -> Self {
774        ScheduledTime {
775            init: ScheduledTimeInit::Offset(offset_ms as f64),
776        }
777    }
778}
779
780impl From<DateTime<Utc>> for ScheduledTime {
781    fn from(date: DateTime<Utc>) -> Self {
782        ScheduledTime {
783            init: ScheduledTimeInit::Date(js_sys::Date::new(&Number::from(
784                date.timestamp_millis() as f64,
785            ))),
786        }
787    }
788}
789
790impl From<Duration> for ScheduledTime {
791    fn from(offset: Duration) -> Self {
792        ScheduledTime {
793            init: ScheduledTimeInit::Offset(offset.as_millis() as f64),
794        }
795    }
796}
797
798#[derive(Debug, Clone, Default, Serialize)]
799pub struct GetAlarmOptions {
800    #[serde(skip_serializing_if = "Option::is_none")]
801    pub allow_concurrency: Option<bool>,
802}
803
804#[derive(Debug, Clone, Default, Serialize)]
805pub struct SetAlarmOptions {
806    #[serde(skip_serializing_if = "Option::is_none")]
807    pub allow_concurrency: Option<bool>,
808    #[serde(skip_serializing_if = "Option::is_none")]
809    pub allow_unconfirmed: Option<bool>,
810}
811
812impl EnvBinding for ObjectNamespace {
813    const TYPE_NAME: &'static str = "DurableObjectNamespace";
814}
815
816impl JsCast for ObjectNamespace {
817    fn instanceof(val: &JsValue) -> bool {
818        val.is_instance_of::<EdgeObjectNamespace>()
819    }
820
821    fn unchecked_from_js(val: JsValue) -> Self {
822        Self { inner: val.into() }
823    }
824
825    fn unchecked_from_js_ref(val: &JsValue) -> &Self {
826        unsafe { &*(val as *const JsValue as *const Self) }
827    }
828}
829
830impl From<ObjectNamespace> for JsValue {
831    fn from(ns: ObjectNamespace) -> Self {
832        JsValue::from(ns.inner)
833    }
834}
835
836impl AsRef<JsValue> for ObjectNamespace {
837    fn as_ref(&self) -> &JsValue {
838        &self.inner
839    }
840}
841
842#[derive(Debug)]
843pub enum WebSocketIncomingMessage {
844    String(String),
845    Binary(Vec<u8>),
846}
847
848/**
849**Note:** Implement this trait with a standard `impl DurableObject for YourType` block, but in order to
850integrate them with the Workers Runtime, you must also add the **`#[durable_object]`** attribute
851to the struct.
852
853## Example
854```no_run
855use worker::*;
856
857#[durable_object]
858pub struct Chatroom {
859    users: Vec<User>,
860    messages: Vec<Message>,
861    state: State,
862    env: Env, // access `Env` across requests, use inside `fetch`
863}
864
865impl DurableObject for Chatroom {
866    fn new(state: State, env: Env) -> Self {
867        Self {
868            users: vec![],
869            messages: vec![],
870            state,
871            env,
872        }
873    }
874
875    async fn fetch(&self, _req: Request) -> Result<Response> {
876        // do some work when a worker makes a request to this DO
877        Response::ok(&format!("{} active users.", self.users.len()))
878    }
879}
880```
881*/
882#[allow(async_fn_in_trait)] // Send is not needed
883pub trait DurableObject: has_durable_object_attribute {
884    fn new(state: State, env: Env) -> Self;
885
886    async fn fetch(&self, req: Request) -> Result<Response>;
887
888    #[allow(clippy::diverging_sub_expression)]
889    async fn alarm(&self) -> Result<Response> {
890        worker_sys::console_error!("alarm() handler not implemented");
891        unimplemented!("alarm() handler")
892    }
893
894    #[allow(unused_variables, clippy::diverging_sub_expression)]
895    async fn websocket_message(
896        &self,
897        ws: WebSocket,
898        message: WebSocketIncomingMessage,
899    ) -> Result<()> {
900        worker_sys::console_error!("websocket_message() handler not implemented");
901        unimplemented!("websocket_message() handler")
902    }
903
904    #[allow(unused_variables, clippy::diverging_sub_expression)]
905    async fn websocket_close(
906        &self,
907        ws: WebSocket,
908        code: usize,
909        reason: String,
910        was_clean: bool,
911    ) -> Result<()> {
912        worker_sys::console_error!("websocket_close() handler not implemented");
913        unimplemented!("websocket_close() handler")
914    }
915
916    #[allow(unused_variables, clippy::diverging_sub_expression)]
917    async fn websocket_error(&self, ws: WebSocket, error: Error) -> Result<()> {
918        worker_sys::console_error!("websocket_error() handler not implemented");
919        unimplemented!("websocket_error() handler")
920    }
921}
922
923#[doc(hidden)]
924#[allow(non_camel_case_types)]
925pub trait has_durable_object_attribute {}