Author transforms
Define both boundaries
Section titled “Define both boundaries”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.
Register on the callee
Section titled “Register on the callee”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.
Apply on the caller
Section titled “Apply on the caller”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);Worker entrypoints
Section titled “Worker entrypoints”Named WorkerEntrypoint service bindings use the same model. Apply transforms to the entrypoint class and call .with() on its binding.
Context is not identity
Section titled “Context is not identity”A target only needs setContext() when caller transforms send context. Methods that do not propagate context can use caller or callee transforms without it.
Manual wrapping
Section titled “Manual wrapping”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);