itty-durable v2.4.1
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
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago