Skip to content

Parse the resolution at the boundary

Resolving from anywhereSDKparseResolverPayloadResolverPayloadTypeErrorschemaVersion

One zod schema gives the workflow its type, its runtime check and its version pin, so resolver payloads enter code already parsed.

The situation

Enforcement guarantees what entered the system. The workflow still receives a plain object, and code that reaches into it by hand drifts from the form over time.

The recipe

forms/intake.ts
import { z } from 'zod';
export const INTAKE_SCHEMA_VERSION = 3;
export const IntakeResolverV1Schema = z.object({
customer: z.object({ name: z.string(), email: z.string() }),
contract: z.object({ tier: z.enum(['starter', 'professional']), approved: z.boolean() }),
});
export type IntakeResolverV1 = z.infer<typeof IntakeResolverV1Schema>;
activities/intake.ts
import { parseResolverPayload } from '@hotmeshio/long-tail/build/sdk/index.js';
import { IntakeResolverV1Schema } from '../forms/intake';
export async function recordIntake(response: unknown) {
const intake = parseResolverPayload(IntakeResolverV1Schema, response);
return saveCustomer(intake.customer.name, intake.contract.tier);
}

The workflow pins schemaVersion: INTAKE_SCHEMA_VERSION on its conditional, so the form people see and the schema code parses stay in step.

The guarantee

A payload that does not conform throws ResolverPayloadTypeError carrying the same field and message violation list as the server’s 422, with the ZodError as cause. Parse inside an activity so the check is checkpointed. See Schema enforcement.