---
url: https://node-ts.github.io/bus/api/bus-core/interfaces/FunctionWorkflow.md
---
[API reference](../../index.md) / [@node-ts/bus-core](../index.md) / FunctionWorkflow

# Interface: FunctionWorkflow\<TWorkflowState>

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:77](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L77)

A workflow declared with `defineWorkflow`. Each `startedBy` and `when` returns a new workflow with the handler
added, so a workflow can be built up step by step and registered with `withWorkflow()`.

What a handler returns is checked against the workflow state: fields of the wrong type, and fields at any depth
that aren't in the state, don't compile. See `CheckedWorkflowHandler` for what can't be checked.

## Type Parameters

| Type Parameter |
| ------ |
| `TWorkflowState` *extends* [`WorkflowState`](../classes/WorkflowState.md) |

## Properties

| Property | Modifier | Type | Description | Defined in |
| ------ | ------ | ------ | ------ | ------ |
| <a id="property-name"></a> `name` | `readonly` | `string` | The name of the workflow, which is the `$name` of its state | [packages/bus-core/src/workflow/define-workflow.ts:81](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L81) |
| <a id="property-workflowstatetype"></a> `workflowStateType` | `readonly` | [`WorkflowStateConstructor`](../type-aliases/WorkflowStateConstructor.md)<`TWorkflowState`> | The class of the workflow's state | [packages/bus-core/src/workflow/define-workflow.ts:86](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L86) |

## Methods

### startedBy()

```ts
startedBy<TMessage, THandler>(message, handler): FunctionWorkflow<TWorkflowState>;
```

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:105](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L105)

Starts a new instance of the workflow each time `message` is handled.

Messages are delivered at least once and starts aren't deduplicated, so a `message` that's retried after the
new workflow state was saved starts a second workflow instance. Make the handler idempotent, such as by
returning `ctx.discard()` when a workflow already exists for the message, if that matters.

#### Type Parameters

| Type Parameter |
| ------ |
| `TMessage` *extends* [`Message`](../../bus-messages/classes/Message.md) |
| `THandler` *extends* (`message`, `workflowState`, `context`) => | [`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`> | `Promise`<[`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`>> |

#### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | [`MessageDeclaration`](../../bus-messages/type-aliases/MessageDeclaration.md)<`TMessage`> | The message that starts the workflow: a message class, or a definition from `defineCommand` or `defineEvent` |
| `handler` | `THandler` & [`CheckedWorkflowHandler`](../type-aliases/CheckedWorkflowHandler.md)<`THandler`, `TWorkflowState`> | Handles `message`, and returns the initial workflow state |

#### Returns

`FunctionWorkflow`<`TWorkflowState`>

A new workflow with the handler added

#### Throws

WorkflowAlreadyStartedByMessage if the workflow is already started by `message`

#### Example

```ts
defineWorkflow(OrderState).startedBy(OrderPlaced, async (message, _state, ctx) => {
  await ctx.send(new ChargeCard(message.orderId))
  return { orderId: message.orderId }
})
```

***

### startedByHandler()

```ts
startedByHandler<TMessage>(message): (message, workflowState, context) => Promise<WorkflowHandlerResult<TWorkflowState>>;
```

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:165](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L165)

Gets the `startedBy` handler of `message`, typed by the message, to call it directly in a test

#### Type Parameters

| Type Parameter |
| ------ |
| `TMessage` *extends* [`Message`](../../bus-messages/classes/Message.md) |

#### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | [`MessageDeclaration`](../../bus-messages/type-aliases/MessageDeclaration.md)<`TMessage`> | The message the workflow is started by |

#### Returns

The handler

(`message`, `workflowState`, `context`) => `Promise`<[`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`>>

#### Throws

WorkflowDoesNotHandleMessage if the workflow isn't started by `message`

#### Example

```ts
const result = await orderWorkflow.startedByHandler(OrderPlaced)(OrderPlaced({ orderId: '1' }), state, workflowContext())
```

***

### when()

#### Call Signature

```ts
when<TMessage, THandler>(message, handler): FunctionWorkflow<TWorkflowState>;
```

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:125](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L125)

Dispatches `message` to the running instances of the workflow that have the `workflowId` sticky attribute of
the message. Messages sent from the workflow, and replies to them, carry it.

##### Type Parameters

| Type Parameter |
| ------ |
| `TMessage` *extends* [`Message`](../../bus-messages/classes/Message.md) |
| `THandler` *extends* (`message`, `workflowState`, `context`) => | [`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`> | `Promise`<[`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`>> |

##### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | [`MessageDeclaration`](../../bus-messages/type-aliases/MessageDeclaration.md)<`TMessage`> | The message to handle: a message class, or a definition from `defineCommand` or `defineEvent` |
| `handler` | `THandler` & [`CheckedWorkflowHandler`](../type-aliases/CheckedWorkflowHandler.md)<`THandler`, `TWorkflowState`> | Handles `message` |

##### Returns

`FunctionWorkflow`<`TWorkflowState`>

A new workflow with the handler added

##### Throws

WorkflowAlreadyHandlesMessage if the workflow already handles `message`

##### Example

```ts
defineWorkflow(OrderState)
  .startedBy(OrderPlaced, ...)
  .when(CardCharged, (_message, _state, ctx) => ctx.complete({ charged: true }))
```

#### Call Signature

```ts
when<TMessage, THandler>(
   message, 
   mapping, 
   handler
): FunctionWorkflow<TWorkflowState>;
```

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:148](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L148)

Dispatches `message` to the running instances of the workflow that `mapping` finds

##### Type Parameters

| Type Parameter |
| ------ |
| `TMessage` *extends* [`Message`](../../bus-messages/classes/Message.md) |
| `THandler` *extends* (`message`, `workflowState`, `context`) => | [`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`> | `Promise`<[`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`>> |

##### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | [`MessageDeclaration`](../../bus-messages/type-aliases/MessageDeclaration.md)<`TMessage`> | The message to handle: a message class, or a definition from `defineCommand` or `defineEvent` |
| `mapping` | [`MessageWorkflowMapping`](MessageWorkflowMapping.md)<`TMessage`, `TWorkflowState`> | Finds the workflow instances whose `mapsTo` field matches the value `lookup` returns for `message`. `mapsTo` must be a field of the workflow state. |
| `handler` | `THandler` & [`CheckedWorkflowHandler`](../type-aliases/CheckedWorkflowHandler.md)<`THandler`, `TWorkflowState`> | Handles `message` |

##### Returns

`FunctionWorkflow`<`TWorkflowState`>

A new workflow with the handler added

##### Throws

WorkflowAlreadyHandlesMessage if the workflow already handles `message`

##### Example

```ts
defineWorkflow(OrderState)
  .startedBy(OrderPlaced, ...)
  .when(CardCharged, { lookup: m => m.orderId, mapsTo: 'orderId' }, (_message, _state, ctx) =>
    ctx.complete({ charged: true })
  )
```

***

### whenHandler()

```ts
whenHandler<TMessage>(message): (message, workflowState, context) => Promise<WorkflowHandlerResult<TWorkflowState>>;
```

Defined in: [packages/bus-core/src/workflow/define-workflow.ts:177](https://github.com/node-ts/bus/blob/2e6cf65c27833b707ae31ee623cfb6343770f434/packages/bus-core/src/workflow/define-workflow.ts#L177)

Gets the `when` handler of `message`, typed by the message, to call it directly in a test

#### Type Parameters

| Type Parameter |
| ------ |
| `TMessage` *extends* [`Message`](../../bus-messages/classes/Message.md) |

#### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `message` | [`MessageDeclaration`](../../bus-messages/type-aliases/MessageDeclaration.md)<`TMessage`> | The message the workflow handles |

#### Returns

The handler

(`message`, `workflowState`, `context`) => `Promise`<[`WorkflowHandlerResult`](../type-aliases/WorkflowHandlerResult.md)<`TWorkflowState`>>

#### Throws

WorkflowDoesNotHandleMessage if the workflow has no `when` handler for `message`

#### Example

```ts
const result = await orderWorkflow.whenHandler(CardCharged)(new CardCharged('1'), state, workflowContext())
```
