Skip to content

Repository files navigation

Durable Object Proxy (do-proxy)

Types includedBundle SizeBundle SizeVersion

Simple interface for accessing Cloudflare Durable Objects' storage and class methods.

This library handles request building, fetching and responding behind the scenes via lightweight proxy object which provides interface for accessing DO instance's storage and class methods.

Install

npm install do-proxy

Examples

  • Todo app utilizing storage and batch methods
  • Todo app extending DOProxy class and utilizing class methods

Usage briefly

Make your Durable Object class methods accessible by extending the DOProxy.

import{DOProxy}from'do-proxy';classMyDOClassextendsDOProxy{// Arguments & return values have to be JSON serialiazablemyClassMethod(param: string){// Do what ever you would do inside DO}}

Inside your Worker's fetch method:

// Get `DurableObjectNamespace` wrapped inside our proxyconstMY_DO_BINDING=MyDOClass.wrap(env.MY_DO_BINDING);// You can use the default namespace methods or shorthand methods `getByName` & `getById`conststub=MY_DO_BINDING.getByName('name');// You can access instance's storage methodsconstres1=awaitstub.storage.get('my-store');// You can also access your class's methods.constres2=awaitstub.class.myClassMethod('foo');// Or handle both with a single fetch behind the scenes using `batch` methodconst[res3,res4]=awaitstub.batch(()=>[stub.storage.get('my-store'),stub.class.myClassMethod('foo'),]);

Usage

You can use DOProxy as is for Durable Object bindings. This enables you to use storage methods.

Here we expect you to have DO class Todo bound to TODO inside wrangler.toml:

import{DOProxy}from'do-proxy';export{DOProxyasTodo};exportdefault{asyncfetch(req: Request,env: any){constTODO=DOProxy.wrap(env.TODO);conststub=TODO.getByName('name');awaittodo.storage.put('todo:1','has to be done');constlist=Object.fromEntries(awaittodo.storage.list());returnResponse.json(list);},};

Or you can extend it, which enables you to call class methods via class property:

import{DOProxy}from'do-proxy';classTodoextendsDOProxy{state: DurableObjectState;constructor(state: DurableObjectState){super(state);this.state=state;}asyncadd(todo: string){constid=Math.ceil(Math.random()*100);this.state.storage.put(`todo:${id}`,todo);returnid;}asyncget(id: number){returnthis.state.storage.get(`todo:${id}`);}}exportdefault{asyncfetch(req: Request,env: any){conststub=Todo.wrap(env.TODO).getByName('my-todos');constid=awaitstub.class.add('has to be done');consttodo=awaitstub.class.get(id);returnResponse.json({
id,
todo,});},};export{Todo};

You can also utilize the batch method which allows you to run multiple methods with one fetch request to DO instance:

// See previous example for `Todo` detailsconst[,,list]=awaitstub.batch(()=>[stub.class.add('my todo'),stub.class.add('my other todo'),stub.storage.list(),]);returnResponse.json(Object.fromEntries(listasMap<string,string>));

storage methods

DOProxy can be used as Durable Object class as is. It gives you access to Durable Object instance's Transactional storage API methods (excluding transaction which can't be proxied because of JSON serialization. See batch method).

Available methods: DurableObjectStubProxy.storage.get|put|delete|deleteAll|list|getAlarm|setAlarm|deleteAlarm|sync

batch method

If you need to invoke Durable Object instance's multiple times, DurableObjectStubProxy has a batch method which allows you to run multiple method calls inside one fetch request.

Method calls passed to batch will be run in sequence.

constCOUNTER=Counter.wrap(env.Counter);conststub=COUNTER.get(COUNTER.newUniqueId());awaitstub.batch(()=>[stub.class.increment(),stub.class.increment(),stub.storage.deleteAll(),stub.class.increment(),]);// => [1, 2, null, 1]

static wrap(binding: DurableObjectNamespace): DurableObjectNamespaceProxy

This method return DurableObjectNamespace wrapped inside proxy. It has all the same methods that DurableObjectNamespace:

  • newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions | undefined): DurableObjectId;
  • idFromName(name: string): DurableObjectId
  • idFromString(id: string): DurableObjectId
  • get(id: DurableObjectId): DurableObjectStubProxy

It also has some custom shorthand methods:

  • getByName(name: string): DurableObjectStubProxy: Shorthand for DO.get(DO.idFromName('foo'))
  • getByString(id: string): DurableObjectStubProxy: Shorthand for DO.get(DO.idFromString(hexId))

get Method returns DurableObjectStubProxy instead of DurableObjectStub.

DurableObjectStubProxy properties

  • id: DurableObjectId
  • stub: DurableObjectStub: The actual stub if you need access to it
  • storage: Object: Storage methods
  • batch: (callback: () => Promise<unknown>[]) => unknown[]
  • class: Object|undefined: All the class methods if wrap was called on an extended class

Limitations

Remember that we are still doing fetch requests even if it is done in the background, so everything sent to class and storage methods must be JSON serializable.

Other libraries

Not the Durable Object proxy you were looking for?

About

Durable Object Proxy

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages