Skip to content

@temporal-contract/contract


@temporal-contract/contract / index

index ​

Classes ​

ContractDefinitionError ​

Defined in: packages/contract/src/builder.ts:483

Thrown by defineContract when the contract definition is structurally invalid. path locates the offending slot in dotted notation from the contract root (workflows.processOrder.activities.charge.activityOptions); it is "" for root-level failures.

A plain Error subclass rather than an unthrown TaggedError: the package root must stay importable without the optional unthrown peer, and an invalid contract is a programming error that aborts at import time anyway.

Extends ​

  • Error

Constructors ​

Constructor ​
ts
new ContractDefinitionError(path, message): ContractDefinitionError;

Defined in: packages/contract/src/builder.ts:487

Parameters ​
ParameterType
pathstring
messagestring
Returns ​

ContractDefinitionError

Overrides ​
ts
Error.constructor

Properties ​

PropertyModifierTypeDefault valueOverridesInherited fromDefined in
cause?publicunknownundefined-Error.causenode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.error.d.ts:24
messagepublicstringundefined-Error.messagenode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1075
namereadonly"ContractDefinitionError""ContractDefinitionError"Error.name-packages/contract/src/builder.ts:484
pathreadonlystringundefined--packages/contract/src/builder.ts:485
stack?publicstringundefined-Error.stacknode_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1076

Type Aliases ​

ActivityDefinition ​

ts
type ActivityDefinition<TInput, TOutput, TErrors> = object;

Defined in: packages/contract/src/types.ts:123

Definition of an activity

Type Parameters ​

Type ParameterDefault type
TInput extends AnySchemaAnySchema
TOutput extends AnySchemaAnySchema
TErrors extends Record<string, ErrorDefinition>Record<string, ErrorDefinition>

Properties ​

PropertyModifierTypeDescriptionDefined in
activityOptions?readonlyContractActivityOptions-packages/contract/src/types.ts:131
errors?readonlyTErrors-packages/contract/src/types.ts:130
idempotencyKey?readonly(input) => stringDerive this activity's idempotency key from its input. Temporal runs an activity at least once: a retry, a worker crash, or a completion that succeeded but was never recorded all re-run the implementation. Making the effect idempotent is the application's job, and the usual remedy is handing a stable key to the downstream API (Stripe's Idempotency-Key, and its equivalents). Declaring the key here means the caller and the implementation cannot disagree about what it is. The function receives the validated input (post-parse, so schema transforms have already run) and must be pure and deterministic: the same input has to produce the same key on every attempt, or the key protects nothing. Being derived from the payload rather than from Temporal's own identifiers is what makes it stable across activity retries, worker crashes, and a fresh workflow execution started with the same inputs. (Context.current().info.activityId looks like an alternative and is not: it is a per-run command sequence number, so a re-run that branches differently before this call gets a different value.) The parameter is typed never here, in the structural definition, so a contract written as a plain object literal (satisfies ContractDefinition) still accepts a derivation that narrows its input — a property-position function type is contravariant in its parameter, and this slot's TInput is only known once a concrete schema is bound. defineActivity re-states the slot against the real input type, so the lambda written there is contextually typed and checked. The key reaches the implementation verbatim. Two activities sharing a downstream keyspace must therefore disambiguate in their own derivations (`charge:${orderId}` vs `refund:${orderId}`) — handing a gateway one key for two opposite operations is the failure to avoid. Key on the identity of the operation, not on its parameters. A customer and an amount describe a charge but do not identify it: the same customer legitimately placing two orders of the same value would produce one key, and the second charge would be swallowed as a replay of the first. Good sources, in rough order of preference: - a business identifier already in the input (orderId, invoiceId) — add it to the input schema if it is not there yet, as this example does; - a dedicated idempotencyKey field in the input, minted by the caller when no natural identifier exists; - the workflow ID, which is per-execution and — when the contract derives it (see WorkflowDefinition.workflowId) — is itself a function of the payload. Read it inside the activity from Context.current().info.workflowExecution.workflowId, and combine it with a per-call discriminator if the same activity runs more than once in a workflow. Example const chargeCard = defineActivity({ // orderIdis in the input for the key's sake: it identifies the // charge, where customer and amount only describe it. input: z.object({ orderId: z.string(), customerId: z.string(), amount: z.number(), }), output: PaymentSchema, idempotencyKey: ({ orderId }) =>charge:${orderId}, });packages/contract/src/types.ts:199
inputreadonlyTInput-packages/contract/src/types.ts:128
outputreadonlyTOutput-packages/contract/src/types.ts:129

ActivityRetryPolicy ​

ts
type ActivityRetryPolicy = object;

Defined in: packages/contract/src/types.ts:73

Portable subset of Temporal's RetryPolicy, usable in contract-level activity defaults. Field names and semantics match @temporalio/common's RetryPolicy one-to-one.

Properties ​

PropertyModifierTypeDefined in
backoffCoefficient?readonlynumberpackages/contract/src/types.ts:76
initialInterval?readonlyDurationValuepackages/contract/src/types.ts:74
maximumAttempts?readonlynumberpackages/contract/src/types.ts:77
maximumInterval?readonlyDurationValuepackages/contract/src/types.ts:75
nonRetryableErrorTypes?readonlyreadonly string[]packages/contract/src/types.ts:78

AnySchema ​

ts
type AnySchema = StandardSchemaV1;

Defined in: packages/contract/src/types.ts:10

Base types for validation schemas Any schema that implements the Standard Schema specification This includes Zod, Valibot, ArkType, and other compatible libraries


AnyWorkflowDefinition ​

ts
type AnyWorkflowDefinition = WorkflowDefinition<AnySchema, AnySchema, Record<string, ActivityDefinition>, Record<string, SignalDefinition>, Record<string, QueryDefinition>, Record<string, UpdateDefinition>, Record<string, SearchAttributeDefinition>, Record<string, ErrorDefinition>>;

Defined in: packages/contract/src/types.ts:372

Widened constraint variant of WorkflowDefinition.

WorkflowDefinition (no args) resolves the empty-record generics to Record<string, never>, which is the right default for fresh callers but too narrow as a constraint — a Record-of-WorkflowDefinition constraint built from it would reject any literal whose activities, signals, queries, or updates block is non-empty. AnyWorkflowDefinition widens those generics back to their permissive bounds so it can act as the value of Record<string, …> in ContractDefinition without preventing real workflow definitions from satisfying the constraint.


ClientInferInput ​

ts
type ClientInferInput<T> = StandardSchemaV1.InferInput<T["input"]>;

Defined in: packages/contract/src/types.ts:502

Infer input type from a definition (client perspective) Client sends the input type (before input schema parsing/transformation)

Type Parameters ​

Type Parameter
T extends object

ClientInferOutput ​

ts
type ClientInferOutput<T> = StandardSchemaV1.InferOutput<T["output"]>;

Defined in: packages/contract/src/types.ts:510

Infer output type from a definition (client perspective) Client receives the output type (after output schema parsing/transformation)

Type Parameters ​

Type Parameter
T extends object

ContractActivityOptions ​

ts
type ContractActivityOptions = object;

Defined in: packages/contract/src/types.ts:112

Contract-level default activity options for a single activity — the portable subset of Temporal's ActivityOptions.

Declared on defineActivity so operational behavior (timeouts, retry policy) ships with the contract as a single source of truth shared by every worker, instead of being scattered per-declareWorkflow call.

Merge precedence at the worker (least → most specific): declareWorkflow's activityOptions (workflow-wide default) → this contract-level activityOptions (activity-specific, from the contract author) → activityOptionsByName (explicit per-workflow, per-activity override).

Two options are deliberately excluded and belong to the worker's activityOptionsByName instead:

  • taskQueue — not because queue names are deployment-specific (the contract's own taskQueue is one), but because a per-activity queue here would name a queue no worker built from this contract polls: a TypedWorker only ever binds to its contract's taskQueue. Nothing would check that some worker serves it, and a mismatch fails silently — the task sits unpolled until a scheduleToStartTimeout/scheduleToCloseTimeout fires, or indefinitely without one. To route an activity to a dedicated pool, declare it on an activity-only contract on that queue and call it with context.executeActivity(thatContract, name, { args }) — the queue is then taken from the contract whose worker polls it. (An activityOptionsByName taskQueue override also works, at the cost of repeating the queue name per calling workflow.)
  • cancellationType — how a deployment wants in-flight work torn down.

Properties ​

PropertyModifierTypeDefined in
heartbeatTimeout?readonlyDurationValuepackages/contract/src/types.ts:116
retry?readonlyActivityRetryPolicypackages/contract/src/types.ts:117
scheduleToCloseTimeout?readonlyDurationValuepackages/contract/src/types.ts:114
scheduleToStartTimeout?readonlyDurationValuepackages/contract/src/types.ts:115
startToCloseTimeout?readonlyDurationValuepackages/contract/src/types.ts:113

ContractDefinition ​

ts
type ContractDefinition<TWorkflows, TActivities> = object;

Defined in: packages/contract/src/types.ts:517

Contract definition containing workflows and optional global activities

Type Parameters ​

Type ParameterDefault type
TWorkflows extends Record<string, AnyWorkflowDefinition>Record<string, AnyWorkflowDefinition>
TActivities extends Record<string, ActivityDefinition>Record<string, ActivityDefinition>

Properties ​

PropertyModifierTypeDefined in
activities?readonlyTActivitiespackages/contract/src/types.ts:523
taskQueuereadonlystringpackages/contract/src/types.ts:521
workflowsreadonlyTWorkflowspackages/contract/src/types.ts:522

DurationValue ​

ts
type DurationValue = `${number}${string}` | number | string & object;

Defined in: packages/contract/src/types.ts:66

A Temporal duration: either a number of milliseconds or an ms-formatted string ("30 seconds", "5m", …). Kept as a hand-rolled union rather than Temporal's template-literal Duration type so the contract package stays free of @temporalio/* dependencies; the worker forwards values to Temporal unchanged.

The type is deliberately permissive — it accepts any string. Duration strings are checked at runtime only, by defineContract, against the ms grammar (MS_DURATION_PATTERN in builder.ts), so a malformed value fails when the contract is defined rather than when the worker schedules the activity. There is no compile-time duration check.

  • `${number}${string}` — keeps literal duration strings as themselves in inferred contract types instead of widening them to string.
  • number — a plain number of milliseconds.
  • string & {} — keeps a computed string (e.g. a timeout read from config) assignable without widening the literals above back to string.

ErrorDefinition ​

ts
type ErrorDefinition<TData> = object;

Defined in: packages/contract/src/types.ts:40

Definition of a typed domain error on an activity or workflow.

Declared under the errors map of defineActivity / defineWorkflow, keyed by error name. The name becomes the ApplicationFailure.type discriminator on the wire, so callers (and Temporal retry policies via retry.nonRetryableErrorTypes) can branch on it.

  • data — optional Standard Schema for the structured payload carried in ApplicationFailure.details. Validated on the producing side before the failure crosses the network boundary, and again when it is rehydrated on the consuming side.
  • message — default human-readable message when the producer doesn't supply one at construction time.
  • nonRetryable — when true, Temporal stops retrying immediately. This lives on the contract (not the call site) so retry semantics are part of the shared source of truth. Defaults to false (retryable).

Type Parameters ​

Type ParameterDefault type
TData extends AnySchemaAnySchema

Properties ​

PropertyModifierTypeDefined in
data?readonlyTDatapackages/contract/src/types.ts:41
message?readonlystringpackages/contract/src/types.ts:42
nonRetryable?readonlybooleanpackages/contract/src/types.ts:43

InferActivityNames ​

ts
type InferActivityNames<TContract> = TContract["activities"] extends Record<string, ActivityDefinition> ? keyof TContract["activities"] & string : never;

Defined in: packages/contract/src/types.ts:551

Extract activity names from a contract (global activities) as a union type

Type Parameters ​

Type Parameter
TContract extends ContractDefinition

Example ​

typescript
type MyActivityNames = InferActivityNames<typeof myContract>;
// "log" | "sendEmail"

InferDeclaredErrors ​

ts
type InferDeclaredErrors<TDef> = TDef extends object ? TErrors extends Record<string, ErrorDefinition> ? TErrors : never : never;

Defined in: packages/contract/src/types.ts:392

Extract the declared errors map from an activity or workflow definition, or never when the definition declares none.

The conditional is distributive and infer-based (rather than indexing TDef["errors"] directly) for the same reasons as InferSignalNames: union definitions yield the union of their error maps, and the optional property is tolerated under exactOptionalPropertyTypes.

Type Parameters ​

Type Parameter
TDef

InferErrorData ​

ts
type InferErrorData<TDef> = TDef extends object ? StandardSchemaV1.InferOutput<TSchema> : undefined;

Defined in: packages/contract/src/types.ts:407

Consumer-side data payload of a declared error: the data schema's output type (post-transform), or undefined when the error declares no data schema. This is the shape a workflow sees after an activity's failure is rehydrated, and a client sees after a workflow's failure is rehydrated.

Type Parameters ​

Type Parameter
TDef extends ErrorDefinition

InferErrorDataInput ​

ts
type InferErrorDataInput<TDef> = TDef extends object ? StandardSchemaV1.InferInput<TSchema> : undefined;

Defined in: packages/contract/src/types.ts:418

Producer-side data payload of a declared error: the data schema's input type (pre-transform) — what an implementation passes to the typed error constructor before boundary validation runs.

Type Parameters ​

Type Parameter
TDef extends ErrorDefinition

InferQueryNames ​

ts
type InferQueryNames<W> = W extends object ? Q extends Record<string, QueryDefinition> ? keyof Q & string : never : never;

Defined in: packages/contract/src/types.ts:450

Extract query names declared on a workflow as a string union, or never if the workflow declares no queries. See InferSignalNames for the rationale behind the distributive infer-based shape.

Type Parameters ​

Type Parameter
W extends AnyWorkflowDefinition

InferSignalNames ​

ts
type InferSignalNames<W> = W extends object ? S extends Record<string, SignalDefinition> ? keyof S & string : never : never;

Defined in: packages/contract/src/types.ts:437

Extract signal names declared on a workflow as a string union, or never if the workflow declares no signals. Used to constrain signalName call sites so typos surface at compile time instead of runtime.

The conditional is intentionally distributive over W (rather than indexing W["signals"] directly) so that union workflow types — e.g. discriminated unions of workflow definitions — yield the union of their signal names rather than the intersection (keyof (A | B) is the intersection of keys, which usually collapses to never). Destructuring signals via infer S also tolerates the property being absent or undefined under exactOptionalPropertyTypes.

Type Parameters ​

Type Parameter
W extends AnyWorkflowDefinition

InferUpdateNames ​

ts
type InferUpdateNames<W> = W extends object ? U extends Record<string, UpdateDefinition> ? keyof U & string : never : never;

Defined in: packages/contract/src/types.ts:463

Extract update names declared on a workflow as a string union, or never if the workflow declares no updates. See InferSignalNames for the rationale behind the distributive infer-based shape.

Type Parameters ​

Type Parameter
W extends AnyWorkflowDefinition

InferWorkflowNames ​

ts
type InferWorkflowNames<TContract> = keyof TContract["workflows"] & string;

Defined in: packages/contract/src/types.ts:539

Extract workflow names from a contract as a union type

Type Parameters ​

Type Parameter
TContract extends ContractDefinition

Example ​

typescript
type MyWorkflowNames = InferWorkflowNames<typeof myContract>;
// "processOrder" | "sendNotification"

QueryDefinition ​

ts
type QueryDefinition<TInput, TOutput> = object;

Defined in: packages/contract/src/types.ts:212

Definition of a query

Type Parameters ​

Type ParameterDefault type
TInput extends AnySchemaAnySchema
TOutput extends AnySchemaAnySchema

Properties ​

PropertyModifierTypeDefined in
inputreadonlyTInputpackages/contract/src/types.ts:216
outputreadonlyTOutputpackages/contract/src/types.ts:217

SearchAttributeDefinition ​

ts
type SearchAttributeDefinition<TKind> = object;

Defined in: packages/contract/src/types.ts:268

Definition of a typed search attribute on a workflow.

Type Parameters ​

Type ParameterDefault type
TKind extends SearchAttributeKindSearchAttributeKind

Properties ​

PropertyModifierTypeDefined in
kindreadonlyTKindpackages/contract/src/types.ts:269

SearchAttributeKind ​

ts
type SearchAttributeKind = 
  | "TEXT"
  | "KEYWORD"
  | "INT"
  | "DOUBLE"
  | "BOOL"
  | "DATETIME"
  | "KEYWORD_LIST";

Defined in: packages/contract/src/types.ts:237

The seven Temporal search attribute kinds.

Mirrors @temporalio/common's SearchAttributeType so values flow into Temporal's typedSearchAttributes API unchanged.


SearchAttributeKindToType ​

ts
type SearchAttributeKindToType<T> = object[T];

Defined in: packages/contract/src/types.ts:255

Map each SearchAttributeKind to its TypeScript representation.

  • TEXT / KEYWORD → string
  • INT / DOUBLE → number
  • BOOL → boolean
  • DATETIME → Date
  • KEYWORD_LIST → string[]

Type Parameters ​

Type Parameter
T extends SearchAttributeKind

SignalDefinition ​

ts
type SignalDefinition<TInput> = object;

Defined in: packages/contract/src/types.ts:205

Definition of a signal

Type Parameters ​

Type ParameterDefault type
TInput extends AnySchemaAnySchema

Properties ​

PropertyModifierTypeDefined in
inputreadonlyTInputpackages/contract/src/types.ts:206

UndefinedInputSchema ​

ts
type UndefinedInputSchema = StandardSchemaV1<undefined, undefined>;

Defined in: packages/contract/src/types.ts:20

The Standard Schema type materialized by defineSignal / defineQuery / defineUpdate when their input is omitted: validation only accepts an absent payload and always yields undefined. Because both type faces are undefined, handler inputs infer as undefined on the worker side, and undefined extends ClientInferInput<T> lets the client detect payload-less sends at the type level.


UpdateDefinition ​

ts
type UpdateDefinition<TInput, TOutput> = object;

Defined in: packages/contract/src/types.ts:223

Definition of an update

Type Parameters ​

Type ParameterDefault type
TInput extends AnySchemaAnySchema
TOutput extends AnySchemaAnySchema

Properties ​

PropertyModifierTypeDefined in
inputreadonlyTInputpackages/contract/src/types.ts:227
outputreadonlyTOutputpackages/contract/src/types.ts:228

WorkerInferInput ​

ts
type WorkerInferInput<T> = StandardSchemaV1.InferOutput<T["input"]>;

Defined in: packages/contract/src/types.ts:486

Infer input type from a definition (worker perspective) Worker receives the output type (after input schema parsing/transformation)

Type Parameters ​

Type Parameter
T extends object

WorkerInferOutput ​

ts
type WorkerInferOutput<T> = StandardSchemaV1.InferInput<T["output"]>;

Defined in: packages/contract/src/types.ts:494

Infer output type from a definition (worker perspective) Worker returns the input type (before output schema parsing/transformation)

Type Parameters ​

Type Parameter
T extends object

WorkflowDefinition ​

ts
type WorkflowDefinition<TInput, TOutput, TActivities, TSignals, TQueries, TUpdates, TSearchAttributes, TErrors> = object;

Defined in: packages/contract/src/types.ts:283

Definition of a workflow.

Generic parameters preserve the schema literal types of input/output and the declared shape of activities/signals/queries/updates/search attributes through defineWorkflow so client and worker call sites can infer typed payloads. Empty-collection generics default to Record<string, never> so that, when no signals/queries/updates/etc. are declared, keyof resolves to never rather than string — turning typos in signalName/queryName/updateName into compile-time errors.

Type Parameters ​

Type ParameterDefault type
TInput extends AnySchemaAnySchema
TOutput extends AnySchemaAnySchema
TActivities extends Record<string, ActivityDefinition>Record<string, never>
TSignals extends Record<string, SignalDefinition>Record<string, never>
TQueries extends Record<string, QueryDefinition>Record<string, never>
TUpdates extends Record<string, UpdateDefinition>Record<string, never>
TSearchAttributes extends Record<string, SearchAttributeDefinition>Record<string, never>
TErrors extends Record<string, ErrorDefinition>Record<string, never>

Properties ​

PropertyModifierTypeDescriptionDefined in
activities?readonlyTActivities-packages/contract/src/types.ts:352
errors?readonlyTErrors-packages/contract/src/types.ts:357
inputreadonlyTInput-packages/contract/src/types.ts:293
outputreadonlyTOutput-packages/contract/src/types.ts:294
queries?readonlyTQueries-packages/contract/src/types.ts:354
searchAttributes?readonlyTSearchAttributes-packages/contract/src/types.ts:356
signals?readonlyTSignals-packages/contract/src/types.ts:353
startPolicyreadonlyWorkflowStartPolicyWhether this workflow is safe to re-run under a workflow ID that has already been used. Applied by the client to every startWorkflow / executeWorkflow / signalWithStart, and by the worker to every context.startChildWorkflow / context.executeChildWorkflow of this workflow. Neither offers a per-call workflowIdReusePolicy override: the policy is the contract's. NOT applied to schedule.create — the schedule action type has no workflowIdReusePolicy field, so a schedule action pinning a fixed workflowId gets Temporal's own default (ALLOW_DUPLICATE) regardless of this policy. Required so the question is asked once per workflow rather than silently inheriting Temporal's ALLOW_DUPLICATE. Named for what it governs — Temporal's workflowIdReusePolicy — rather than for idempotency in general. It does not make a workflow idempotent, and it says nothing about an activity running twice under Temporal's at-least-once guarantee; that is an activity's idempotencyKey.packages/contract/src/types.ts:351
updates?readonlyTUpdates-packages/contract/src/types.ts:355
workflowId?readonly(input) => stringDerive this workflow's workflow ID from its input. Declaring it moves the ID from the caller to the contract: every startWorkflow / executeWorkflow / signalWithStart computes the ID from the payload, and passing one explicitly becomes a type error. That is what makes startPolicy mean anything — a caller free to pass crypto.randomUUID() defeats "once-per-id" silently, because every start gets a fresh ID and the policy never fires. The function receives the validated input and must be pure: the same payload has to produce the same ID on every call, or two starts of the same logical request will not collide. NOT applied to schedule.create, which generates one ID per firing — a scheduled run wants a distinct execution, not deduplication. The parameter is typed never here for the same reason as an activity's idempotencyKey (a property-position function type is contravariant, and plain-object contracts must stay assignable); defineWorkflow re-states the slot against the bound input schema, so the lambda written there is contextually typed. Example const processOrder = defineWorkflow({ input: OrderSchema, output: OrderResultSchema, workflowId: ({ orderId }) => orderId, startPolicy: "retry-if-failed", });packages/contract/src/types.ts:328

WorkflowStartPolicy ​

ts
type WorkflowStartPolicy = "once-per-id" | "retry-if-failed" | "allow-duplicate";

Defined in: packages/contract/src/start-policy.ts:14

How a workflow behaves when started again with a workflow ID that has already been used.

Named for the intent rather than Temporal's enum, which names the mechanism: a reader of "retry-if-failed" knows what is protected, where ALLOW_DUPLICATE_FAILED_ONLY has to be decoded.

This governs the Closed-run case only (workflowIdReusePolicy). What happens against a Running run is workflowIdConflictPolicy, which stays a per-call option because different callers legitimately want different answers to "one is already in flight".

Variables ​

CONTRACT_ERROR_TAG ​

ts
const CONTRACT_ERROR_TAG: "@temporal-contract/ContractError" = "@temporal-contract/ContractError";

Defined in: packages/contract/src/error-tags.ts:17

_tag of ContractError — a contract-declared typed domain error.


TECHNICAL_ERROR_TAG ​

ts
const TECHNICAL_ERROR_TAG: "@temporal-contract/TechnicalError" = "@temporal-contract/TechnicalError";

Defined in: packages/contract/src/error-tags.ts:20

_tag of TechnicalError — an infrastructure fault carried as a defect's cause.

Functions ​

defineActivity() ​

ts
function defineActivity<TInput, TOutput, TActivity>(definition): TActivity;

Defined in: packages/contract/src/builder.ts:70

Define a Temporal activity with type-safe input and output schemas.

Activities are the building blocks of Temporal workflows that execute business logic and interact with external services. This function preserves TypeScript types while providing a consistent structure for activity definitions.

Type Parameters ​

Type ParameterDescription
TInput extends AnySchema-
TOutput extends AnySchema-
TActivity extends ActivityDefinition<TInput, TOutput>The activity definition type with input/output schemas

Parameters ​

ParameterTypeDescription
definitionTActivity & object & NoExcessKeys<TActivity, ActivityDefinition>The activity definition containing input and output schemas

Returns ​

TActivity

The same definition with preserved types for type inference

Example ​

typescript
import { defineActivity } from '@temporal-contract/contract';
import { z } from 'zod';

export const sendEmail = defineActivity({
  input: z.object({
    to: z.string().email(),
    subject: z.string(),
    body: z.string(),
  }),
  output: z.object({
    messageId: z.string(),
    sentAt: z.date(),
  }),
  // Typed domain errors — the error name becomes the
  // `ApplicationFailure.type` on the wire, `data` its validated payload,
  // and `nonRetryable` drives Temporal's retry policy from the contract.
  errors: {
    RecipientRejected: {
      data: z.object({ reason: z.string() }),
      nonRetryable: true,
    },
  },
  // Contract-level ActivityOptions defaults shared by every worker.
  // Merge precedence: declareWorkflow's activityOptions
  // < this contract-level activityOptions < activityOptionsByName.
  activityOptions: {
    startToCloseTimeout: "30 seconds",
    retry: { maximumAttempts: 5 },
  },
});

defineContract() ​

ts
function defineContract<TContract>(definition): TContract;

Defined in: packages/contract/src/builder.ts:410

Define a complete Temporal contract with type-safe workflows and activities.

A contract is the central definition that ties together your Temporal application's workflows and activities. It provides:

  • Type safety across client, worker, and workflow code
  • Automatic validation at runtime
  • Compile-time verification of implementations
  • Clear API boundaries and documentation

The contract validates the structure and ensures:

  • Task queue is specified, trimmed, and within Temporal's length limit
  • At least one workflow or global activity is defined (a contract with only global activities and zero workflows is valid — e.g. a dedicated activity-pool task queue)
  • No unknown keys on the contract or on any definition in it (typo protection)
  • Every workflow declares a valid startPolicy
  • Valid JavaScript identifiers that don't collide with Object.prototype members, Temporal-reserved names, Temporal system search attributes, or the worker's own failure types are used
  • No ambiguous name collisions between workflows, global activities, and workflow-specific activities (referencing the same activity definition object from several scopes is allowed), and no search attribute declared with two different kinds
  • Durations and retry policies are ones Temporal accepts
  • All schemas implement the Standard Schema specification

Type Parameters ​

Type ParameterDescription
TContract extends ContractDefinitionThe contract definition type

Parameters ​

ParameterTypeDescription
definitionTContractThe complete contract definition

Returns ​

TContract

The same definition with preserved types for type inference

Throws ​

If the contract structure is invalid

Composition-first. Define resources individually with defineActivity / defineWorkflow (and friends), then reference them here — don't inline definitions in defineContract. Named resources are reusable across workflows and contracts, get precise hover/jump-to-definition, and keep the contract itself a readable table of contents.

Example ​

typescript
import { defineActivity, defineContract, defineWorkflow } from '@temporal-contract/contract';
import { z } from 'zod';

// Define resources first...
const chargePayment = defineActivity({
  input: z.object({ amount: z.number() }),
  output: z.object({ transactionId: z.string() }),
});

const logEvent = defineActivity({
  input: z.object({ message: z.string() }),
  output: z.void(),
});

const processOrder = defineWorkflow({
  input: z.object({ orderId: z.string() }),
  output: z.object({ success: z.boolean() }),
  // Payment already moved money on success — block a second successful
  // run per order. A start is still retryable after a genuinely failed
  // attempt (e.g. a declined payment, where no charge went through).
  startPolicy: 'retry-if-failed',
  activities: { chargePayment },
});

// ...then compose the contract from references.
export const myContract = defineContract({
  taskQueue: 'orders',
  workflows: { processOrder },
  // Optional global activities shared across workflows
  activities: { logEvent },
});

defineContractBinding() ​

ts
function defineContractBinding<C, Queue>(contract, options): Omit<C, "taskQueue"> & object;

Defined in: packages/contract/src/binding.ts:17

Bind a compatible protocol to a deployment task queue without changing its workflow names, schemas, activity destinations or workflow execution IDs. Resolve before starting work, or from a recorded decision during replay.

Type Parameters ​

Type ParameterDescription
C extends ContractDefinitionThe source protocol contract
Queue extends stringThe physical deployment task queue

Parameters ​

ParameterTypeDescription
contractCThe protocol whose definitions remain shared
options{ taskQueue: Queue; }The deployment destination
options.taskQueueQueueA non-empty, trimmed queue name within Temporal's limit

Returns ​

Omit<C, "taskQueue"> & object

A new validated contract preserving definitions and the queue's literal type

Throws ​

If the bound contract or task queue is invalid


defineQuery() ​

Call Signature ​

ts
function defineQuery<TQuery>(definition): TQuery;

Defined in: packages/contract/src/builder.ts:172

Define a Temporal query with type-safe input and output schemas.

Queries allow you to read the current state of a running workflow without modifying it. They are synchronous and should not perform any mutations.

Synchronous validation required. Temporal query handlers must complete synchronously, so the input and output schemas you pass here must validate synchronously. In practice this rules out async refinements (e.g. Zod's .refine(async (x) => …)). Standard Schema doesn't expose the sync/async distinction at the type level, so the worker checks at runtime and throws if it ever receives a Promise from ~standard.validate. Use plain Zod / Valibot / ArkType object schemas without async refinements.

Type Parameters ​
Type ParameterDescription
TQuery extends QueryDefinitionThe query definition type with input/output schemas
Parameters ​
ParameterTypeDescription
definitionTQuery & NoExcessKeys<TQuery, QueryDefinition>The query definition containing input and output schemas
Returns ​

TQuery

The same definition with preserved types for type inference

input may be omitted for argument-less queries: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineQuery } from '@temporal-contract/contract';
import { z } from 'zod';

export const getOrderStatus = defineQuery({
  input: z.object({ orderId: z.string() }),
  output: z.object({
    status: z.enum(['pending', 'processing', 'completed', 'failed']),
    updatedAt: z.date(),
  }),
});

// Argument-less query — the handler input is `undefined`.
export const getProgress = defineQuery({
  output: z.object({ percent: z.number() }),
});

Call Signature ​

ts
function defineQuery<TOutput>(definition): QueryDefinition<UndefinedInputSchema, TOutput>;

Defined in: packages/contract/src/builder.ts:175

Define a Temporal query with type-safe input and output schemas.

Queries allow you to read the current state of a running workflow without modifying it. They are synchronous and should not perform any mutations.

Synchronous validation required. Temporal query handlers must complete synchronously, so the input and output schemas you pass here must validate synchronously. In practice this rules out async refinements (e.g. Zod's .refine(async (x) => …)). Standard Schema doesn't expose the sync/async distinction at the type level, so the worker checks at runtime and throws if it ever receives a Promise from ~standard.validate. Use plain Zod / Valibot / ArkType object schemas without async refinements.

Type Parameters ​
Type Parameter
TOutput extends AnySchema
Parameters ​
ParameterTypeDescription
definition{ input?: undefined; output: TOutput; }The query definition containing input and output schemas
definition.input?undefined-
definition.outputTOutput-
Returns ​

QueryDefinition<UndefinedInputSchema, TOutput>

The same definition with preserved types for type inference

input may be omitted for argument-less queries: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineQuery } from '@temporal-contract/contract';
import { z } from 'zod';

export const getOrderStatus = defineQuery({
  input: z.object({ orderId: z.string() }),
  output: z.object({
    status: z.enum(['pending', 'processing', 'completed', 'failed']),
    updatedAt: z.date(),
  }),
});

// Argument-less query — the handler input is `undefined`.
export const getProgress = defineQuery({
  output: z.object({ percent: z.number() }),
});

defineSearchAttribute() ​

ts
function defineSearchAttribute<TKind>(definition): SearchAttributeDefinition<TKind>;

Defined in: packages/contract/src/builder.ts:276

Define a typed search attribute on a workflow.

Search attributes are indexed on Temporal's visibility store and let you query / filter workflow executions by domain attributes. Declaring them on the contract means the client's workflow-start options and (eventually) the worker's search-attribute reader are constrained to declared keys with the right value types.

Type Parameters ​

Type Parameter
TKind extends SearchAttributeKind

Parameters ​

ParameterType
definitionSearchAttributeDefinition<TKind>

Returns ​

SearchAttributeDefinition<TKind>

Example ​

typescript
import { defineSearchAttribute } from '@temporal-contract/contract';

defineWorkflow({
  input: z.object({ orderId: z.string() }),
  output: z.object({ status: z.string() }),
  startPolicy: 'allow-duplicate',
  searchAttributes: {
    customerId: defineSearchAttribute({ kind: 'KEYWORD' }),
    priority: defineSearchAttribute({ kind: 'INT' }),
    placedAt: defineSearchAttribute({ kind: 'DATETIME' }),
  },
});

The seven Temporal kinds map to TypeScript types like so:

kindTS type
TEXTstring
KEYWORDstring
INTnumber
DOUBLEnumber
BOOLboolean
DATETIMEDate
KEYWORD_LISTstring[]

defineSignal() ​

Call Signature ​

ts
function defineSignal<TSignal>(definition): TSignal;

Defined in: packages/contract/src/builder.ts:119

Define a Temporal signal with type-safe input schema.

Signals are asynchronous messages sent to running workflows to update their state or trigger certain behaviors. This function ensures type safety for signal payloads.

Type Parameters ​
Type ParameterDescription
TSignal extends SignalDefinitionThe signal definition type with input schema
Parameters ​
ParameterTypeDescription
definitionTSignal & NoExcessKeys<TSignal, SignalDefinition>The signal definition containing input schema
Returns ​

TSignal

The same definition with preserved types for type inference

input may be omitted for payload-less signals: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineSignal } from '@temporal-contract/contract';
import { z } from 'zod';

export const approveOrder = defineSignal({
  input: z.object({
    orderId: z.string(),
    approvedBy: z.string(),
  }),
});

// Payload-less signal — the handler input is `undefined`.
export const shutdown = defineSignal();

Call Signature ​

ts
function defineSignal(definition?): SignalDefinition<UndefinedInputSchema>;

Defined in: packages/contract/src/builder.ts:122

Define a Temporal signal with type-safe input schema.

Signals are asynchronous messages sent to running workflows to update their state or trigger certain behaviors. This function ensures type safety for signal payloads.

Parameters ​
ParameterTypeDescription
definition?{ input?: undefined; }The signal definition containing input schema
definition.input?undefined-
Returns ​

SignalDefinition<UndefinedInputSchema>

The same definition with preserved types for type inference

input may be omitted for payload-less signals: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineSignal } from '@temporal-contract/contract';
import { z } from 'zod';

