bpmn-engine 19.0.1 → 20.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "bpmn-engine",
3
3
  "description": "BPMN 2.0 execution engine. Open source javascript workflow engine.",
4
- "version": "19.0.1",
5
- "main": "index.js",
6
- "types": "types/bpmn-engine.d.ts",
4
+ "version": "20.0.1",
5
+ "type": "module",
6
+ "module": "./src/index.js",
7
+ "main": "./lib/index.cjs",
8
+ "types": "./types/bpmn-engine.d.ts",
9
+ "sideEffects": false,
7
10
  "repository": {
8
11
  "type": "git",
9
12
  "url": "git://github.com/paed01/bpmn-engine"
@@ -17,18 +20,20 @@
17
20
  },
18
21
  "files": [
19
22
  "lib/",
20
- "types/",
21
- "index.js"
23
+ "src/",
24
+ "types/"
22
25
  ],
23
26
  "scripts": {
24
- "test": "mocha -R dot",
27
+ "test": "mocha -p -R @bonniernews/hot-bev",
25
28
  "posttest": "npm run lint && npm run toc",
26
- "lint": "eslint . --cache",
29
+ "lint": "eslint . --cache && prettier . -c --cache",
27
30
  "wintest": "mocha",
28
- "cov:html": "c8 -r html -r text mocha -R dot",
31
+ "cov:html": "c8 -r html -r text mocha -p -R @bonniernews/hot-bev",
29
32
  "test:lcov": "c8 -r lcov mocha && npm run lint",
30
33
  "toc": "node scripts/generate-api-toc ./docs/API.md,./docs/Examples.md",
31
- "test-md": "node scripts/test-markdown.js ./docs/API.md && node scripts/test-markdown.js ./docs/Examples.md"
34
+ "test-md": "node --experimental-vm-modules --no-warnings scripts/test-markdown.js ./docs/API.md,./docs/Examples.md,./docs/Upgrade.md",
35
+ "dist": "rollup -c",
36
+ "prepack": "npm run dist"
32
37
  },
33
38
  "keywords": [
34
39
  "workflow",
@@ -46,23 +51,28 @@
46
51
  }
47
52
  ],
48
53
  "devDependencies": {
54
+ "@bonniernews/hot-bev": "^0.4.0",
55
+ "@rollup/plugin-commonjs": "^25.0.7",
56
+ "@types/bpmn-moddle": "^5.1.6",
57
+ "@types/node": "^18.19.31",
49
58
  "bent": "^7.3.12",
50
59
  "c8": "^9.1.0",
51
60
  "camunda-bpmn-moddle": "^7.0.1",
52
- "chai": "^4.3.7",
61
+ "chai": "^5.1.0",
53
62
  "chronokinesis": "^6.0.0",
54
- "eslint": "^8.45.0",
63
+ "eslint": "^9.0.0",
55
64
  "markdown-toc": "^1.2.0",
56
65
  "mocha": "^10.2.0",
57
66
  "mocha-cakes-2": "^3.3.0",
58
- "nock": "^13.3.2"
67
+ "nock": "^13.3.2",
68
+ "prettier": "^3.2.5",
69
+ "rollup": "^4.10.0"
59
70
  },
60
71
  "dependencies": {
61
- "@types/bpmn-moddle": "^5.1.6",
62
- "bpmn-elements": "^13.1.2",
63
- "bpmn-moddle": "^8.0.1",
72
+ "bpmn-elements": "^13.2.0",
73
+ "bpmn-moddle": "^9.0.1",
64
74
  "debug": "^4.3.4",
65
- "moddle-context-serializer": "^4.0.0",
66
- "smqp": "^8.0.0"
75
+ "moddle-context-serializer": "^4.2.0",
76
+ "smqp": "^8.2.3"
67
77
  }
68
78
  }
@@ -1,16 +1,12 @@
1
- 'use strict';
1
+ import { Script } from 'vm';
2
2
 
