NestJS integration for Hatchet - a distributed workflow
orchestration engine. Provides type-safe decorators, services, and event
handling for building robust workflows.
yarn add @abinnovision/nestjs-hatchet
This package includes a patched version of @hatchet-dev/typescript-sdk that properly
exports the v1 subdirectory. You can import SDK types and classes directly without
adding the Hatchet SDK as a separate dependency:
import { HatchetClient, Context } from "@abinnovision/nestjs-hatchet/sdk";
import { HatchetModule } from "@abinnovision/nestjs-hatchet";
@Module({
imports: [
HatchetModule.forRoot({
config: {
token: process.env.HATCHET_CLIENT_TOKEN,
tls_config: { tls_strategy: "none" },
},
workerName: "my-worker",
}),
],
})
export class AppModule {}
import { Host, Task, TaskCtx, taskHost } from "@abinnovision/nestjs-hatchet";
import { z } from "zod";
@Host({ name: "process-data" })
export class ProcessDataTask extends taskHost(z.object({ data: z.string() })) {
@Task({})
public async task(ctx: TaskCtx<typeof this>) {
return { result: ctx.input.data.toUpperCase() };
}
}
HatchetModule.forFeature(taskRef(ProcessDataTask));
@Injectable()
export class MyService {
constructor(private client: Client) {}
async process(data: string) {
return this.client.run(taskRef(ProcessDataTask), { data });
}
}
Standalone units of work with a single executable method.
@Host({ name: "cleanup" })
export class CleanupTask extends taskHost() {
@Task({})
public async task(ctx: TaskCtx<typeof this>) {
return { cleaned: true };
}
}
Multi-step processes with task dependencies.
@Host({ name: "order-workflow" })
export class OrderWorkflow extends workflowHost(
z.object({ orderId: z.string() }),
) {
@WorkflowTask<typeof OrderWorkflow>({ parents: [] })
public async validate(ctx: WorkflowCtx<typeof this>) {
return { valid: true };
}
@WorkflowTask<typeof OrderWorkflow>({ parents: ["validate"] })
public async process(ctx: WorkflowCtx<typeof this>) {
const validation = await ctx.parent(this.validate);
return { processed: validation.valid };
}
}
Type-safe event definitions with schema validation.
export const UserCreatedEvent = defineEvent(
"user:created",
z.object({ userId: z.string(), email: z.string().email() }),
);
@Host({ name: "user-handler", onEvents: ["user:created"] })
export class UserHandlerWorkflow extends workflowHost() {
@WorkflowTask<typeof UserHandlerWorkflow>({ parents: [] })
public async handle(ctx: WorkflowCtx<typeof this>) {
if (UserCreatedEvent.isCtx(ctx)) {
return { userId: ctx.input.userId };
}
}
}
await client.emit(UserCreatedEvent, {
userId: "123",
email: "user@example.com",
});
| Method |
Description |
HatchetModule.forRoot(config) |
Initialize with synchronous config |
HatchetModule.forRootAsync(options) |
Initialize with async config factory |
HatchetModule.forFeature(...refs) |
Register tasks/workflows in feature modules |
| Decorator |
Description |
@Host(opts) |
Mark class as task or workflow host |
@Task(opts) |
Mark method as standalone task |
@WorkflowTask(opts) |
Mark method as workflow step |
| Factory |
Description |
taskHost(schema?) |
Create TaskHost base class |
workflowHost(schema?) |
Create WorkflowHost base class |
| Function |
Description |
taskRef(TaskClass) |
Create type-safe task reference |
workflowRef(WorkflowClass) |
Create type-safe workflow reference |
| Method |
Description |
client.run(ref, input, opts?) |
Execute task/workflow |
client.emit(event, payload) |
Emit single event |
client.emitBulk(event, payloads) |
Emit multiple events |
| Type |
Description |
TaskCtx<T> |
Context for task execution |
WorkflowCtx<T> |
Context for workflow tasks |
HelperCtx<T> |
Context for helper methods |
ctx.input
ctx.fromSDK
ctx.run(ref, input, opts ?)
ctx.parent(method)
const runRef = await ctx.run(taskRef(SomeTask), input, { wait: false });
const result = await runRef.output;
await client.emitBulk(OrderEvent, [
{ orderId: "1", total: 100 },
{ orderId: "2", total: 200 },
]);
@Host({ name: "my-task" })
export class MyTask extends taskHost(schema) {
@Task({})
public async task(ctx: TaskCtx<typeof this>) {
return this.helper(ctx);
}
private async helper(ctx: HelperCtx<typeof this>) {
return { result: ctx.input.value };
}
}