export const approveOrder = defineSignal({
  input: z.object({
    orderId: z.string(),
    approvedBy: z.string(),
  }),
});

// Payload-less signal — the handler input is `undefined`.
export const shutdown = defineSignal();

defineUpdate() ​

Call Signature ​

ts
function defineUpdate<TUpdate>(definition): TUpdate;

Defined in: packages/contract/src/builder.ts:224

Define a Temporal update with type-safe input and output schemas.

Updates are similar to signals but return a value and wait for the workflow to process them before completing. They provide a synchronous way to modify workflow state and get immediate feedback.

Type Parameters ​
Type ParameterDescription
TUpdate extends UpdateDefinitionThe update definition type with input/output schemas
Parameters ​
ParameterTypeDescription
definitionTUpdate & NoExcessKeys<TUpdate, UpdateDefinition>The update definition containing input and output schemas
Returns ​

TUpdate

The same definition with preserved types for type inference

input may be omitted for argument-less updates: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineUpdate } from '@temporal-contract/contract';
import { z } from 'zod';

export const updateOrderQuantity = defineUpdate({
  input: z.object({
    orderId: z.string(),
    newQuantity: z.number().positive(),
  }),
  output: z.object({
    success: z.boolean(),
    totalPrice: z.number(),
  }),
});