3
- const {Script} = require('vm');
4
-
5
- module.exports = Scripts;
6
-
7
- function Scripts(disableDummy) {
3
+ export default function Scripts(disableDummy) {
8
4
  if (!(this instanceof Scripts)) return new Scripts(disableDummy);
9
5
  this.scripts = {};
10
6
  this.disableDummy = disableDummy;
11
7
  }
12
8
 
13
- Scripts.prototype.register = function register({id, type, behaviour, logger, environment}) {
9
+ Scripts.prototype.register = function register({ id, type, behaviour, logger, environment }) {
14
10
  let scriptBody, language;
15
11
 
16
12
  switch (type) {
@@ -43,20 +39,20 @@ Scripts.prototype.register = function register({id, type, behaviour, logger, env
43
39
  return script;
44
40
  };
45
41
 
46
- Scripts.prototype.getScript = function getScript(language, {id}) {
42
+ Scripts.prototype.getScript = function getScript(language, { id }) {
47
43
  return this.scripts[id];
48
44
  };
49
45
 
50
46
  function JavaScript(language, filename, scriptBody, environment) {
51
47
  this.id = filename;
52
- this.script = new Script(scriptBody, {filename});
48
+ this.script = new Script(scriptBody, { filename });
53
49
  this.language = language;
54
50
  this.environment = environment;
55
51
  }
56
52
 
57
53
  JavaScript.prototype.execute = function execute(executionContext, callback) {
58
54
  const timers = this.environment.timers.register(executionContext);
59
- return this.script.runInNewContext({...executionContext, ...timers, next: callback});
55
+ return this.script.runInNewContext({ ...executionContext, ...timers, next: callback });
60
56
  };
61
57
 
62
58
  function DummyScript(language, filename, logger) {
@@ -67,7 +63,7 @@ function DummyScript(language, filename, logger) {
67
63
  }
68
64
 
69
65
  DummyScript.prototype.execute = function execute(executionContext, callback) {
70
- const {id, executionId} = executionContext.content;
66
+ const { id, executionId } = executionContext.content;
71
67
  this.logger.debug(`<${executionId} (${id})> passthrough dummy script ${this.language || 'esperanto'}`);
72
68
  callback();
73
69
  };
@@ -1,11 +1,9 @@
1
- 'use strict';
1
+ import Debug from 'debug';
2
2
 
3
- const Debug = require('debug');
4
-
5
- module.exports = function Logger(scope) {
3
+ export default function Logger(scope) {
6
4
  return {
7
5
  debug: Debug('bpmn-engine:' + scope),
8
6
  error: Debug('bpmn-engine:error:' + scope),
9
7
  warn: Debug('bpmn-engine:warn:' + scope),
10
8
  };
11
- };
9
+ }
@@ -0,0 +1,41 @@
1
+ const kDataObjectDef = Symbol.for('data object definition');
2
+
3
+ export default function ProcessOutputDataObject(dataObjectDef, { environment }) {
4
+ this[kDataObjectDef] = dataObjectDef;
5
+ this.environment = environment;
6
+ this.behaviour = dataObjectDef.behaviour;
7
+ this.name = dataObjectDef.name;
8
+ this.parent = dataObjectDef.parent;
9
+ }
10
+
11
+ Object.defineProperties(ProcessOutputDataObject.prototype, {
12
+ id: {
13
+ get() {
14
+ return this[kDataObjectDef].id;
15
+ },
16
+ },
17
+ type: {
18
+ get() {
19
+ return this[kDataObjectDef].type;
20
+ },
21
+ },
22
+ });
23
+
24
+ ProcessOutputDataObject.prototype.read = function readDataObject(broker, exchange, routingKeyPrefix, messageProperties) {
25
+ const environment = this.environment;
26
+ const { id, name, type } = this;
27
+ const value = environment.variables.data && environment.variables.data[this.id];
28
+ return broker.publish(exchange, `${routingKeyPrefix}response`, { id, name, type, value }, messageProperties);
29
+ };
30
+
31
+ ProcessOutputDataObject.prototype.write = function writeDataObject(broker, exchange, routingKeyPrefix, value, messageProperties) {
32
+ const environment = this.environment;
33
+ const { id, name, type } = this;
34
+
35
+ environment.variables.data = environment.variables.data || {};
36
+ environment.variables.data[id] = value;
37
+
38
+ environment.output.data = environment.output.data || {};
39
+ environment.output.data[id] = value;
40
+ return broker.publish(exchange, `${routingKeyPrefix}response`, { id, name, type, value }, messageProperties);
41
+ };
@@ -1,6 +1,4 @@
1
- 'use strict';
2
-
3
- module.exports = function getOptionsAndCallback(optionsOrCallback, callback) {
1
+ export default function getOptionsAndCallback(optionsOrCallback, callback) {
4
2
  let options;
5
3
  if (typeof optionsOrCallback === 'function') {
6
4
  callback = optionsOrCallback;
@@ -9,4 +7,4 @@ module.exports = function getOptionsAndCallback(optionsOrCallback, callback) {
9
7
  }
10
8
 
11
9
  return [options, callback];
12
- };
10
+ }
@@ -1,15 +1,19 @@
1
- 'use strict';
2
-
3
- const BpmnModdle = require('bpmn-moddle');
4
- const Elements = require('bpmn-elements');
5
- const {Broker} = require('smqp');
6
- const {default: serializer, deserialize, TypeResolver} = require('moddle-context-serializer');
7
- const {EventEmitter} = require('events');
8
- const {version: engineVersion} = require('./package.json');
9
- const DebugLogger = require('./lib/Logger.js');
10
- const JavaScripts = require('./lib/JavaScripts.js');
11
- const getOptionsAndCallback = require('./lib/getOptionsAndCallback.js');
12
- const ProcessOutputDataObject = require('./lib/extensions/ProcessOutputDataObject.js');
1
+ import { createRequire } from 'module';
2
+ import { EventEmitter } from 'events';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ import BpmnModdle from 'bpmn-moddle';
6
+ import * as Elements from 'bpmn-elements';
7
+ import { Broker } from 'smqp';
8
+ import serializer, { deserialize, TypeResolver } from 'moddle-context-serializer';
9
+
10
+ import DebugLogger from './Logger.js';
11
+ import JavaScripts from './JavaScripts.js';
12
+ import getOptionsAndCallback from './getOptionsAndCallback.js';
13
+ import ProcessOutputDataObject from './extensions/ProcessOutputDataObject.js';
14
+
15
+ const nodeRequire = createRequire(fileURLToPath(import.meta.url));
16
+ const { version: engineVersion } = nodeRequire('../package.json');
13
17
 
14
18
  const kEngine = Symbol.for('engine');
15
19
  const kEnvironment = Symbol.for('environment');
@@ -23,36 +27,40 @@ const kState = Symbol.for('state');
23
27
  const kStopped = Symbol.for('stopped');
24
28
  const kTypeResolver = Symbol.for('type resolver');
25
29
 
26
- module.exports = {Engine, Execution};
30
+ export default Engine;
31
+ export { JavaScripts };
27
32
 
28
- function Engine(options = {}) {
33
+ export function Engine(options = {}) {
29
34
  if (!(this instanceof Engine)) return new Engine(options);
30
35
 
31
36
  EventEmitter.call(this);
32
37
 
33
- const opts = this.options = {
38
+ const opts = (this.options = {
34
39
  Logger: DebugLogger,
35
40
  scripts: new JavaScripts(options.disableDummyScript),
36
41
  ...options,
37
- };
42
+ });
38
43
 
39
44
  this.logger = opts.Logger('engine');
40
45
 
41
- this[kTypeResolver] = TypeResolver({
42
- ...Elements,
43
- ...opts.elements,
44
- }, opts.typeResolver || defaultTypeResolver);
46
+ this[kTypeResolver] = TypeResolver(
47
+ {
48
+ ...Elements,
49
+ ...opts.elements,
50
+ },
51
+ opts.typeResolver || defaultTypeResolver
52
+ );
45
53
 
46
54
  this[kEnvironment] = new Elements.Environment(opts);
47
55
 
48
- const broker = this.broker = new Broker(this);
49
- broker.assertExchange('event', 'topic', {autoDelete: false});
56
+ const broker = (this.broker = new Broker(this));
57
+ broker.assertExchange('event', 'topic', { autoDelete: false });
50
58
 
51
59
  this[kExecution] = null;
52
60
  this[kLoadedDefinitions] = null;
53
61
  this[kSources] = [];
54
62
 
55
- const pendingSources = this[kPendingSources] = [];
63
+ const pendingSources = (this[kPendingSources] = []);
56
64
  if (opts.source) pendingSources.push(this._serializeSource(opts.source));
57
65
  if (opts.moddleContext) pendingSources.push(this._serializeModdleContext(opts.moddleContext));
58
66
  if (opts.sourceContext) pendingSources.push(opts.sourceContext);
@@ -117,7 +125,7 @@ Engine.prototype.execute = async function execute(...args) {
117
125
  throw err;
118
126
  }
119
127
 
120
- const execution = this[kExecution] = new Execution(this, definitions, this.options);
128
+ const execution = (this[kExecution] = new Execution(this, definitions, this.options));
121
129
  return execution._execute(executeOptions, callback);
122
130
  };
123
131
 
@@ -144,7 +152,7 @@ Engine.prototype.recover = function recover(savedState, recoverOptions) {
144
152
  const preSources = pendingSources.splice(0);
145
153
 
146
154
  const typeResolver = this[kTypeResolver];
147
- const loadedDefinitions = this[kLoadedDefinitions] = savedState.definitions.map((dState) => {
155
+ const loadedDefinitions = (this[kLoadedDefinitions] = savedState.definitions.map((dState) => {
148
156
  let source;
149
157
  if (dState.source) source = deserialize(JSON.parse(dState.source), typeResolver);
150
158
  else source = preSources.find((s) => s.id === dState.id);
@@ -157,7 +165,7 @@ Engine.prototype.recover = function recover(savedState, recoverOptions) {
157
165
  definition.recover(dState);
158
166
 
159
167
  return definition;
160
- });
168
+ }));
161
169
 
162
170
  this[kExecution] = new Execution(this, loadedDefinitions, {}, true);
163
171
 
@@ -181,16 +189,16 @@ Engine.prototype.resume = async function resume(...args) {
181
189
  return execution._resume(resumeOptions, callback);
182
190
  };
183
191
 
184
- Engine.prototype.addSource = function addSource({sourceContext: addContext} = {}) {
192
+ Engine.prototype.addSource = function addSource({ sourceContext: addContext } = {}) {
185
193
  if (!addContext) return;
186
194
  const loadedDefinitions = this[kLoadedDefinitions];
187
195
  if (loadedDefinitions) loadedDefinitions.splice(0);
188
196
  this[kPendingSources].push(addContext);
189
197
  };
190
198
 
191
- Engine.prototype.getDefinitions = async function getDefinitions(executeOptions) {
199
+ Engine.prototype.getDefinitions = function getDefinitions(executeOptions) {
192
200
  const loadedDefinitions = this[kLoadedDefinitions];
193
- if (loadedDefinitions?.length) return loadedDefinitions;
201
+ if (loadedDefinitions?.length) return Promise.resolve(loadedDefinitions);
194
202
  return this._loadDefinitions(executeOptions);
195
203
  };
196
204
 
@@ -225,27 +233,30 @@ Engine.prototype.waitFor = function waitFor(eventName) {
225
233
 
226
234
  Engine.prototype._loadDefinitions = async function loadDefinitions(executeOptions) {
227
235
  const runSources = await Promise.all(this[kPendingSources]);
228
- const loadedDefinitions = this[kLoadedDefinitions] = runSources.map((source) => this._loadDefinition(source, executeOptions));
236
+ const loadedDefinitions = (this[kLoadedDefinitions] = runSources.map((source) => this._loadDefinition(source, executeOptions)));
229
237
  return loadedDefinitions;
230
238
  };
231
239
 
232
240
  Engine.prototype._loadDefinition = function loadDefinition(serializedContext, executeOptions = {}) {
233
- const {settings, variables} = executeOptions;
241
+ const { settings, variables } = executeOptions;
234
242
 
235
243
  const environment = this.environment;
236
- const context = new Elements.Context(serializedContext, environment.clone({
237
- listener: environment.options.listener,
238
- ...executeOptions,
239
- settings: {
240
- ...environment.settings,
241
- ...settings,
242
- },
243
- variables: {
244
- ...environment.variables,
245
- ...variables,
246
- },
247
- source: serializedContext,
248
- }));
244
+ const context = new Elements.Context(
245
+ serializedContext,
246
+ environment.clone({
247
+ listener: environment.options.listener,
248
+ ...executeOptions,
249
+ settings: {
250
+ ...environment.settings,
251
+ ...settings,
252
+ },
253
+ variables: {
254
+ ...environment.variables,
255
+ ...variables,
256
+ },
257
+ source: serializedContext,
258
+ })
259
+ );
249
260
 
250
261
  return new Elements.Definition(context);
251
262
  };
@@ -266,7 +277,7 @@ Engine.prototype._getModdleContext = function getModdleContext(source) {
266
277
  return bpmnModdle.fromXML(Buffer.isBuffer(source) ? source.toString() : source.trim());
267
278
  };
268
279
 
269
- function Execution(engine, definitions, options, isRecovered = false) {
280
+ export function Execution(engine, definitions, options, isRecovered = false) {
270
281
  this.name = engine.name;
271
282
  this.options = options;
272
283
  this.definitions = definitions;
@@ -275,7 +286,7 @@ function Execution(engine, definitions, options, isRecovered = false) {
275
286
  this[kEnvironment] = engine.environment;
276
287
  this[kEngine] = engine;
277
288
  this[kExecuting] = [];
278
- const onBrokerReturn = this[kOnBrokerReturn] = this._onBrokerReturn.bind(this);
289
+ const onBrokerReturn = (this[kOnBrokerReturn] = this._onBrokerReturn.bind(this));
279
290
  engine.broker.on('return', onBrokerReturn);
280
291
  }
281
292
 
@@ -300,29 +311,10 @@ Object.defineProperties(Execution.prototype, {
300
311
  return this[kEnvironment];
301
312
  },
302
313
  },
303
- });
304
-
305
- Object.defineProperty(Execution.prototype, 'activityStatus', {
306
- get() {
307
- let status = 'idle';
308
- const running = this[kExecuting];
309
- if (!running.length) return status;
310
-
311
- for (const def of running) {
312
- const bpStatus = def.activityStatus;
313
- switch (def.activityStatus) {
314
- case 'executing':
315
- return bpStatus;
316
- case 'timer':
317
- status = bpStatus;
318
- break;
319
- case 'wait':
320
- if (status === 'idle') status = bpStatus;
321
- break;
322
- }
323
- }
324
-
325
- return status;
314
+ activityStatus: {
315
+ get() {
316
+ return this._getActivityStatus();
317
+ },
326
318
  },
327
319
  });
328
320
 
@@ -370,20 +362,35 @@ Execution.prototype._addConsumerCallbacks = function addConsumerCallbacks(callba
370
362
 
371
363
  clearConsumers();
372
364
 
373
- broker.subscribeOnce('event', 'engine.stop', () => {
374
- clearConsumers();
375
- return callback(null, this);
376
- }, {consumerTag: 'ctag-cb-stop'});
377
-
378
- broker.subscribeOnce('event', 'engine.end', () => {
379
- clearConsumers();
380
- return callback(null, this);
381
- }, {consumerTag: 'ctag-cb-end'});
382
-
383
- broker.subscribeOnce('event', 'engine.error', (_, message) => {
384
- clearConsumers();
385
- return callback(message.content);
386
- }, {consumerTag: 'ctag-cb-error'});
365
+ broker.subscribeOnce(
366
+ 'event',
367
+ 'engine.stop',
368
+ () => {
369
+ clearConsumers();
370
+ return callback(null, this);
371
+ },
372
+ { consumerTag: 'ctag-cb-stop' }
373
+ );
374
+
375
+ broker.subscribeOnce(
376
+ 'event',
377
+ 'engine.end',
378
+ () => {
379
+ clearConsumers();
380
+ return callback(null, this);
381
+ },
382
+ { consumerTag: 'ctag-cb-end' }
383
+ );
384
+
385
+ broker.subscribeOnce(
386
+ 'event',
387
+ 'engine.error',
388
+ (_, message) => {
389
+ clearConsumers();
390
+ return callback(message.content);
391
+ },
392
+ { consumerTag: 'ctag-cb-error' }
393
+ );
387
394
 
388
395
  return callback;
389
396
 
@@ -419,7 +426,7 @@ Execution.prototype._setup = function setup(setupOptions = {}) {
419
426
  for (const definition of this.definitions) {
420
427
  if (listener) definition.environment.options.listener = listener;
421
428
 
422
- const {queueName} = definition.broker.subscribeTmp('event', 'definition.#', onChildMessage, {noAck: true, consumerTag: '_engine_definition'});
429
+ const { queueName } = definition.broker.subscribeTmp('event', 'definition.#', onChildMessage, { noAck: true, consumerTag: '_engine_definition' });
423
430
  definition.broker.bindQueue(queueName, 'event', 'process.#');
424
431
  definition.broker.bindQueue(queueName, 'event', 'activity.#');
425
432
  definition.broker.bindQueue(queueName, 'event', 'flow.#');
@@ -427,7 +434,7 @@ Execution.prototype._setup = function setup(setupOptions = {}) {
427
434
  };
428
435
 
429
436
  Execution.prototype._onChildMessage = function onChildMessage(routingKey, message, owner) {
430
- const {environment: ownerEnvironment} = owner;
437
+ const { environment: ownerEnvironment } = owner;
431
438
  const listener = ownerEnvironment.options?.listener;
432
439
  this[kState] = 'running';
433
440
 
@@ -460,30 +467,19 @@ Execution.prototype._onChildMessage = function onChildMessage(routingKey, messag
460
467
 
461
468
  newState = 'idle';
462
469
  break;
463
- case 'definition.error':
470
+ case 'definition.error': {
471
+ this._saveOutput(owner.environment.output);
464
472
  this._teardownDefinition(owner);
465
473
  newState = 'error';
466
474
  break;
475
+ }
467
476
  case 'activity.wait': {
468
477
  if (listener) listener.emit('wait', owner.getApi(message), this);
469
478
  break;
470
479
  }
471
480
  case 'process.end': {
472
- if (!message.content.output) break;
473
- const environment = this.environment;
474
-
475
- for (const key in message.content.output) {
476
- switch (key) {
477
- case 'data': {
478
- environment.output.data = environment.output.data || {};
479
- environment.output.data = {...environment.output.data, ...message.content.output.data};
480
- break;
481
- }
482
- default: {
483
- environment.output[key] = message.content.output[key];
484
- }
485
- }
486
- }
481
+ if (message.content.inbound) break;
482
+ this._saveOutput(message.content.output);
487
483
  break;
488
484
  }
489
485
  }
@@ -491,7 +487,7 @@ Execution.prototype._onChildMessage = function onChildMessage(routingKey, messag
491
487
  if (listener) listener.emit(routingKey, elementApi, this);
492
488
 
493
489
  const broker = this.broker;
494
- broker.publish('event', routingKey, {...message.content}, {...message.properties, mandatory: false});
490
+ broker.publish('event', routingKey, { ...message.content }, { ...message.properties, mandatory: false });
495
491
 
496
492
  if (!newState) return;
497
493
 
@@ -500,13 +496,13 @@ Execution.prototype._onChildMessage = function onChildMessage(routingKey, messag
500
496
  switch (newState) {
501
497
  case 'stopped':
502
498
  this._debug('stopped');
503
- return this._complete('stop', {}, {type: 'stop'});
499
+ return this._complete('stop', {}, { type: 'stop' });
504
500
  case 'idle':
505
501
  this._debug('completed');
506
- return this._complete('end', {}, {type: 'end'});
502
+ return this._complete('end', {}, { type: 'end' });
507
503
  case 'error':
508
504
  this._debug('error');
509
- return this._complete('error', message.content.error, {type: 'error', mandatory: true});
505
+ return this._complete('error', message.content.error, { type: 'error', mandatory: true });
510
506
  }
511
507
  };
512
508
 
@@ -525,6 +521,21 @@ Execution.prototype._teardownDefinition = function teardownDefinition(definition
525
521
  definition.broker.cancel('_engine_definition');
526
522
  };
527
523
 
524
+ Execution.prototype._saveOutput = function saveOutput(output) {
525
+ if (!output || typeof output !== 'object') return;
526
+
527
+ const environmentOutput = this.environment.output;
528
+
529
+ for (const key in output) {
530
+ if (key === 'data') {
531
+ const data = (environmentOutput.data = environmentOutput.data || {});
532
+ environmentOutput.data = { ...data, ...output.data };
533
+ } else {
534
+ environmentOutput[key] = output[key];
535
+ }
536
+ }
537
+ };
538
+
528
539
  Execution.prototype.getState = function getState() {
529
540
  const definitions = [];
530
541
  for (const definition of this.definitions) {
@@ -559,7 +570,7 @@ Execution.prototype.getPostponed = function getPostponed() {
559
570
  }, []);
560
571
  };
561
572
 
562
- Execution.prototype.signal = function signal(payload, {ignoreSameDefinition} = {}) {
573
+ Execution.prototype.signal = function signal(payload, { ignoreSameDefinition } = {}) {
563
574
  for (const definition of this[kExecuting]) {
564
575
  if (ignoreSameDefinition && payload?.parent?.id === definition.id) continue;
565
576
  definition.signal(payload);
@@ -585,3 +596,26 @@ Execution.prototype._onBrokerReturn = function onBrokerReturn(message) {
585
596
  Execution.prototype._debug = function debug(msg) {
586
597
  this[kEngine].logger.debug(`<${this.name}> ${msg}`);
587
598
  };
599
+
600
+ Execution.prototype._getActivityStatus = function getActivityStatus() {
601
+ let status = 'idle';
602
+ const running = this[kExecuting];
603
+ if (!running.length) return status;
604
+ else if (running.length === 1) return running[0].activityStatus;
605
+
606
+ for (const def of running) {
607
+ const bpStatus = def.activityStatus;
608
+ switch (def.activityStatus) {
609
+ case 'executing':
610
+ return bpStatus;
611
+ case 'timer':
612
+ status = bpStatus;
613
+ break;
614
+ case 'wait':
615
+ if (status === 'idle') status = bpStatus;
616
+ break;
617
+ }
618
+ }
619
+
620
+ return status;
621
+ };