# 25.0.1 API Reference
- [Engine](#engine)
- [`new Engine([options])`](#new-engineoptions)
- [`execute([options[, callback]])`](#executeoptions-callback)
- [Execution `listener`](#execution-listener)
- [Execution `variables`](#execution-variables)
- [Execution `services`](#execution-services)
- [`async getDefinitionById(id)`](#async-getdefinitionbyidid)
- [`addSource({sourceContext})`](#addsourcesourcecontext)
- [`getDefinitions()`](#getdefinitions)
- [`getState()`](#getstate)
- [`stop()`](#stop)
- [`recover(state[, recoverOptions])`](#recoverstate-recoveroptions)
- [`resume([options, [callback]])`](#resumeoptions-callback)
- [Execution API](#execution-api)
- [`getActivityById(activityId)`](#getactivitybyidactivityid)
- [`getState()`](#getstate)
- [`signal(message[, options])`](#signalmessage-options)
- [`cancelActivity(message)`](#cancelactivitymessage)
- [Engine events](#engine-events)
- [Activity events](#activity-events)
- [Event Api](#event-api)
- [Sequence flow events](#sequence-flow-events)
- [Expressions](#expressions)
# Engine
The engine. Executes passed BPMN 2.0 definitions.
## `new Engine([options])`
Creates a new Engine.
Arguments:
- `options`: Optional options, passed to [environment](https://github.com/paed01/bpmn-elements/blob/master/docs/Environment.md):
- `disableDummyScript`: optional boolean to disable dummy script supplied to empty ScriptTask
- `elements`: optional object with element type mapping override
- `expressions`: optional override [expressions](#expressions) handler
- `extendFn`: optional extend [serializer](https://github.com/paed01/moddle-context-serializer/blob/master/API.md) function
- `Logger`: optional [Logger factory](https://github.com/paed01/bpmn-elements/blob/master/docs/Environment.md#logger), defaults to [debug](https://www.npmjs.com/package/debug) logger
- `moddleContext`: optional BPMN 2.0 definition moddle context
- `moddleOptions`: optional bpmn-moddle options to be passed to bpmn-moddle
- `name`: optional name of engine,
- `scripts`: optional [inline script handler](https://github.com/paed01/bpmn-elements/blob/master/docs/Scripts.md), defaults to nodejs vm module handling, i.e. JavaScript
- `source`: optional BPMN 2.0 definition source as string
- `sourceContext`: optional serialized context supplied by [moddle-context-serializer](https://github.com/paed01/moddle-context-serializer)
- `timers`: [Timers instance](https://github.com/paed01/bpmn-elements/blob/master/docs/Timers.md)
- `typeResolver`: optional type resolver function passed to moddle-context-serializer
- `extensions`: optional behavior [extensions](https://github.com/paed01/bpmn-elements/blob/master/docs/Extension.md)
Returns:
- `name`: engine name
- `broker`: engine [broker](https://github.com/paed01/smqp)
- `state`: engine state
- `activityStatus`: string, activity status
- `executing`: at least one activity is executing, e.g. a service task making a asynchronous request
- `timer`: at least one activity is waiting for a timer to complete, usually only TimerEventDefinition's
- `wait`: at least one activity is waiting for a signal of some sort, e.g. user tasks, intermediate catch events, etc
- `idle`: idle, no activities are running
- `stopped`: boolean stopped
- `execution`: current engine execution
- `environment`: engine [environment](https://github.com/paed01/bpmn-elements/blob/master/docs/Environment.md)
- `logger`: engine logger
- `async execute()`: execute definition
- `async getDefinitionById()`: get definition by id
- `async getDefinitions()`: get all definitions
- `async getState()`: get execution serialized state
- `recover()`: recover from state
- `async resume()`: resume execution
- `async stop()`: stop execution
- `waitFor()`: wait for engine events, returns Promise
```javascript
import fs from 'node:fs';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { Engine } from 'bpmn-engine';
const camunda = createRequire(fileURLToPath(import.meta.url))('camunda-bpmn-moddle/resources/camunda.json');
const engine = new Engine({
name: 'mother of all',
source: fs.readFileSync('./test/resources/mother-of-all.bpmn'),
moddleOptions: {
camunda,
},
});
```
### `execute([options[, callback]])`
Execute definition.
Arguments:
- `options`: Optional object with options to override the initial engine options
- [`listener`](#execution-listener): Listen for [activity events](#activity-events), an `EventEmitter` object
- [`variables`](#execution-variables): Optional object with instance variables
- [`services`](#execution-services): Optional object with service functions
- `expressions`: Optional expression handling override
- `callback`: optional callback
- `err`: Error if any
- `execution`: Engine execution
Execute options overrides the initial options passed to the engine before executing the definition.
Returns [Execution API](#execution-api)
```javascript
import { EventEmitter } from 'node:events';
import { Engine } from 'bpmn-engine';
const source = `
`;
const engine = new Engine({
name: 'first',
source,
variables: {
data: {
inputFromUser: 0,
},
},
});
const listener = new EventEmitter();
listener.on('activity.wait', (elementApi) => {
elementApi.owner.logger.debug(`<${elementApi.executionId} (${elementApi.id})> signal with io`, elementApi.content.ioSpecification);
elementApi.signal({
ioSpecification: {
dataOutputs: [
{
id: 'userInput',
value: 2,
},
],
},
});
});
engine.execute(
{
listener,
variables: {
data: {
inputFromUser: 1,
},
},
},
(err, execution) => {
if (err) throw err;
console.log('completed with overridden listener', execution.environment.output);
}
);
```
#### Execution `listener`
An `EventEmitter` object with listeners. Listen for [activity events](#activity-events).
```javascript
import { EventEmitter } from 'node:events';
import { Engine } from 'bpmn-engine';
const source = `
`;
const engine = new Engine({
name: 'first listener',
source,
});
const listener = new EventEmitter();
listener.on('activity.enter', (elementApi, engineApi) => {
console.log(`${elementApi.type} <${elementApi.id}> of ${engineApi.name} is entered`);
});
listener.on('activity.wait', (elemntApi, instance) => {
console.log(`${elemntApi.type} <${elemntApi.id}> of ${instance.name} is waiting for input`);
elemntApi.signal('don“t wait for me');
});
engine.execute({
listener,
});
```
#### Execution `variables`
Execution variables are passed as the first argument to `#execute`.
```javascript
import fs from 'node:fs';
import { Engine } from 'bpmn-engine';
const engine = new Engine({
name: 'using variables',
source: fs.readFileSync('./test/resources/simple-task.bpmn'),
});
const variables = {
input: 1,
};
engine.execute(
{
variables,
},
(err, engineApi) => {
if (err) throw err;
console.log('completed');
}
);
```
#### Execution `services`
A service is a function exposed on `environment.services`.
```javascript
import { Engine } from 'bpmn-engine';
import bent from 'bent';
const source = `
`;
const engine = new Engine({
name: 'services doc',
source,
});
engine.execute(
{
services: {
get: bent('json'),
},
},
(err, engineApi) => {
if (err) throw err;
console.log('completed', engineApi.name, engineApi.environment.variables);
}
);
```
### `async getDefinitionById(id)`
Get definition by id, returns Promise
### `addSource({sourceContext})`
Add definition source by source context.
Arguments:
- `source`: object
- `sourceContext`: serializable source
```javascript
import { EventEmitter } from 'node:events';
import BpmnModdle from 'bpmn-moddle';
import * as elements from 'bpmn-elements';
import { Engine } from 'bpmn-engine';
import Serializer, { TypeResolver } from 'moddle-context-serializer';
const engine = new Engine({
name: 'add source',
});
(async function IIFE(source) {
const sourceContext = await getContext(source);
engine.addSource({
sourceContext,
});
const listener = new EventEmitter();
listener.once('activity.wait', (api) => {
console.log(api.name, 'is waiting');
api.signal();
});
await engine.execute({
listener,
});
await engine.waitFor('end');
})(`
`);
async function getContext(source, options) {
const moddleContext = await getModdleContext(source, options);
if (moddleContext.warnings) {
moddleContext.warnings.forEach(({ error, message, element, property }) => {
if (error) return console.error(message);
console.error(`<${element.id}> ${property}:`, message);
});
}
const types = TypeResolver({
...elements,
...options?.elements,
});
return Serializer(moddleContext, types, options?.extendFn);
}
function getModdleContext(source, options) {
const bpmnModdle = new BpmnModdle(options);
return bpmnModdle.fromXML(source);
}
```
### `getDefinitions()`
Get all definitions
```javascript
import { Engine } from 'bpmn-engine';
const source = `
`;
const engine = new Engine({
source,
});
engine.getDefinitions().then((definitions) => {
console.log('Loaded', definitions[0].id);
console.log('The definition comes with process', definitions[0].getProcesses()[0].id);
});
```
### `getState()`
Asynchronous function to get state of a running execution.
The saved state will include the following content:
- `state`: `running` or `idle`
- `engineVersion`: module package version
- `moddleOptions`: Engine moddleOptions
- `definitions`: List of definitions
- `state`: State of definition, `pending`, `running`, or `completed`
- `processes`: Object with processes with id as key
- `variables`: Execution variables
- `services`: Execution services
- `children`: List of child states
- `entered`: Boolean indicating if the child is currently executing
```javascript
import fs from 'node:fs/promises';
import { EventEmitter } from 'node:events';
import { Engine } from 'bpmn-engine';
const processXml = `
`;
const engine = new Engine({
source: processXml,
});
const listener = new EventEmitter();
let state;
listener.once('activity.wait', async () => {
state = await engine.getState();
await fs.writeFile('./tmp/some-random-id.json', JSON.stringify(state, null, 2));
});
listener.once('activity.start', async () => {
state = await engine.getState();
await fs.writeFile('./tmp/some-random-id.json', JSON.stringify(state, null, 2));
});
engine.execute({
listener,
});
```
### `stop()`
Stop execution. The instance is terminated.
```javascript
import { EventEmitter } from 'node:events';
import { Engine } from 'bpmn-engine';
const source = `
`;
const engine = new Engine({
source,
});
const listener = new EventEmitter();
let state;
listener.once('activity.wait', async () => {
engine.stop();
state = await engine.getState();
});
engine.execute({
variables: {
executionId: 'some-random-id',
},
listener,
});
```
### `recover(state[, recoverOptions])`
Recover engine from state.
> NB! Will throw an error if the engine is running.
Arguments:
- `state`: engine state
- `recoverOptions`: optional object with options that will override options passed to the engine at init, but not options recovered from state
```js
import { Engine } from 'bpmn-engine';
const state = fetchSomeState();
const engine = new Engine().recover(state);
```
### `resume([options, [callback]])`
Resume execution function with previously saved engine state.
> NB! Attempting to resume a running engine returns error in callback or throws if callback is not passed.
Arguments:
- `options`: optional resume options object
- [`listener`](#execution-listener): execution listener
- `callback`: optional callback
- `err`: Error if any
- `execution`: Resumed engine execution
```js
import { EventEmitter } from 'node:events';
import { Engine } from 'bpmn-engine';
const state = fetchSomeState();
const engine = new Engine().recover(state);
const listener = new EventEmitter();
engine.resume({ listener }, () => {
console.log('completed');
});
```
# Execution API
- `name`: engine name
- `state`: execution state
- `stopped`: is execution stopped?
- `broker`: engine message broker
- `environment`: execution environment
- `definitions`: list of definitions
- `activityStatus`: string, execution activity status, e.g. if `wait` or `timer` **no** activities are `executing`, if `executing` there can be both running timers and waiting tasks, if `timer` there can be waiting activities but **no** `executing` activities, and so forth
- `executing`: at least one activity is executing, e.g. a service task making a asynchronous request
- `timer`: at least one activity is waiting for a timer to complete, usually only TimerEventDefinition's
- `wait`: at least one activity is waiting for a signal of some sort, e.g. user tasks, intermediate catch events, etc
- `idle`: idle, no activities are running, the engine is not running at all
- `isRunning`: are any definition running?
- `getActivityById(activityId)`(#getactivitybyid-activityid): get activity/element by id, returns first found among definitions
- `getState()`: get execution state
- `getPostponed()`: get postponed activities, i.e. activities waiting for some interaction, signal, or timer
- [`signal(message)`](#signalmessage): send signal to execution, distributed to all definitions
- [`cancelActivity(message)`](#cancelactivitymessage): send cancel activity to execution, distributed to all definitions
- `stop()`: stop execution
- `waitFor(event)`: wait for [engine events](#engine-events), returns Promise
## `getActivityById(activityId)`
Get activity/element by id. Loops the definitions and returns the first found activity with id.
- `activityId`: Activity or element id
Returns [activity](https://github.com/paed01/bpmn-elements/blob/master/docs/Activity.md).
## `getState()`
Get execution state.
## `signal(message[, options])`
Delegate a signal message to all interested parties, usually MessageEventDefinition, SignalEventDefinition, SignalTask (user, manual), ReceiveTask, or a StartEvent that has a form.
Arguments:
- `message`: optional object
- `id`: optional task/element id to signal, also matched with Message and Signal id. If not passed only anonymous Signal- and MessageEventDefinitions will pick up the signal.
- `executionId`: optional execution id to signal, specially for looped tasks, also works for signal tasks that are not looped
- `[name]*`: any other properties will be forwarded as message to activity
- options: optional options object
- `ignoreSameDefinition`: boolean, ignore same definition, used when a signal is forwarded from another definition execution, see example
An example on how to setup signal forwarding between definitions:
```js
engine.broker.subscribeTmp(
'event',
'activity.signal',
(routingKey, msg) => {
engine.execution.signal(msg.content.message, { ignoreSameDefinition: true });
},
{ noAck: true }
);
```
## `cancelActivity(message)`
Delegate a cancel message to all interested parties, perhaps a stalled TimerEventDefinition.
Arguments:
- `message`: optional object
- `id`: optional activity id to cancel execution
- `executionId`: optional execution id to signal, useful for an event with multiple event defintions
- `[name]*`: any other properties will be forwarded as message to activity
# Engine events
Engine emits the following events:
- `error`: An non-recoverable error has occurred
- `stop`: Executions was stopped
- `end`: Execution completed
## Activity events
Each activity and flow emits events when changing state.
- `activity.enter`: An activity is entered
- `activity.start`: An activity is started
- `activity.wait`: The activity is postponed for some reason, e.g. a user task is waiting to be signaled or a message is expected
- `wait`: Same as above
- `activity.end`: An activity has ended successfully
- `activity.leave`: The execution left the activity
- `activity.stop`: Activity run was stopped
- `activity.throw`: An recoverable error was thrown
- `activity.error`: An non-recoverable error has occurred
## Event Api
Events are emitted with api with execution properties
- `name`: engine name
- `state`: state of execution, i.e running or idle
- `stopped`: is the execution stopped
- `environment`: engine environment
- `definitions`: executing definitions
- `stop()`: stop execution
- `getState()`: get execution serializable state
- `getPostponed()`: get activities in a postponed state
## Sequence flow events
- `flow.take`: The sequence flow was taken
- `flow.discard`: The sequence flow was discarded
- `flow.looped`: The sequence is looped
# Expressions
If not overridden [bpmn-elements](https://github.com/paed01/bpmn-elements/blob/master/docs/Expression.md) expressions handler is used.
Try out [`aircall-expression-parser`](https://github.com/aircall/aircall-expression-parser) by [Aircall](https://github.com/aircall) if you expect advanced expressions with operators.
[1]: https://www.npmjs.com/package/camunda-bpmn-moddle
[2]: https://www.npmjs.com/package/bpmn-moddle