// Argument-less update — the handler input is `undefined`.
export const restock = defineUpdate({
  output: z.object({ restocked: z.boolean() }),
});

Call Signature ​

ts
function defineUpdate<TOutput>(definition): UpdateDefinition<UndefinedInputSchema, TOutput>;

Defined in: packages/contract/src/builder.ts:227

Define a Temporal update with type-safe input and output schemas.

Updates are similar to signals but return a value and wait for the workflow to process them before completing. They provide a synchronous way to modify workflow state and get immediate feedback.

Type Parameters ​
Type Parameter
TOutput extends AnySchema
Parameters ​
ParameterTypeDescription
definition{ input?: undefined; output: TOutput; }The update definition containing input and output schemas
definition.input?undefined-
definition.outputTOutput-
Returns ​

UpdateDefinition<UndefinedInputSchema, TOutput>

The same definition with preserved types for type inference

input may be omitted for argument-less updates: the definition then carries a materialized schema whose validated value is always undefined, so the handler input infers as undefined — no z.void() ceremony.

Example ​
typescript
import { defineUpdate } from '@temporal-contract/contract';
import { z } from 'zod';

export const updateOrderQuantity = defineUpdate({
  input: z.object({
    orderId: z.string(),
    newQuantity: z.number().positive(),
  }),
  output: z.object({
    success: z.boolean(),
    totalPrice: z.number(),
  }),
});

// Argument-less update — the handler input is `undefined`.
export const restock = defineUpdate({
  output: z.object({ restocked: z.boolean() }),
});

defineWorkflow() ​

ts
function defineWorkflow<TInput, TWorkflow>(definition): TWorkflow;

Defined in: packages/contract/src/builder.ts:319

Define a Temporal workflow with type-safe input, output, and associated operations.

Workflows are durable functions that orchestrate activities, handle timeouts, and manage long-running processes. This function provides type safety for the entire workflow definition including activities, signals, queries, and updates.

Type Parameters ​

Type ParameterDescription
TInput extends AnySchema-
TWorkflow extends AnyWorkflowDefinition & objectThe workflow definition type with all associated schemas

Parameters ​

ParameterTypeDescription
definitionTWorkflow & object & NoExcessKeys<TWorkflow, AnyWorkflowDefinition>The workflow definition containing input, output, and operations

Returns ​

TWorkflow

The same definition with preserved types for type inference

Example ​

typescript
import { defineWorkflow, defineActivity, defineSignal } from '@temporal-contract/contract';
import { z } from 'zod';

export const processOrder = defineWorkflow({
  input: z.object({ orderId: z.string() }),
  output: z.object({ success: z.boolean() }),
  // Payment already moved money on success — block a second successful
  // run per order. A start is still retryable after a genuinely failed
  // attempt (e.g. a declined payment, where no charge went through).
  startPolicy: 'retry-if-failed',
  activities: {
    chargePayment: defineActivity({
      input: z.object({ orderId: z.string(), amount: z.number() }),
      output: z.object({ transactionId: z.string() }),
    }),
  },
  signals: {
    cancel: defineSignal({
      input: z.object({ reason: z.string() }),
    }),
  },
});

formatIssue() ​

ts
function formatIssue(issue): string;

Defined in: packages/contract/src/format.ts:36

Render a Standard Schema StandardSchemaV1.Issue into a human-readable string that includes the failing field's path.

Example output:

  • at items[0].quantity: Expected number, received undefined
  • at customerId: Expected string, received undefined
  • at user["first name"]: Expected string, received undefined
  • Validation error (no path)

The schema's message is included verbatim, and schema libraries embed the raw input in it (Valibot: Invalid email: Received "jane@x"). Use it for in-process diagnostics only — never for text that crosses a Temporal boundary; summarizeIssues is the redacted form for that.

Parameters ​

ParameterType
issueIssue

Returns ​

string


summarizeIssues() ​

ts
function summarizeIssues(issues): string;

Defined in: packages/contract/src/format.ts:58

Join a list of validation issues into a single, redacted message: only the failing paths, never the schema-provided message text, capped at the first five issues — e.g. at items[0].quantity; at customerId; …and 3 more (at root for an issue on the value itself).

The summary becomes ApplicationFailure.message in Temporal history, which payload codecs do not encrypt, and schema libraries embed raw input values in their messages (Valibot: Invalid email: Received "jane@x") — so the messages are dropped and the length is bounded. The full issues stay available, in process, on the error objects' issues property.

Parameters ​

ParameterType
issuesreadonly Issue[]

Returns ​

string

Released under the MIT License.