2.4.1 • Published 1 year ago

itty-durable v2.4.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

itty-durable

npm package Build Status Open Issues

Simplifies usage of Cloudflare Durable Objects, allowing lightweight object definitions and direct access to object methods from within Workers (no need for request building/handling).

Features

  • Removes nearly all boilerplate from using Durable Objects, by automatically handling request building/handling internally via itty-router
  • Optional, automatic non-blocking persistance layer
  • Optionally return Durable contents from methods without explicit return (convenience feature)
  • Control how contents of Durable look to outside requests
  • Control what, if anything, is persisted

Installation

npm install itty-durable

Example

Counter.js (your Durable Object class)
import { createIttyDurable } from 'itty-durable'

export class Counter extends createIttyDurable({ autoReturn: true }) {
  constructor(state, env) {
    super(state, env)

    // anything defined here is only used for initialization (if not loaded from storage)
    this.counter = 0
  }

  // Because this function does not return anything, it will return the entire contents
  // Example: { counter: 1 }
  increment() {
    this.counter++
  }

  // Any explicit return will honored, despite the autoReturn flag.
  // Note that any serializable params can passed through from the Worker without issue.
  add(a, b) {
    return a + b
  }
}
Worker.js (your CF Worker function)
import { ThrowableRouter, missing, withParams } from 'itty-router-extras'
import { withDurables } from 'itty-durable'

// export the durable class, per spec
export { Counter } from './Counter'

const router = ThrowableRouter({ base: '/counter' })

router
  // add upstream middleware, allowing Durable access off the request
  .all('*', withDurables())

  // get the durable itself... returns json response, so no need to wrap
  .get('/', ({ Counter }) => Counter.get('test').toJSON())

  // example route with multiple calls to DO
  .get('/increment-a-few-times',
    async ({ Counter }) => {
      const counter = Counter.get('test') // gets DO with id/namespace = 'test'

      // then we fire some methods on the durable... these could all be done separately.
      await Promise.all([
        counter.increment(),
        counter.increment(),
        counter.increment(),
      ])

      // and return the contents (it'll be a json response)
      return counter.toJSON()
    }
  )

  // reset the durable)
  .get('/reset', ({ Counter }) => Counter.get('test').reset())

  // will pass on unknown requests to the durable... (e.g. /counter/add/3/4 => 7)
  .get('/:action/:a?/:b?', withParams,
    ({ Counter, action, a, b }) => Counter.get('test')[action](Number(a), Number(b))
  )

  // 404 for everything else
  .all('*', () => missing('Are you sure about that?'))

// with itty, and using ES6 module syntax (required for DO), this is all you need
export default {
  fetch: router.handle
}

Interacting with it!

GET /counter/increment-a-few-times          => { counter: 3 }
GET /counter/increment-a-few-times          => { counter: 6 }
GET /counter/reset                          => { counter: 0 }
GET /counter/increment                      => { counter: 1 }
GET /counter/increment                      => { counter: 2 }
GET /counter/add/20/3                       => 23
GET /counter                                => { counter: 2 }

(more examples to come shortly, hang tight!)

Exports

IttyDurable: class

Base class to extend, with persistOnChange, but no timestamps.

createIttyDurable(options = {}): class

Factory function for defining another IttyDurable class (different base options).

withDurables(options = {})

This is the Worker middleware to put either on routes individually, up globally as an upstream route. This allows requests for the DO binding directly off the request, and simplifies even the id translation. Any durable stubs retrieved this way automatically talk to the router within IttyDurable (base class) when accessing instance methods on the stub, allowing all fetch boilerplate to be abstracted away.

Special Thanks

Big time thanks to all the fantastic developers on the Cloudflare Workers discord group, for their putting up with my constant questions, code snippets, and guiding me off the dangerously flawed path of async setters ;)

Contributors

Let's face it, in open source, these are the real heroes... improving the quality of libraries out there for everyone!

  • README tweaks, fixes, improvements: @tomByrer
3.0.0-next.2

1 year ago

3.0.0-next.1

1 year ago

3.0.0-next.3

1 year ago

3.0.0-next.0

1 year ago

2.4.1

1 year ago

2.4.0

1 year ago

2.3.0

1 year ago

2.2.0

1 year ago

2.1.0

2 years ago

2.0.0

2 years ago

1.6.0-next.0

2 years ago

1.6.0

3 years ago

1.5.0

3 years ago

1.4.0

3 years ago

1.3.1

3 years ago

1.3.0

3 years ago

1.2.0

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.1.2

3 years ago

1.0.0

3 years ago

0.4.0-next.0

3 years ago

0.4.0-next.1

3 years ago

0.4.0

4 years ago

0.3.0

4 years ago

0.3.2

4 years ago

0.3.1

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.5

4 years ago

0.1.4

4 years ago

0.1.3

4 years ago

0.1.2

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago