defineHook()
Creates a type-safe hook helper that ensures the payload type is consistent between hook creation and resumption.
This is a lightweight wrapper around createHook() and resumeHook() to avoid type mismatches. It also supports optional runtime validation and transformation of payloads using any Standard Schema v1 compliant validator like Zod or Valibot.
We recommend using defineHook() over createHook() in production codebases for better type safety and optional runtime validation.
import { defineHook } from "workflow";
const nameHook = defineHook<{
name: string;
}>();
export async function nameWorkflow() {
"use workflow";
const hook = nameHook.create();
const result = await hook; // Fully typed as { name: string }
console.log('Name:', result.name);
}API Signature
Parameters
| Name | Type | Description |
|---|---|---|
__0 | { schema?: StandardSchemaV1<TInput, TOutput>; } | Schema used to validate and transform the input payload before resuming |
Returns
| Name | Type | Description |
|---|---|---|
create | (options?: any) => Hook<T> | Creates a new hook with the defined payload type. |
resume | (token: string, payload: T) => Promise<any> | Resumes a hook by sending a payload with the defined type. |
Examples
Basic Type-Safe Hook Definition
By defining the hook once with a specific payload type, you can reuse it in multiple workflows and API routes with automatic type safety.
import { defineHook } from "workflow";
// Define once with a specific payload type
const approvalHook = defineHook<{
approved: boolean;
comment: string;
}>();
// In your workflow
export async function workflowWithApproval() {
"use workflow";
const hook = approvalHook.create();
const result = await hook; // Fully typed as { approved: boolean; comment: string }
console.log('Approved:', result.approved);
console.log('Comment:', result.comment);
}Resuming with Type Safety
Hooks can be resumed using the same defined hook and a token. By using the same hook, you can ensure that the payload matches the defined type when resuming a hook.
// Use the same defined hook to resume
export async function POST(request: Request) {
const { token, approved, comment } = await request.json();
// Type-safe resumption - TypeScript ensures the payload matches
const result = await approvalHook.resume(token, {
approved,
comment,
});
if (!result) {
return Response.json({ error: 'Hook not found' }, { status: 404 });
}
return Response.json({ success: true, runId: result.runId });
}Validate and Transform with Schema
You can provide runtime validation and transformation of hook payloads using the schema option. This option accepts any validator that conforms to the Standard Schema v1 specification.
Standard Schema is a standardized specification for schema validation libraries. Most popular validation libraries support it, including Zod, Valibot, ArkType, and Effect Schema. You can also write custom validators.
Using Zod with defineHook
Here's an example using Zod to validate and transform hook payloads:
import { defineHook } from "workflow";
import { z } from "zod";
export const approvalHook = defineHook({
schema: z.object({
approved: z.boolean(),
comment: z.string().min(1).transform((value) => value.trim()),
}),
});
export async function approvalWorkflow(approvalId: string) {
"use workflow";
const hook = approvalHook.create({
token: `approval:${approvalId}`,
});
// Payload is automatically typed based on the schema
const { approved, comment } = await hook;
console.log('Approved:', approved);
console.log('Comment (trimmed):', comment);
}When resuming the hook from an API route, the schema validates and transforms the incoming payload before the workflow resumes:
export async function POST(request: Request) {
// Incoming payload: { token: "...", approved: true, comment: " Ready! " }
const { token, approved, comment } = await request.json();
// The schema validates and transforms the payload:
// - Checks that `approved` is a boolean
// - Checks that `comment` is a non-empty string
// - Trims whitespace from the comment
// If validation fails, an error is thrown and the hook is not resumed
await approvalHook.resume(token, {
approved,
comment, // Automatically trimmed to "Ready!"
});
return Response.json({ success: true });
}Using Other Standard Schema Libraries
The same pattern works with any Standard Schema v1 compliant library. Here's an example with Valibot:
import { defineHook } from "workflow";
import * as v from "valibot";
export const approvalHook = defineHook({
schema: v.object({
approved: v.boolean(),
comment: v.pipe(v.string(), v.minLength(1), v.trim()),
}),
});Customizing Tokens
Tokens are used to identify a specific hook and for resuming a hook. You can customize the token to be more specific to a use case.
const slackHook = defineHook<{ text: string; userId: string }>();
export async function slackBotWorkflow(channelId: string) {
"use workflow";
const hook = slackHook.create({
token: `slack:${channelId}`,
});
const message = await hook;
console.log(`Message from ${message.userId}: ${message.text}`);
}Related Functions
-
createHook()- Create a hook in a workflow. -
resumeHook()- Resume a hook with a payload.