Skip to content

Author transforms

import { DurableObject } from 'cloudflare:workers';
import {
applyTransforms,
createTransformContextTarget,
defineTransform,
registerTransform,
} from '@durability/transforms';
type RequestContext = { requestId?: string };
class ExampleObject extends DurableObject<Env> {
setContext(context: RequestContext) {
return createTransformContextTarget(this, context);
}
async greet(name: string) {
return `Hello, ${name}`;
}
}
const observability = defineTransform<ExampleObject, RequestContext>()
.caller(
(requestId: string) =>
async ({ next }) =>
next({ context: { requestId } })
)
.callee((metricName: string) => async ({ context, next }) => {
console.log(metricName, context.requestId);
return next();
});

The caller and callee option types are independent. Their shared context type checks what the caller can send and the target can receive.

applyTransforms(ExampleObject, {
all: [registerTransform(metrics, 'example')],
methods: {
greet: [registerTransform(observability, 'greet_calls')],
},
});

Global transforms run outside method-specific transforms. applyTransforms mutates the class prototype cumulatively; call it once during module initialization, never per request or instance.

const stub = env.EXAMPLE.getByName('example').with(
observability,
crypto.randomUUID()
);
await stub.greet('Ada');

Transforms without options omit the options argument:

registerTransform(betterResultCodec);
stub.with(betterResultCodec);

Named WorkerEntrypoint service bindings use the same model. Apply transforms to the entrypoint class and call .with() on its binding.

A target only needs setContext() when caller transforms send context. Methods that do not propagate context can use caller or callee transforms without it.

When Vite wrapping is unavailable:

import {
createTransformStub,
timeout,
withTransforms,
} from '@durability/transforms';
const service = createTransformStub(env.MY_SERVICE).with(timeout, 5_000);
const namespace = withTransforms(env.MY_DURABLE_OBJECT);
const object = namespace.get(namespace.idFromName('example'))
.with(timeout, 5_000);